欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【linux】22、信号:高级特性

程序员文章站 2022-07-12 10:31:21
...

硬件产生的信号:SIGBUS、SIGFPE、SIGILL、SIGSEGV

信号的同步生成和异步生成

同步生成:信号的产生由进程本身的执行造成的
异步生成:引发信号产生的事件,与进程执行无关

信号传递的顺序

linux内核按照信号编号的升序来传递信号。

实时信号

(1)发送进程使用sigqueue()系统调用来发送信号及其伴随数据
(2)要为该信号建立一个处理器函数,接收进程应以SA_SIGINFO标志发起狂对sigaction()的调用。

#define _POSIX_C_SOURCE 199309
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);
//success 0; error -1

t_sigqueue.c

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>

static int getInt(char *, char *);

int main(int argc, char **argv){
	pid_t pid;
	int sigNum, sigData, frequency, i;
	union sigval sv;

	if (argc < 4 || (argc > 1 && strcmp(argv[1], "--help") == 0)){
		printf("usgae: %s pid sigNum sigData frequency\n", argv[0]);
		exit(EXIT_SUCCESS);
	}
	
	pid = (pid_t)getInt(argv[1], "pid of receive function");
	sigNum = getInt(argv[2], "number of signal");
	sigData  = getInt(argv[3], "signal carrying value");
	frequency = (argc > 4) ? getInt(argv[4], "Sending frequency") : 1;

	for (i = 0;i < frequency;i++){
		sv.sival_int = sigData + i;
		if (sigqueue(pid, sigNum, sv) == -1){
			printf("sigqueue() error!\n");
			exit(EXIT_FAILURE);
		}
	}
	
}

static int getInt(char *p, char *msg){
	int data;
	char *str;

	data = strtol(p, &str, 10);
	if (*str != '\0'){
		printf("%s must be string\n", msg);
		exit(EXIT_FAILURE);
	}else if (data <= 0){
		printf("%s must be greater than zero\n", msg);
		exit(EXIT_FAILURE);
	}
	return data;
}

catch_rtsigs.c

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>

static volatile sig_atomic_t flag = 0;
static volatile int handler_sleepTime;
static volatile int sigCount = 0;

static int getInt(char *, char *);
static void sigHandler(int, siginfo_t *, void *);

int main(int argc, char **argv){
	struct sigaction sa;
	int i, main_sleepTime;
	sigset_t blockMask, prevMask;

	if (argc != 3 || (argc > 1 && strcmp(argv[1], "--help") == 0)){
		printf("usage: %s num1 num2\n"
				"\tnum1: sleep time for main function\n"
				"\tnum2: sleep time for sigHandler function\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	printf("pid: %d\n", getpid());

	sigfillset(&sa.sa_mask);
	sa.sa_flags = SA_SIGINFO;
	sa.sa_sigaction = sigHandler;

	for (i = 1;i < NSIG; i++){
		if (i != SIGQUIT && i != SIGTSTP){
			/*
			if (sigaction(i, &sa, NULL) == -1){
				printf("sigaction() error!\n");
				exit(-1);
			}
			*/
			sigaction(i, &sa, NULL);
		}
	}

	main_sleepTime  = getInt(argv[1], "main sleep time");
	handler_sleepTime = (argc > 2) ? getInt(argv[2], "handler sleep time") : 1;
	
	sigfillset(&blockMask);
	sigdelset(&blockMask, SIGINT);
	if (sigprocmask(SIG_SETMASK, &blockMask, &prevMask) == -1){
		printf("sigprocmask() error!\n");
		exit(EXIT_FAILURE);
	}
	sleep(main_sleepTime);
	printf("main function sleep complete\n");
	sigprocmask(SIG_SETMASK, &prevMask, NULL);
	
	while (!flag)
		pause();
	return 0;
}


static int getInt(char *p, char *msg){
	char *ch;
	int data;

	data = strtol(p, &ch, 10);

	if (*ch != '\0'){
		fprintf(stdout, "%s cannot be character\n", msg);
		exit(EXIT_FAILURE);
	}else if(data <= 0){
		fprintf(stdout, "%s must be more than zero\n", msg);
		exit(EXIT_FAILURE);
	} 
	return data;
}

static void sigHandler(int sig, siginfo_t *si, void *ucontext){

	if (sig == SIGINT){
	 	flag = 1;
		return;
	}
	sigCount++;
	printf("Caught signal %d: %s\n", sig, strsignal(sig));
	
	printf("si_signo=%d, si_code=%d, ",si->si_signo, si->si_code);
	printf("si_pid=%ld, si_uid=%ld, ", (long)si->si_pid, (long)si->si_uid);
	printf("si_value=%d\n", si->si_value.sival_int);
	sleep(handler_sleepTime);
}

【linux】22、信号:高级特性
【linux】22、信号:高级特性

使用掩码来等待信号:sigsuspend()

#include <signal.h>

int sigsuspend(const sigset_t *mask);

t_sigsuspend.c

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <time.h>
#include <errno.h>

static volatile sig_atomic_t flag = 0;

static void printSig(char *, char *);
static void errExit(char *);
static void sigHandler(int);

int main(int argc, char **argv){
	struct sigaction sa;
	sigset_t blockSig, prevSig;
	int i;
	time_t startTime;

	printSig("previous signal mask: ", "mask");

	sigemptyset(&blockSig);
	sigaddset(&blockSig, SIGINT);
	sigaddset(&blockSig, SIGQUIT);
	if (sigprocmask(SIG_BLOCK, &blockSig, &prevSig) == -1){
		errExit("siprocmask()");
	}

	sa.sa_flags = 0;
	sa.sa_handler = sigHandler;
	sigemptyset(&sa.sa_mask);

	for (i = 1; i< NSIG; i++){
		if (i == SIGINT || i == SIGQUIT){
			sigaction(i, &sa, NULL);
		}
	}

	for (i = 1; !flag; i++){
		printf("*********LOOP%d************\n", i);
		printSig("before the critical section, signal mask:", "mask");
		for (startTime = time(NULL); time(NULL) < startTime + 4;)
			continue;
		printSig("the pending signal: ", "pending");
		if (sigsuspend(&prevSig) == -1 && errno != EINTR){
			errExit("sigsuspend()");
		}
	}
	if (sigprocmask(SIG_SETMASK, NULL, &prevSig) == -1){
		errExit("sigprocmask");
	}
	printSig("At last, the signal mask:", "mask");
	exit(EXIT_SUCCESS);
}

static void printSig(char *msg, char *mask){
	int sig, num = 0;
	sigset_t sigSet;	
	
	if (strcmp(mask, "mask") == 0){
		if (sigprocmask(SIG_SETMASK, NULL, &sigSet) == -1)
			errExit("sigprocmask()");
	}else{
		if (sigpending(&sigSet) == -1)
			errExit("sigpending()");
	}
	printf("%s", msg);
	for (sig = 1; sig < NSIG;sig++){
		if (sigismember(&sigSet, sig)){
			num++;
			printf("%d ", sig);
		}
	} 
	if (!num)
		printf("empty set\n");
	else
		printf("\n");
}

static void errExit(char *msg){
	printf("%s error\n", msg);
	exit(EXIT_FAILURE);
}

static void sigHandler(int sig){
	if (sig == SIGQUIT){
		flag = 1;
		return;
	}
	printf("signal %d: %s\n", sig, strsignal(sig));
}

【linux】22、信号:高级特性

以同步方式等待信号

#define POSIX_C_SOURCE 199309
#include <signal.h>

int sigwaitinfor(const sigset_t *set, siginfo_t *info);
//success, signal; error, -1

(1) sigwaitinfo()系统调用挂起进程的执行,直至set指向信号集中的某一信号抵达。
(2)调用sigwaitinfo(),需要先阻塞set中的信号

【linux】22、信号:高级特性
【linux】22、信号:高级特性