进程信号之自定义处理

信号的捕捉流程:主要是针对信号的自定义处理方式

信号并不是立即处理的,而是选择一个合适的时机去处理,合适的时机就是当前程序从内核态切换到用户态的时候

注意:程序如何从用户态切换到内核态?

答:1.程序异常的时候 2.发起系统调用的时候 3.中断的时候

信号的捕捉是当我们发起系统调用/程序异常/中断当前程序从内核态运行切换到用户态,去处理这些事情,处理完毕之后,要从内核态返回用户态,但是在返回之前会看一下是否有信号需要被处理,如果有就处理信号(切换到用户态执行信号的自定义处理方式),处理完毕之后再次返回内核态,判断没有信号要处理了就调用sys_sigreturn返回用户态(我们程序之前运行的位置)(就像我们课堂上布置的作业不会立即写)

信号捕捉流程

注意:在使用这个接口时可能会因为该函数是库函数,而在Linux下的系统版本下会有细微差异

多是使用此函数所调用的系统调用接口sigaction

1
2
3
4
5
6
7
8
9
int sigaction(int signum, const struct sigaction *act,

struct sigaction *oldact);

signum:指定给哪个信号去自定义处理方式

act:新的处理方式

oldact:保存新自定义之前的原本的操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct sigaction {

//都是信号的回调函数(取决于flags),任意指定其一

void (*sa_handler)(int);

void (*sa_sigaction)(int, siginfo_t *, void *);//传递信号并同时携带参数

//当处理时不希望被别的信号所影响,所以使用sa_mask来指定需要暂时阻塞的信号

sigset_t sa_mask;

//当flags被指定为SA_SIGINFO这个参数时回调的是sa_sigaction,否则都是调用handler

int sa_flags;

void (*sa_restorer)(void);

};

下边是一个sigaction的使用demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
 1 /*

2 * 因为signal这个接口有linux版本的差异性,因此可以使用sigaction这个接口来替代signal函数,

3 * 它的功能也是自定义信号的处理方式,并且signal函数内部也是通过sigaction来实现的

4 *

5 *

6 */

7

8 /* struct sigaction {

9 void (*sa_handler)(int);//处理函数

10 void (*sa_sigaction)(int, siginfo_t *, void *);//处理函数(当flags被指定为SA_SIGINFO这个参数时回调)

11 sigset_t sa_mask;//在处理信号时通过这个mask暂时阻塞一些信号,处理完之后还原

12 int sa_flags;//决定使用哪个处理接口

13 void (*sa_restorer)(void);

14 };*/

15

16

17 #include<stdio.h>

18 #include<unistd.h>

19 #include<signal.h>

20

21 void sigcb(int signo)

22 {

23 printf("rec signal:%d\n",signo);

24 }

25

26 void sigcb1(int signo,siginfo_t* info,void* context)//context为预留的,不是传的参数,暂时不管它

27 {

28 printf("rec signo:%d---param:%d\n",signo,info->si_int);

29 }

30

31

32 int main()

33 {

34 struct sigaction new_act;

35 struct sigaction old_act;

36 //重新定义处理方式的信号为SIGINT SINQUIT

37 //int sigaction(int signum, const struct sigaction *act,

38 // struct sigaction *oldact);

39 //signum:信号编号

40 //act:新的处理方式

41 //oldact:保存原有的处理方式

42

43 //这个操作时一般性的更改一个信号的处理方式,sa_flags =0代表使用的回调接口为sa_handler

44 sigemptyset(&new_act.sa_mask);

45 new_act.sa_flags = 0;

46 new_act.sa_handler = sigcb;

47 sigaction(SIGINT,&new_act,&old_act);

48

49 //这个操作是用于传递信号同时携带参数的情况,sa_flags需要被指定为sa_SIGINFO,并且调用的接口是sa_sigaction

50 sigemptyset(&new_act.sa_mask);

51 new_act.sa_flags = SA_SIGINFO;

52 new_act.sa_sigaction = sigcb1;

53 sigaction(SIGQUIT,&new_act,&old_act);

54 while(1)

55 {

56 sleep(1);

57 kill(getpid(),SIGINT);

58 //int sigqueue(pid_t pid, int sig, const union sigval value); //这个函数不仅可以发送信号,还可以

//顺便携带一 个信号

59 // pid:进程ID

60 // sig:信号编号

61 // sigval:参数

62 /* union sigval {

63 int sival_int;

64 void *sival_ptr;

65 };*/

66 union sigval val;

67 val.sival_int = 999;

68 sigqueue(getpid(),SIGQUIT,val);//传参函数

69 }

70 return 0;

71 }
0%