]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* signal.c: FRV specific bits of signal handling |
2 | * | |
3 | * Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved. | |
4 | * Written by David Howells (dhowells@redhat.com) | |
5 | * - Derived from arch/m68k/kernel/signal.c | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License | |
9 | * as published by the Free Software Foundation; either version | |
10 | * 2 of the License, or (at your option) any later version. | |
11 | */ | |
12 | ||
13 | #include <linux/sched.h> | |
14 | #include <linux/mm.h> | |
15 | #include <linux/smp.h> | |
16 | #include <linux/smp_lock.h> | |
17 | #include <linux/kernel.h> | |
18 | #include <linux/signal.h> | |
19 | #include <linux/errno.h> | |
20 | #include <linux/wait.h> | |
21 | #include <linux/ptrace.h> | |
22 | #include <linux/unistd.h> | |
23 | #include <linux/personality.h> | |
24 | #include <linux/suspend.h> | |
25 | #include <asm/ucontext.h> | |
26 | #include <asm/uaccess.h> | |
27 | #include <asm/cacheflush.h> | |
28 | ||
29 | #define DEBUG_SIG 0 | |
30 | ||
31 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | |
32 | ||
33 | struct fdpic_func_descriptor { | |
34 | unsigned long text; | |
35 | unsigned long GOT; | |
36 | }; | |
37 | ||
38 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); | |
39 | ||
40 | /* | |
41 | * Atomically swap in the new signal mask, and wait for a signal. | |
42 | */ | |
43 | asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask) | |
44 | { | |
45 | sigset_t saveset; | |
46 | ||
47 | mask &= _BLOCKABLE; | |
48 | spin_lock_irq(¤t->sighand->siglock); | |
49 | saveset = current->blocked; | |
50 | siginitset(¤t->blocked, mask); | |
51 | recalc_sigpending(); | |
52 | spin_unlock_irq(¤t->sighand->siglock); | |
53 | ||
54 | __frame->gr8 = -EINTR; | |
55 | while (1) { | |
56 | current->state = TASK_INTERRUPTIBLE; | |
57 | schedule(); | |
58 | if (do_signal(__frame, &saveset)) | |
59 | /* return the signal number as the return value of this function | |
60 | * - this is an utterly evil hack. syscalls should not invoke do_signal() | |
61 | * as entry.S sets regs->gr8 to the return value of the system call | |
62 | * - we can't just use sigpending() as we'd have to discard SIG_IGN signals | |
63 | * and call waitpid() if SIGCHLD needed discarding | |
64 | * - this only works on the i386 because it passes arguments to the signal | |
65 | * handler on the stack, and the return value in EAX is effectively | |
66 | * discarded | |
67 | */ | |
68 | return __frame->gr8; | |
69 | } | |
70 | } | |
71 | ||
72 | asmlinkage int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) | |
73 | { | |
74 | sigset_t saveset, newset; | |
75 | ||
76 | /* XXX: Don't preclude handling different sized sigset_t's. */ | |
77 | if (sigsetsize != sizeof(sigset_t)) | |
78 | return -EINVAL; | |
79 | ||
80 | if (copy_from_user(&newset, unewset, sizeof(newset))) | |
81 | return -EFAULT; | |
82 | sigdelsetmask(&newset, ~_BLOCKABLE); | |
83 | ||
84 | spin_lock_irq(¤t->sighand->siglock); | |
85 | saveset = current->blocked; | |
86 | current->blocked = newset; | |
87 | recalc_sigpending(); | |
88 | spin_unlock_irq(¤t->sighand->siglock); | |
89 | ||
90 | __frame->gr8 = -EINTR; | |
91 | while (1) { | |
92 | current->state = TASK_INTERRUPTIBLE; | |
93 | schedule(); | |
94 | if (do_signal(__frame, &saveset)) | |
95 | /* return the signal number as the return value of this function | |
96 | * - this is an utterly evil hack. syscalls should not invoke do_signal() | |
97 | * as entry.S sets regs->gr8 to the return value of the system call | |
98 | * - we can't just use sigpending() as we'd have to discard SIG_IGN signals | |
99 | * and call waitpid() if SIGCHLD needed discarding | |
100 | * - this only works on the i386 because it passes arguments to the signal | |
101 | * handler on the stack, and the return value in EAX is effectively | |
102 | * discarded | |
103 | */ | |
104 | return __frame->gr8; | |
105 | } | |
106 | } | |
107 | ||
108 | asmlinkage int sys_sigaction(int sig, | |
109 | const struct old_sigaction __user *act, | |
110 | struct old_sigaction __user *oact) | |
111 | { | |
112 | struct k_sigaction new_ka, old_ka; | |
113 | int ret; | |
114 | ||
115 | if (act) { | |
116 | old_sigset_t mask; | |
117 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | |
118 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | |
119 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | |
120 | return -EFAULT; | |
121 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | |
122 | __get_user(mask, &act->sa_mask); | |
123 | siginitset(&new_ka.sa.sa_mask, mask); | |
124 | } | |
125 | ||
126 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | |
127 | ||
128 | if (!ret && oact) { | |
129 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | |
130 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | |
131 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | |
132 | return -EFAULT; | |
133 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | |
134 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | |
135 | } | |
136 | ||
137 | return ret; | |
138 | } | |
139 | ||
140 | asmlinkage | |
141 | int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) | |
142 | { | |
143 | return do_sigaltstack(uss, uoss, __frame->sp); | |
144 | } | |
145 | ||
146 | ||
147 | /* | |
148 | * Do a signal return; undo the signal stack. | |
149 | */ | |
150 | ||
151 | struct sigframe | |
152 | { | |
153 | void (*pretcode)(void); | |
154 | int sig; | |
155 | struct sigcontext sc; | |
156 | unsigned long extramask[_NSIG_WORDS-1]; | |
157 | uint32_t retcode[2]; | |
158 | }; | |
159 | ||
160 | struct rt_sigframe | |
161 | { | |
162 | void (*pretcode)(void); | |
163 | int sig; | |
164 | struct siginfo *pinfo; | |
165 | void *puc; | |
166 | struct siginfo info; | |
167 | struct ucontext uc; | |
168 | uint32_t retcode[2]; | |
169 | }; | |
170 | ||
171 | static int restore_sigcontext(struct sigcontext __user *sc, int *_gr8) | |
172 | { | |
173 | struct user_context *user = current->thread.user; | |
174 | unsigned long tbr, psr; | |
175 | ||
176 | tbr = user->i.tbr; | |
177 | psr = user->i.psr; | |
178 | if (copy_from_user(user, &sc->sc_context, sizeof(sc->sc_context))) | |
179 | goto badframe; | |
180 | user->i.tbr = tbr; | |
181 | user->i.psr = psr; | |
182 | ||
183 | restore_user_regs(user); | |
184 | ||
185 | user->i.syscallno = -1; /* disable syscall checks */ | |
186 | ||
187 | *_gr8 = user->i.gr[8]; | |
188 | return 0; | |
189 | ||
190 | badframe: | |
191 | return 1; | |
192 | } | |
193 | ||
194 | asmlinkage int sys_sigreturn(void) | |
195 | { | |
196 | struct sigframe __user *frame = (struct sigframe __user *) __frame->sp; | |
197 | sigset_t set; | |
198 | int gr8; | |
199 | ||
200 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | |
201 | goto badframe; | |
202 | if (__get_user(set.sig[0], &frame->sc.sc_oldmask)) | |
203 | goto badframe; | |
204 | ||
205 | if (_NSIG_WORDS > 1 && | |
206 | __copy_from_user(&set.sig[1], &frame->extramask, sizeof(frame->extramask))) | |
207 | goto badframe; | |
208 | ||
209 | sigdelsetmask(&set, ~_BLOCKABLE); | |
210 | spin_lock_irq(¤t->sighand->siglock); | |
211 | current->blocked = set; | |
212 | recalc_sigpending(); | |
213 | spin_unlock_irq(¤t->sighand->siglock); | |
214 | ||
215 | if (restore_sigcontext(&frame->sc, &gr8)) | |
216 | goto badframe; | |
217 | return gr8; | |
218 | ||
219 | badframe: | |
220 | force_sig(SIGSEGV, current); | |
221 | return 0; | |
222 | } | |
223 | ||
224 | asmlinkage int sys_rt_sigreturn(void) | |
225 | { | |
226 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *) __frame->sp; | |
227 | sigset_t set; | |
228 | int gr8; | |
229 | ||
230 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | |
231 | goto badframe; | |
232 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | |
233 | goto badframe; | |
234 | ||
235 | sigdelsetmask(&set, ~_BLOCKABLE); | |
236 | spin_lock_irq(¤t->sighand->siglock); | |
237 | current->blocked = set; | |
238 | recalc_sigpending(); | |
239 | spin_unlock_irq(¤t->sighand->siglock); | |
240 | ||
241 | if (restore_sigcontext(&frame->uc.uc_mcontext, &gr8)) | |
242 | goto badframe; | |
243 | ||
244 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, __frame->sp) == -EFAULT) | |
245 | goto badframe; | |
246 | ||
247 | return gr8; | |
248 | ||
249 | badframe: | |
250 | force_sig(SIGSEGV, current); | |
251 | return 0; | |
252 | } | |
253 | ||
254 | /* | |
255 | * Set up a signal frame | |
256 | */ | |
257 | static int setup_sigcontext(struct sigcontext __user *sc, unsigned long mask) | |
258 | { | |
259 | save_user_regs(current->thread.user); | |
260 | ||
261 | if (copy_to_user(&sc->sc_context, current->thread.user, sizeof(sc->sc_context)) != 0) | |
262 | goto badframe; | |
263 | ||
264 | /* non-iBCS2 extensions.. */ | |
265 | if (__put_user(mask, &sc->sc_oldmask) < 0) | |
266 | goto badframe; | |
267 | ||
268 | return 0; | |
269 | ||
270 | badframe: | |
271 | return 1; | |
272 | } | |
273 | ||
274 | /*****************************************************************************/ | |
275 | /* | |
276 | * Determine which stack to use.. | |
277 | */ | |
278 | static inline void __user *get_sigframe(struct k_sigaction *ka, | |
279 | struct pt_regs *regs, | |
280 | size_t frame_size) | |
281 | { | |
282 | unsigned long sp; | |
283 | ||
284 | /* Default to using normal stack */ | |
285 | sp = regs->sp; | |
286 | ||
287 | /* This is the X/Open sanctioned signal stack switching. */ | |
288 | if (ka->sa.sa_flags & SA_ONSTACK) { | |
289 | if (! on_sig_stack(sp)) | |
290 | sp = current->sas_ss_sp + current->sas_ss_size; | |
291 | } | |
292 | ||
293 | return (void __user *) ((sp - frame_size) & ~7UL); | |
294 | } /* end get_sigframe() */ | |
295 | ||
296 | /*****************************************************************************/ | |
297 | /* | |
298 | * | |
299 | */ | |
300 | static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) | |
301 | { | |
302 | struct sigframe __user *frame; | |
303 | int rsig; | |
304 | ||
305 | frame = get_sigframe(ka, regs, sizeof(*frame)); | |
306 | ||
307 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | |
308 | goto give_sigsegv; | |
309 | ||
310 | rsig = sig; | |
311 | if (sig < 32 && | |
312 | __current_thread_info->exec_domain && | |
313 | __current_thread_info->exec_domain->signal_invmap) | |
314 | rsig = __current_thread_info->exec_domain->signal_invmap[sig]; | |
315 | ||
316 | if (__put_user(rsig, &frame->sig) < 0) | |
317 | goto give_sigsegv; | |
318 | ||
319 | if (setup_sigcontext(&frame->sc, set->sig[0])) | |
320 | goto give_sigsegv; | |
321 | ||
322 | if (_NSIG_WORDS > 1) { | |
323 | if (__copy_to_user(frame->extramask, &set->sig[1], | |
324 | sizeof(frame->extramask))) | |
325 | goto give_sigsegv; | |
326 | } | |
327 | ||
328 | /* Set up to return from userspace. If provided, use a stub | |
329 | * already in userspace. */ | |
330 | if (ka->sa.sa_flags & SA_RESTORER) { | |
331 | if (__put_user(ka->sa.sa_restorer, &frame->pretcode) < 0) | |
332 | goto give_sigsegv; | |
333 | } | |
334 | else { | |
335 | /* Set up the following code on the stack: | |
336 | * setlos #__NR_sigreturn,gr7 | |
337 | * tira gr0,0 | |
338 | */ | |
339 | if (__put_user((void (*)(void))frame->retcode, &frame->pretcode) || | |
340 | __put_user(0x8efc0000|__NR_sigreturn, &frame->retcode[0]) || | |
341 | __put_user(0xc0700000, &frame->retcode[1])) | |
342 | goto give_sigsegv; | |
343 | ||
344 | flush_icache_range((unsigned long) frame->retcode, | |
345 | (unsigned long) (frame->retcode + 2)); | |
346 | } | |
347 | ||
348 | /* set up registers for signal handler */ | |
349 | regs->sp = (unsigned long) frame; | |
350 | regs->lr = (unsigned long) &frame->retcode; | |
351 | regs->gr8 = sig; | |
352 | ||
353 | if (get_personality & FDPIC_FUNCPTRS) { | |
354 | struct fdpic_func_descriptor __user *funcptr = | |
355 | (struct fdpic_func_descriptor *) ka->sa.sa_handler; | |
356 | __get_user(regs->pc, &funcptr->text); | |
357 | __get_user(regs->gr15, &funcptr->GOT); | |
358 | } else { | |
359 | regs->pc = (unsigned long) ka->sa.sa_handler; | |
360 | regs->gr15 = 0; | |
361 | } | |
362 | ||
363 | set_fs(USER_DS); | |
364 | ||
365 | #if DEBUG_SIG | |
366 | printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", | |
367 | sig, current->comm, current->pid, frame, regs->pc, frame->pretcode); | |
368 | #endif | |
369 | ||
370 | return; | |
371 | ||
372 | give_sigsegv: | |
373 | if (sig == SIGSEGV) | |
374 | ka->sa.sa_handler = SIG_DFL; | |
375 | ||
376 | force_sig(SIGSEGV, current); | |
377 | } /* end setup_frame() */ | |
378 | ||
379 | /*****************************************************************************/ | |
380 | /* | |
381 | * | |
382 | */ | |
383 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |
384 | sigset_t *set, struct pt_regs * regs) | |
385 | { | |
386 | struct rt_sigframe __user *frame; | |
387 | int rsig; | |
388 | ||
389 | frame = get_sigframe(ka, regs, sizeof(*frame)); | |
390 | ||
391 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | |
392 | goto give_sigsegv; | |
393 | ||
394 | rsig = sig; | |
395 | if (sig < 32 && | |
396 | __current_thread_info->exec_domain && | |
397 | __current_thread_info->exec_domain->signal_invmap) | |
398 | rsig = __current_thread_info->exec_domain->signal_invmap[sig]; | |
399 | ||
400 | if (__put_user(rsig, &frame->sig) || | |
401 | __put_user(&frame->info, &frame->pinfo) || | |
402 | __put_user(&frame->uc, &frame->puc)) | |
403 | goto give_sigsegv; | |
404 | ||
405 | if (copy_siginfo_to_user(&frame->info, info)) | |
406 | goto give_sigsegv; | |
407 | ||
408 | /* Create the ucontext. */ | |
409 | if (__put_user(0, &frame->uc.uc_flags) || | |
410 | __put_user(0, &frame->uc.uc_link) || | |
411 | __put_user((void*)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) || | |
412 | __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags) || | |
413 | __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size)) | |
414 | goto give_sigsegv; | |
415 | ||
416 | if (setup_sigcontext(&frame->uc.uc_mcontext, set->sig[0])) | |
417 | goto give_sigsegv; | |
418 | ||
419 | if (__copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set))) | |
420 | goto give_sigsegv; | |
421 | ||
422 | /* Set up to return from userspace. If provided, use a stub | |
423 | * already in userspace. */ | |
424 | if (ka->sa.sa_flags & SA_RESTORER) { | |
425 | if (__put_user(ka->sa.sa_restorer, &frame->pretcode)) | |
426 | goto give_sigsegv; | |
427 | } | |
428 | else { | |
429 | /* Set up the following code on the stack: | |
430 | * setlos #__NR_sigreturn,gr7 | |
431 | * tira gr0,0 | |
432 | */ | |
433 | if (__put_user((void (*)(void))frame->retcode, &frame->pretcode) || | |
434 | __put_user(0x8efc0000|__NR_rt_sigreturn, &frame->retcode[0]) || | |
435 | __put_user(0xc0700000, &frame->retcode[1])) | |
436 | goto give_sigsegv; | |
437 | ||
438 | flush_icache_range((unsigned long) frame->retcode, | |
439 | (unsigned long) (frame->retcode + 2)); | |
440 | } | |
441 | ||
442 | /* Set up registers for signal handler */ | |
443 | regs->sp = (unsigned long) frame; | |
444 | regs->lr = (unsigned long) &frame->retcode; | |
445 | regs->gr8 = sig; | |
446 | regs->gr9 = (unsigned long) &frame->info; | |
447 | ||
448 | if (get_personality & FDPIC_FUNCPTRS) { | |
449 | struct fdpic_func_descriptor *funcptr = | |
450 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; | |
451 | __get_user(regs->pc, &funcptr->text); | |
452 | __get_user(regs->gr15, &funcptr->GOT); | |
453 | } else { | |
454 | regs->pc = (unsigned long) ka->sa.sa_handler; | |
455 | regs->gr15 = 0; | |
456 | } | |
457 | ||
458 | set_fs(USER_DS); | |
459 | ||
460 | #if DEBUG_SIG | |
461 | printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", | |
462 | sig, current->comm, current->pid, frame, regs->pc, frame->pretcode); | |
463 | #endif | |
464 | ||
465 | return; | |
466 | ||
467 | give_sigsegv: | |
468 | if (sig == SIGSEGV) | |
469 | ka->sa.sa_handler = SIG_DFL; | |
470 | force_sig(SIGSEGV, current); | |
471 | ||
472 | } /* end setup_rt_frame() */ | |
473 | ||
474 | /*****************************************************************************/ | |
475 | /* | |
476 | * OK, we're invoking a handler | |
477 | */ | |
478 | static void handle_signal(unsigned long sig, siginfo_t *info, | |
479 | struct k_sigaction *ka, sigset_t *oldset, | |
480 | struct pt_regs *regs) | |
481 | { | |
482 | /* Are we from a system call? */ | |
483 | if (in_syscall(regs)) { | |
484 | /* If so, check system call restarting.. */ | |
485 | switch (regs->gr8) { | |
486 | case -ERESTART_RESTARTBLOCK: | |
487 | case -ERESTARTNOHAND: | |
488 | regs->gr8 = -EINTR; | |
489 | break; | |
490 | ||
491 | case -ERESTARTSYS: | |
492 | if (!(ka->sa.sa_flags & SA_RESTART)) { | |
493 | regs->gr8 = -EINTR; | |
494 | break; | |
495 | } | |
496 | /* fallthrough */ | |
497 | case -ERESTARTNOINTR: | |
498 | regs->gr8 = regs->orig_gr8; | |
499 | regs->pc -= 4; | |
500 | } | |
501 | } | |
502 | ||
503 | /* Set up the stack frame */ | |
504 | if (ka->sa.sa_flags & SA_SIGINFO) | |
505 | setup_rt_frame(sig, ka, info, oldset, regs); | |
506 | else | |
507 | setup_frame(sig, ka, oldset, regs); | |
508 | ||
69be8f18 SR |
509 | spin_lock_irq(¤t->sighand->siglock); |
510 | sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask); | |
511 | if (!(ka->sa.sa_flags & SA_NODEFER)) | |
1da177e4 | 512 | sigaddset(¤t->blocked, sig); |
69be8f18 SR |
513 | recalc_sigpending(); |
514 | spin_unlock_irq(¤t->sighand->siglock); | |
1da177e4 LT |
515 | } /* end handle_signal() */ |
516 | ||
517 | /*****************************************************************************/ | |
518 | /* | |
519 | * Note that 'init' is a special process: it doesn't get signals it doesn't | |
520 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | |
521 | * mistake. | |
522 | */ | |
523 | int do_signal(struct pt_regs *regs, sigset_t *oldset) | |
524 | { | |
525 | struct k_sigaction ka; | |
526 | siginfo_t info; | |
527 | int signr; | |
528 | ||
529 | /* | |
530 | * We want the common case to go fast, which | |
531 | * is why we may in certain cases get here from | |
532 | * kernel mode. Just return without doing anything | |
533 | * if so. | |
534 | */ | |
535 | if (!user_mode(regs)) | |
536 | return 1; | |
537 | ||
3e1d1d28 | 538 | if (try_to_freeze()) |
1da177e4 | 539 | goto no_signal; |
1da177e4 LT |
540 | |
541 | if (!oldset) | |
542 | oldset = ¤t->blocked; | |
543 | ||
544 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | |
545 | if (signr > 0) { | |
546 | handle_signal(signr, &info, &ka, oldset, regs); | |
547 | return 1; | |
548 | } | |
549 | ||
550 | no_signal: | |
551 | /* Did we come from a system call? */ | |
552 | if (regs->syscallno >= 0) { | |
553 | /* Restart the system call - no handlers present */ | |
554 | if (regs->gr8 == -ERESTARTNOHAND || | |
555 | regs->gr8 == -ERESTARTSYS || | |
556 | regs->gr8 == -ERESTARTNOINTR) { | |
557 | regs->gr8 = regs->orig_gr8; | |
558 | regs->pc -= 4; | |
559 | } | |
560 | ||
561 | if (regs->gr8 == -ERESTART_RESTARTBLOCK){ | |
562 | regs->gr8 = __NR_restart_syscall; | |
563 | regs->pc -= 4; | |
564 | } | |
565 | } | |
566 | ||
567 | return 0; | |
568 | } /* end do_signal() */ | |
569 | ||
570 | /*****************************************************************************/ | |
571 | /* | |
572 | * notification of userspace execution resumption | |
573 | * - triggered by current->work.notify_resume | |
574 | */ | |
575 | asmlinkage void do_notify_resume(__u32 thread_info_flags) | |
576 | { | |
577 | /* pending single-step? */ | |
578 | if (thread_info_flags & _TIF_SINGLESTEP) | |
579 | clear_thread_flag(TIF_SINGLESTEP); | |
580 | ||
581 | /* deal with pending signal delivery */ | |
582 | if (thread_info_flags & _TIF_SIGPENDING) | |
583 | do_signal(__frame, NULL); | |
584 | ||
585 | } /* end do_notify_resume() */ |