This source file includes following definitions.
- sys_sgetmask
- sys_ssetmask
- sys_sigpending
- sys_sigsuspend
- check_pending
- sys_signal
- sys_sigaction
- sys_sigreturn
- setup_frame
- 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 #include <linux/unistd.h>
14
15 #include <asm/segment.h>
16
17 #define _S(nr) (1<<((nr)-1))
18
19 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
20
21 extern int core_dump(long signr,struct pt_regs * regs);
22
23 extern "C" int do_signal(unsigned long oldmask, struct pt_regs * regs);
24
25 extern "C" int sys_sgetmask(void)
26 {
27 return current->blocked;
28 }
29
30 extern "C" int sys_ssetmask(int newmask)
31 {
32 int old=current->blocked;
33
34 current->blocked = newmask & _BLOCKABLE;
35 return old;
36 }
37
38 extern "C" int sys_sigpending(sigset_t *set)
39 {
40 int error;
41
42 error = verify_area(VERIFY_WRITE, set, 4);
43 if (!error)
44 put_fs_long(current->blocked & current->signal, (unsigned long *)set);
45 return error;
46 }
47
48
49
50
51 extern "C" int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
52 {
53 unsigned long mask;
54 struct pt_regs * regs = (struct pt_regs *) &restart;
55
56 mask = current->blocked;
57 current->blocked = set & _BLOCKABLE;
58 regs->eax = -EINTR;
59 while (1) {
60 current->state = TASK_INTERRUPTIBLE;
61 schedule();
62 if (do_signal(mask,regs))
63 return -EINTR;
64 }
65 }
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 static void check_pending(int signum)
83 {
84 struct sigaction *p;
85
86 p = signum - 1 + current->sigaction;
87 if (p->sa_handler == SIG_IGN) {
88 if (signum == SIGCHLD)
89 return;
90 current->signal &= ~_S(signum);
91 return;
92 }
93 if (p->sa_handler == SIG_DFL) {
94 if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH)
95 return;
96 current->signal &= ~_S(signum);
97 return;
98 }
99 }
100
101 extern "C" int sys_signal(int signum, unsigned long handler)
102 {
103 struct sigaction tmp;
104
105 if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
106 return -EINVAL;
107 if (handler >= TASK_SIZE)
108 return -EFAULT;
109 tmp.sa_handler = (void (*)(int)) handler;
110 tmp.sa_mask = 0;
111 tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
112 tmp.sa_restorer = NULL;
113 handler = (long) current->sigaction[signum-1].sa_handler;
114 current->sigaction[signum-1] = tmp;
115 check_pending(signum);
116 return handler;
117 }
118
119 extern "C" int sys_sigaction(int signum, const struct sigaction * action,
120 struct sigaction * oldaction)
121 {
122 struct sigaction new_sa, *p;
123
124 if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
125 return -EINVAL;
126 p = signum - 1 + current->sigaction;
127 if (action) {
128 memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
129 if (new_sa.sa_flags & SA_NOMASK)
130 new_sa.sa_mask = 0;
131 else {
132 new_sa.sa_mask |= _S(signum);
133 new_sa.sa_mask &= _BLOCKABLE;
134 }
135 if (TASK_SIZE <= (unsigned long) new_sa.sa_handler)
136 return -EFAULT;
137 }
138 if (oldaction) {
139 if (!verify_area(VERIFY_WRITE,oldaction, sizeof(struct sigaction)))
140 memcpy_tofs(oldaction, p, sizeof(struct sigaction));
141 }
142 if (action) {
143 *p = new_sa;
144 check_pending(signum);
145 }
146 return 0;
147 }
148
149 extern "C" int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
150
151
152
153
154 extern "C" int sys_sigreturn(unsigned long oldmask, unsigned long eip, unsigned long esp)
155 {
156 struct pt_regs * regs;
157
158 regs = (struct pt_regs *) &oldmask;
159 current->blocked = oldmask & _BLOCKABLE;
160 regs->eip = eip;
161 regs->esp = esp;
162 return 0;
163 }
164
165
166
167
168
169 static void setup_frame(unsigned long ** fp, unsigned long eip,
170 struct pt_regs * regs, int signr,
171 unsigned long sa_handler, unsigned long oldmask)
172 {
173 unsigned long * frame;
174
175 #define __CODE ((unsigned long)(frame+24))
176 #define CODE(x) ((unsigned long *) ((x)+__CODE))
177 frame = *fp - 32;
178 verify_area(VERIFY_WRITE,frame,32*4);
179
180 put_fs_long(__CODE,frame);
181 put_fs_long(signr, frame+1);
182 put_fs_long(regs->gs, frame+2);
183 put_fs_long(regs->fs, frame+3);
184 put_fs_long(regs->es, frame+4);
185 put_fs_long(regs->ds, frame+5);
186 put_fs_long(regs->edi, frame+6);
187 put_fs_long(regs->esi, frame+7);
188 put_fs_long(regs->ebp, frame+8);
189 put_fs_long(regs->esp, frame+9);
190 put_fs_long(regs->ebx, frame+10);
191 put_fs_long(regs->edx, frame+11);
192 put_fs_long(regs->ecx, frame+12);
193 put_fs_long(regs->eax, frame+13);
194 put_fs_long(0, frame+14);
195 put_fs_long(0, frame+15);
196 put_fs_long(regs->eip, frame+16);
197 put_fs_long(regs->cs, frame+17);
198 put_fs_long(regs->eflags, frame+18);
199 put_fs_long(regs->esp, frame+19);
200 put_fs_long(regs->ss, frame+20);
201 put_fs_long(0,frame+21);
202
203 put_fs_long(regs->eflags, frame+22);
204 put_fs_long(eip, frame+23);
205
206 put_fs_long(0x0000b858, CODE(0));
207 put_fs_long(0x00bb0000, CODE(4));
208 put_fs_long(0xcd000000, CODE(8));
209 put_fs_long(0x0fa90f80, CODE(12));
210 put_fs_long(0x611f07a1, CODE(16));
211 put_fs_long(0x20c48390, CODE(20));
212 put_fs_long(0x0020c29d, CODE(24));
213 put_fs_long(__NR_ssetmask, CODE(2));
214 put_fs_long(oldmask, CODE(7));
215 *fp = frame;
216 #undef __CODE
217 #undef CODE
218 }
219
220
221
222
223
224
225
226
227
228
229 extern "C" int do_signal(unsigned long oldmask, struct pt_regs * regs)
230 {
231 unsigned long mask = ~current->blocked;
232 unsigned long handler_signal = 0;
233 unsigned long *frame = NULL;
234 unsigned long eip = 0;
235 unsigned long signr;
236 unsigned long sa_handler;
237 struct sigaction * sa;
238
239 while ((signr = current->signal & mask)) {
240 __asm__("bsf %2,%1\n\t"
241 "btrl %1,%0"
242 :"=m" (current->signal),"=r" (signr)
243 :"1" (signr));
244 sa = current->sigaction + signr;
245 signr++;
246 if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
247 current->exit_code = signr;
248 current->state = TASK_STOPPED;
249 notify_parent(current);
250 schedule();
251 if (!(signr = current->exit_code))
252 continue;
253 current->exit_code = 0;
254 if (signr == SIGSTOP)
255 continue;
256 if (_S(signr) & current->blocked) {
257 current->signal |= _S(signr);
258 continue;
259 }
260 sa = current->sigaction + signr - 1;
261 }
262 if (sa->sa_handler == SIG_IGN) {
263 if (signr != SIGCHLD)
264 continue;
265
266 while (sys_waitpid(-1,NULL,WNOHANG) > 0)
267 ;
268 continue;
269 }
270 if (sa->sa_handler == SIG_DFL) {
271 if (current->pid == 1)
272 continue;
273 switch (signr) {
274 case SIGCONT: case SIGCHLD: case SIGWINCH:
275 continue;
276
277 case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
278 current->state = TASK_STOPPED;
279 current->exit_code = signr;
280 if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
281 SA_NOCLDSTOP))
282 notify_parent(current);
283 schedule();
284 continue;
285
286 case SIGQUIT: case SIGILL: case SIGTRAP:
287 case SIGIOT: case SIGFPE: case SIGSEGV:
288 if (core_dump(signr,regs))
289 signr |= 0x80;
290
291 default:
292 current->signal |= _S(signr & 0x7f);
293 do_exit(signr);
294 }
295 }
296
297
298
299 if (regs->orig_eax >= 0) {
300 if (regs->eax == -ERESTARTNOHAND ||
301 (regs->eax == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
302 regs->eax = -EINTR;
303 }
304 handler_signal |= 1 << (signr-1);
305 mask &= ~sa->sa_mask;
306 }
307 if (regs->orig_eax >= 0 &&
308 (regs->eax == -ERESTARTNOHAND ||
309 regs->eax == -ERESTARTSYS ||
310 regs->eax == -ERESTARTNOINTR)) {
311 regs->eax = regs->orig_eax;
312 regs->eip -= 2;
313 }
314 if (!handler_signal)
315 return 0;
316 eip = regs->eip;
317 frame = (unsigned long *) regs->esp;
318 signr = 1;
319 sa = current->sigaction;
320 if (regs->cs != USER_CS || regs->ss != USER_DS)
321 printk("Warning: signal handler with nonstandard code/stack segment\n");
322 for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
323 if (mask > handler_signal)
324 break;
325 if (!(mask & handler_signal))
326 continue;
327 sa_handler = (unsigned long) sa->sa_handler;
328 if (sa->sa_flags & SA_ONESHOT)
329 sa->sa_handler = NULL;
330
331 __asm__("testb $0,%%fs:%0": :"m" (*(char *) sa_handler));
332 setup_frame(&frame,eip,regs,signr,sa_handler,oldmask);
333 eip = sa_handler;
334 current->blocked |= sa->sa_mask;
335 oldmask |= sa->sa_mask;
336 }
337 regs->esp = (unsigned long) frame;
338 regs->eip = eip;
339 return 1;
340 }