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