This source file includes following definitions.
- sys_sgetmask
- sys_ssetmask
- sys_sigpending
- sys_sigsuspend
- check_pending
- sys_signal
- sys_sigaction
- do_signal
1
2
3
4
5
6
7 #include <linux/sched.h>
8 #include <linux/kernel.h>
9 #include <linux/signal.h>
10 #include <linux/errno.h>
11 #include <linux/wait.h>
12 #include <linux/ptrace.h>
13
14 #include <asm/segment.h>
15
16 #define _S(nr) (1<<((nr)-1))
17
18 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
19
20 extern int core_dump(long signr,struct pt_regs * regs);
21
22 int sys_sgetmask(void)
23 {
24 return current->blocked;
25 }
26
27 int sys_ssetmask(int newmask)
28 {
29 int old=current->blocked;
30
31 current->blocked = newmask & _BLOCKABLE;
32 return old;
33 }
34
35 int sys_sigpending(sigset_t *set)
36 {
37 int error;
38
39 error = verify_area(VERIFY_WRITE, set, 4);
40 if (!error)
41 put_fs_long(current->blocked & current->signal, (unsigned long *)set);
42 return error;
43 }
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 int sys_sigsuspend(volatile int restart, volatile unsigned long old_mask, unsigned long set)
63 {
64 extern int sys_pause(void);
65
66 switch (restart) {
67 case 0:
68
69 restart = 1;
70 old_mask = current->blocked;
71 current->blocked = set & _BLOCKABLE;
72 break;
73 case 1:
74
75 current->blocked = old_mask & _BLOCKABLE;
76 return -EINTR;
77 case 2:
78
79 restart = 1;
80 break;
81 }
82
83 if (sys_pause() == -ERESTARTSYS)
84 restart = 2;
85 return -ERESTARTNOINTR;
86 }
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103 static void check_pending(int signum)
104 {
105 struct sigaction *p;
106
107 p = signum - 1 + current->sigaction;
108 if (p->sa_handler == SIG_IGN) {
109 if (signum == SIGCHLD)
110 return;
111 current->signal &= ~_S(signum);
112 return;
113 }
114 if (p->sa_handler == SIG_DFL) {
115 if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH)
116 return;
117 current->signal &= ~_S(signum);
118 return;
119 }
120 }
121
122 int sys_signal(int signum, long handler, long restorer)
123 {
124 struct sigaction tmp;
125
126 if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
127 return -EINVAL;
128 tmp.sa_handler = (void (*)(int)) handler;
129 tmp.sa_mask = 0;
130 tmp.sa_flags = SA_ONESHOT | SA_NOMASK | SA_INTERRUPT;
131 tmp.sa_restorer = (void (*)(void)) restorer;
132 handler = (long) current->sigaction[signum-1].sa_handler;
133 current->sigaction[signum-1] = tmp;
134 check_pending(signum);
135 return handler;
136 }
137
138 int sys_sigaction(int signum, const struct sigaction * action,
139 struct sigaction * oldaction)
140 {
141 struct sigaction new, *p;
142
143 if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
144 return -EINVAL;
145 p = signum - 1 + current->sigaction;
146 if (action) {
147 memcpy_fromfs(&new, action, sizeof(struct sigaction));
148 if (new.sa_flags & SA_NOMASK)
149 new.sa_mask = 0;
150 else {
151 new.sa_mask |= _S(signum);
152 new.sa_mask &= _BLOCKABLE;
153 }
154 }
155 if (oldaction) {
156 if (!verify_area(VERIFY_WRITE,oldaction, sizeof(struct sigaction)))
157 memcpy_tofs(oldaction, p, sizeof(struct sigaction));
158 }
159 if (action) {
160 *p = new;
161 check_pending(signum);
162 }
163 return 0;
164 }
165
166 extern int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
167
168
169
170
171
172
173 void do_signal(struct pt_regs * regs)
174 {
175 unsigned long signr;
176 unsigned long sa_handler;
177 long old_eip = regs->eip;
178 struct sigaction * sa;
179 int longs;
180 unsigned long * tmp_esp;
181
182 if (regs->orig_eax >= 0 && regs->eax == -ERESTARTNOINTR) {
183 regs->eax = regs->orig_eax;
184 regs->eip = old_eip -= 2;
185 }
186 signr = current->signal & ~current->blocked;
187 do {
188 __asm__("bsf %2,%1\n\t"
189 "btrl %1,%0"
190 :"=m" (current->signal),"=r" (signr)
191 :"1" (signr));
192 sa = current->sigaction + signr;
193 signr++;
194 sa_handler = (unsigned long) sa->sa_handler;
195 if (sa_handler==1) {
196
197 if (signr == SIGCHLD)
198 while (sys_waitpid(-1,NULL,WNOHANG) > 0)
199 ;
200 continue;
201 }
202 if (!sa_handler) {
203 if (current->pid == 1)
204 continue;
205 switch (signr) {
206 case SIGCONT:
207 case SIGCHLD:
208 case SIGWINCH:
209 continue;
210
211 case SIGSTOP:
212 case SIGTSTP:
213 case SIGTTIN:
214 case SIGTTOU:
215 current->state = TASK_STOPPED;
216 current->exit_code = signr;
217 if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
218 SA_NOCLDSTOP))
219 send_sig(SIGCHLD, current->p_pptr, 1);
220 schedule();
221 continue;
222
223 case SIGQUIT:
224 case SIGILL:
225 case SIGTRAP:
226 case SIGIOT:
227 case SIGFPE:
228 case SIGSEGV:
229 if (core_dump(signr,regs))
230 signr |= 0x80;
231
232 default:
233 current->signal |= _S(signr & 0x7f);
234 do_exit(signr);
235 }
236 }
237
238
239
240 if (regs->orig_eax >= 0 && regs->eax == -ERESTARTSYS) {
241 if (sa->sa_flags & SA_INTERRUPT)
242 regs->eax = -EINTR;
243 else {
244 regs->eax = regs->orig_eax;
245 regs->eip = old_eip -= 2;
246 }
247 }
248 if (sa->sa_flags & SA_ONESHOT)
249 sa->sa_handler = NULL;
250 regs->eip = sa_handler;
251 longs = (sa->sa_flags & SA_NOMASK)?(7*4):(8*4);
252 regs->esp -= longs;
253 tmp_esp = (unsigned long *) regs->esp;
254 verify_area(VERIFY_WRITE,tmp_esp,longs);
255 put_fs_long((long) sa->sa_restorer,tmp_esp++);
256 put_fs_long(signr,tmp_esp++);
257 if (!(sa->sa_flags & SA_NOMASK))
258 put_fs_long(current->blocked,tmp_esp++);
259 put_fs_long(regs->eax,tmp_esp++);
260 put_fs_long(regs->ecx,tmp_esp++);
261 put_fs_long(regs->edx,tmp_esp++);
262 put_fs_long(regs->eflags,tmp_esp++);
263 put_fs_long(old_eip,tmp_esp++);
264 current->blocked |= sa->sa_mask;
265
266 __asm__("testb $0,%%fs:%0"::"m" (*(char *) sa_handler));
267 return;
268 } while ((signr = current->signal & ~current->blocked));
269 if (regs->orig_eax >= 0 && regs->eax == -ERESTARTSYS) {
270 regs->eax = regs->orig_eax;
271 regs->eip = old_eip -= 2;
272 }
273 }