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 void sys_sigreturn(int signr, unsigned long oldmask, unsigned long unused)
147 {
148 current->blocked = oldmask & _BLOCKABLE;
149 }
150
151
152
153
154
155
156
157 static unsigned long * setup_first(struct pt_regs * regs,
158 int signr, unsigned long sa_handler, unsigned long oldmask)
159 {
160 unsigned long * tmp_esp;
161
162 regs->esp -= 18*4;
163 tmp_esp = (unsigned long *) regs->esp;
164 verify_area(VERIFY_WRITE,tmp_esp,18*4);
165
166 put_fs_long(regs->esp+15*4,tmp_esp);
167 put_fs_long(signr,tmp_esp+1);
168 put_fs_long(0,tmp_esp+2);
169 put_fs_long(oldmask,tmp_esp+3);
170 put_fs_long(__NR_sigreturn,tmp_esp+4);
171
172 return tmp_esp+5;
173 }
174
175
176
177
178
179
180 static void setup_other(unsigned long eip, struct pt_regs * regs, int signr,
181 unsigned long sa_handler, unsigned long oldmask)
182 {
183 unsigned long * tmp_esp;
184
185 regs->esp -= 9*4;
186 tmp_esp = (unsigned long *) regs->esp;
187 verify_area(VERIFY_WRITE,tmp_esp,9*4);
188
189 put_fs_long(regs->esp+6*4,tmp_esp);
190 put_fs_long(signr,tmp_esp+1);
191 put_fs_long(0,tmp_esp+2);
192 put_fs_long(oldmask,tmp_esp+3);
193 put_fs_long(__NR_sigreturn,tmp_esp+4);
194 put_fs_long(eip,tmp_esp+5);
195
196 put_fs_long(0x58595a5b,tmp_esp+6);
197 put_fs_long(0x909080cd,tmp_esp+7);
198 put_fs_long(0x000cc290,tmp_esp+8);
199 }
200
201
202
203
204
205
206 int do_signal(unsigned long oldmask, struct pt_regs * regs)
207 {
208 unsigned long *frame = NULL;
209 unsigned long eip = 0;
210 unsigned long signr;
211 unsigned long sa_handler;
212 struct sigaction * sa;
213
214 while ((signr = current->signal & ~current->blocked)) {
215 __asm__("bsf %2,%1\n\t"
216 "btrl %1,%0"
217 :"=m" (current->signal),"=r" (signr)
218 :"1" (signr));
219 sa = current->sigaction + signr;
220 signr++;
221 sa_handler = (unsigned long) sa->sa_handler;
222 if (sa_handler==1) {
223
224 if (signr == SIGCHLD)
225 while (sys_waitpid(-1,NULL,WNOHANG) > 0)
226 ;
227 continue;
228 }
229 if (!sa_handler) {
230 if (current->pid == 1)
231 continue;
232 switch (signr) {
233 case SIGCONT: case SIGCHLD: case SIGWINCH:
234 continue;
235
236 case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
237 current->state = TASK_STOPPED;
238 current->exit_code = signr;
239 if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
240 SA_NOCLDSTOP))
241 send_sig(SIGCHLD, current->p_pptr, 1);
242 schedule();
243 continue;
244
245 case SIGQUIT: case SIGILL: case SIGTRAP:
246 case SIGIOT: case SIGFPE: case SIGSEGV:
247 if (core_dump(signr,regs))
248 signr |= 0x80;
249
250 default:
251 current->signal |= _S(signr & 0x7f);
252 do_exit(signr);
253 }
254 }
255
256
257
258 if (regs->orig_eax >= 0) {
259 if (regs->eax == -ERESTARTNOHAND ||
260 (regs->eax == -ERESTARTSYS && (sa->sa_flags & SA_INTERRUPT)))
261 regs->eax = -EINTR;
262 }
263 if (sa->sa_flags & SA_ONESHOT)
264 sa->sa_handler = NULL;
265
266 __asm__("testb $0,%%fs:%0"::"m" (*(char *) sa_handler));
267 if (!frame) {
268 frame = setup_first(regs,signr,sa_handler,oldmask);
269 } else
270 setup_other(eip,regs,signr,sa_handler,oldmask);
271 eip = sa_handler;
272 current->blocked |= sa->sa_mask;
273 oldmask |= sa->sa_mask;
274 }
275 if (regs->orig_eax >= 0 &&
276 (regs->eax == -ERESTARTNOHAND ||
277 regs->eax == -ERESTARTSYS ||
278 regs->eax == -ERESTARTNOINTR)) {
279 regs->eax = regs->orig_eax;
280 regs->eip -= 2;
281 }
282 if (!frame)
283 return 0;
284
285 put_fs_long(regs->edi,frame);
286 put_fs_long(regs->esi,frame+1);
287 put_fs_long(regs->ebp,frame+2);
288 put_fs_long(regs->esp,frame+3);
289 put_fs_long(regs->ebx,frame+4);
290 put_fs_long(regs->edx,frame+5);
291 put_fs_long(regs->ecx,frame+6);
292 put_fs_long(regs->eax,frame+7);
293 put_fs_long(regs->eflags,frame+8);
294 put_fs_long(regs->eip,frame+9);
295
296 put_fs_long(0x58595a5b,frame+10);
297 put_fs_long(0x906180cd,frame+11);
298 put_fs_long(0x000cc29d,frame+12);
299 regs->eip = eip;
300 return 1;
301 }