diff options
author | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 04:27:00 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2006-09-27 04:27:00 -0400 |
commit | 9f23e7e94f7083d9705b595cbd6b30972be6fbbb (patch) | |
tree | 5fc6e90a9e361dca2e56bb03327078a2eb88cb4c /arch/sh/kernel | |
parent | a2d1a5fae6296c2a3ac1aaa982c95464c46c0585 (diff) |
sh: pselect6 and ppoll, along with signal trampoline rework.
This implements support for ppoll() and pselect6()..
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r-- | arch/sh/kernel/entry.S | 8 | ||||
-rw-r--r-- | arch/sh/kernel/signal.c | 137 | ||||
-rw-r--r-- | arch/sh/kernel/syscalls.S | 31 |
3 files changed, 85 insertions, 91 deletions
diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S index fcbf50d4ee10..fd5fe2349f20 100644 --- a/arch/sh/kernel/entry.S +++ b/arch/sh/kernel/entry.S | |||
@@ -371,12 +371,12 @@ work_pending: | |||
371 | ! r8: current_thread_info | 371 | ! r8: current_thread_info |
372 | ! t: result of "tst #_TIF_NEED_RESCHED, r0" | 372 | ! t: result of "tst #_TIF_NEED_RESCHED, r0" |
373 | bf/s work_resched | 373 | bf/s work_resched |
374 | tst #_TIF_SIGPENDING, r0 | 374 | tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0 |
375 | work_notifysig: | 375 | work_notifysig: |
376 | bt/s restore_all | 376 | bt/s restore_all |
377 | mov r15, r4 | 377 | mov r15, r4 |
378 | mov #0, r5 | 378 | mov r12, r5 ! set arg1(save_r0) |
379 | mov r12, r6 ! set arg2(save_r0) | 379 | mov r0, r6 |
380 | mov.l 2f, r1 | 380 | mov.l 2f, r1 |
381 | mova restore_all, r0 | 381 | mova restore_all, r0 |
382 | jmp @r1 | 382 | jmp @r1 |
@@ -414,7 +414,7 @@ work_resched: | |||
414 | 414 | ||
415 | .align 2 | 415 | .align 2 |
416 | 1: .long schedule | 416 | 1: .long schedule |
417 | 2: .long do_signal | 417 | 2: .long do_notify_resume |
418 | 418 | ||
419 | .align 2 | 419 | .align 2 |
420 | syscall_exit_work: | 420 | syscall_exit_work: |
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c index eb6a3b97e46c..2f1c9545b49f 100644 --- a/arch/sh/kernel/signal.c +++ b/arch/sh/kernel/signal.c | |||
@@ -29,13 +29,10 @@ | |||
29 | #include <asm/pgtable.h> | 29 | #include <asm/pgtable.h> |
30 | #include <asm/cacheflush.h> | 30 | #include <asm/cacheflush.h> |
31 | 31 | ||
32 | #define DEBUG_SIG 0 | 32 | #undef DEBUG |
33 | 33 | ||
34 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 34 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
35 | 35 | ||
36 | asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, | ||
37 | unsigned int save_r0); | ||
38 | |||
39 | /* | 36 | /* |
40 | * Atomically swap in the new signal mask, and wait for a signal. | 37 | * Atomically swap in the new signal mask, and wait for a signal. |
41 | */ | 38 | */ |
@@ -44,51 +41,17 @@ sys_sigsuspend(old_sigset_t mask, | |||
44 | unsigned long r5, unsigned long r6, unsigned long r7, | 41 | unsigned long r5, unsigned long r6, unsigned long r7, |
45 | struct pt_regs regs) | 42 | struct pt_regs regs) |
46 | { | 43 | { |
47 | sigset_t saveset; | ||
48 | |||
49 | mask &= _BLOCKABLE; | 44 | mask &= _BLOCKABLE; |
50 | spin_lock_irq(¤t->sighand->siglock); | 45 | spin_lock_irq(¤t->sighand->siglock); |
51 | saveset = current->blocked; | 46 | current->saved_sigmask = current->blocked; |
52 | siginitset(¤t->blocked, mask); | 47 | siginitset(¤t->blocked, mask); |
53 | recalc_sigpending(); | 48 | recalc_sigpending(); |
54 | spin_unlock_irq(¤t->sighand->siglock); | 49 | spin_unlock_irq(¤t->sighand->siglock); |
55 | 50 | ||
56 | regs.regs[0] = -EINTR; | 51 | current->state = TASK_INTERRUPTIBLE; |
57 | while (1) { | 52 | schedule(); |
58 | current->state = TASK_INTERRUPTIBLE; | 53 | set_thread_flag(TIF_RESTORE_SIGMASK); |
59 | schedule(); | 54 | return -ERESTARTNOHAND; |
60 | if (do_signal(®s, &saveset, regs.regs[0])) | ||
61 | return -EINTR; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | asmlinkage int | ||
66 | sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, | ||
67 | unsigned long r6, unsigned long r7, | ||
68 | struct pt_regs regs) | ||
69 | { | ||
70 | sigset_t saveset, newset; | ||
71 | |||
72 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
73 | if (sigsetsize != sizeof(sigset_t)) | ||
74 | return -EINVAL; | ||
75 | |||
76 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
77 | return -EFAULT; | ||
78 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
79 | spin_lock_irq(¤t->sighand->siglock); | ||
80 | saveset = current->blocked; | ||
81 | current->blocked = newset; | ||
82 | recalc_sigpending(); | ||
83 | spin_unlock_irq(¤t->sighand->siglock); | ||
84 | |||
85 | regs.regs[0] = -EINTR; | ||
86 | while (1) { | ||
87 | current->state = TASK_INTERRUPTIBLE; | ||
88 | schedule(); | ||
89 | if (do_signal(®s, &saveset, regs.regs[0])) | ||
90 | return -EINTR; | ||
91 | } | ||
92 | } | 55 | } |
93 | 56 | ||
94 | asmlinkage int | 57 | asmlinkage int |
@@ -349,7 +312,7 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) | |||
349 | return (void __user *)((sp - frame_size) & -8ul); | 312 | return (void __user *)((sp - frame_size) & -8ul); |
350 | } | 313 | } |
351 | 314 | ||
352 | static void setup_frame(int sig, struct k_sigaction *ka, | 315 | static int setup_frame(int sig, struct k_sigaction *ka, |
353 | sigset_t *set, struct pt_regs *regs) | 316 | sigset_t *set, struct pt_regs *regs) |
354 | { | 317 | { |
355 | struct sigframe __user *frame; | 318 | struct sigframe __user *frame; |
@@ -369,10 +332,9 @@ static void setup_frame(int sig, struct k_sigaction *ka, | |||
369 | 332 | ||
370 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); | 333 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); |
371 | 334 | ||
372 | if (_NSIG_WORDS > 1) { | 335 | if (_NSIG_WORDS > 1) |
373 | err |= __copy_to_user(frame->extramask, &set->sig[1], | 336 | err |= __copy_to_user(frame->extramask, &set->sig[1], |
374 | sizeof(frame->extramask)); | 337 | sizeof(frame->extramask)); |
375 | } | ||
376 | 338 | ||
377 | /* Set up to return from userspace. If provided, use a stub | 339 | /* Set up to return from userspace. If provided, use a stub |
378 | already in userspace. */ | 340 | already in userspace. */ |
@@ -403,21 +365,22 @@ static void setup_frame(int sig, struct k_sigaction *ka, | |||
403 | 365 | ||
404 | set_fs(USER_DS); | 366 | set_fs(USER_DS); |
405 | 367 | ||
406 | #if DEBUG_SIG | 368 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", |
407 | printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", | 369 | current->comm, current->pid, frame, regs->pc, regs->pr); |
408 | current->comm, current->pid, frame, regs->pc, regs->pr); | ||
409 | #endif | ||
410 | 370 | ||
411 | flush_cache_sigtramp(regs->pr); | 371 | flush_cache_sigtramp(regs->pr); |
372 | |||
412 | if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) | 373 | if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) |
413 | flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); | 374 | flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); |
414 | return; | 375 | |
376 | return 0; | ||
415 | 377 | ||
416 | give_sigsegv: | 378 | give_sigsegv: |
417 | force_sigsegv(sig, current); | 379 | force_sigsegv(sig, current); |
380 | return -EFAULT; | ||
418 | } | 381 | } |
419 | 382 | ||
420 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 383 | static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
421 | sigset_t *set, struct pt_regs *regs) | 384 | sigset_t *set, struct pt_regs *regs) |
422 | { | 385 | { |
423 | struct rt_sigframe __user *frame; | 386 | struct rt_sigframe __user *frame; |
@@ -478,28 +441,31 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
478 | 441 | ||
479 | set_fs(USER_DS); | 442 | set_fs(USER_DS); |
480 | 443 | ||
481 | #if DEBUG_SIG | 444 | pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", |
482 | printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n", | 445 | current->comm, current->pid, frame, regs->pc, regs->pr); |
483 | current->comm, current->pid, frame, regs->pc, regs->pr); | ||
484 | #endif | ||
485 | 446 | ||
486 | flush_cache_sigtramp(regs->pr); | 447 | flush_cache_sigtramp(regs->pr); |
448 | |||
487 | if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) | 449 | if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode)) |
488 | flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); | 450 | flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES); |
489 | return; | 451 | |
452 | return 0; | ||
490 | 453 | ||
491 | give_sigsegv: | 454 | give_sigsegv: |
492 | force_sigsegv(sig, current); | 455 | force_sigsegv(sig, current); |
456 | return -EFAULT; | ||
493 | } | 457 | } |
494 | 458 | ||
495 | /* | 459 | /* |
496 | * OK, we're invoking a handler | 460 | * OK, we're invoking a handler |
497 | */ | 461 | */ |
498 | 462 | ||
499 | static void | 463 | static int |
500 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | 464 | handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, |
501 | sigset_t *oldset, struct pt_regs *regs) | 465 | sigset_t *oldset, struct pt_regs *regs) |
502 | { | 466 | { |
467 | int ret; | ||
468 | |||
503 | /* Are we from a system call? */ | 469 | /* Are we from a system call? */ |
504 | if (regs->tra >= 0) { | 470 | if (regs->tra >= 0) { |
505 | /* If so, check system call restarting.. */ | 471 | /* If so, check system call restarting.. */ |
@@ -540,19 +506,23 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | |||
540 | 506 | ||
541 | /* Set up the stack frame */ | 507 | /* Set up the stack frame */ |
542 | if (ka->sa.sa_flags & SA_SIGINFO) | 508 | if (ka->sa.sa_flags & SA_SIGINFO) |
543 | setup_rt_frame(sig, ka, info, oldset, regs); | 509 | ret = setup_rt_frame(sig, ka, info, oldset, regs); |
544 | else | 510 | else |
545 | setup_frame(sig, ka, oldset, regs); | 511 | ret = setup_frame(sig, ka, oldset, regs); |
546 | 512 | ||
547 | if (ka->sa.sa_flags & SA_ONESHOT) | 513 | if (ka->sa.sa_flags & SA_ONESHOT) |
548 | ka->sa.sa_handler = SIG_DFL; | 514 | ka->sa.sa_handler = SIG_DFL; |
549 | 515 | ||
550 | spin_lock_irq(¤t->sighand->siglock); | 516 | if (ret == 0) { |
551 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 517 | spin_lock_irq(¤t->sighand->siglock); |
552 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 518 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
553 | sigaddset(¤t->blocked,sig); | 519 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
554 | recalc_sigpending(); | 520 | sigaddset(¤t->blocked,sig); |
555 | spin_unlock_irq(¤t->sighand->siglock); | 521 | recalc_sigpending(); |
522 | spin_unlock_irq(¤t->sighand->siglock); | ||
523 | } | ||
524 | |||
525 | return ret; | ||
556 | } | 526 | } |
557 | 527 | ||
558 | /* | 528 | /* |
@@ -564,11 +534,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, | |||
564 | * the kernel can handle, and then we build all the user-level signal handling | 534 | * the kernel can handle, and then we build all the user-level signal handling |
565 | * stack-frames in one go after that. | 535 | * stack-frames in one go after that. |
566 | */ | 536 | */ |
567 | int do_signal(struct pt_regs *regs, sigset_t *oldset, unsigned int save_r0) | 537 | static void do_signal(struct pt_regs *regs, unsigned int save_r0) |
568 | { | 538 | { |
569 | siginfo_t info; | 539 | siginfo_t info; |
570 | int signr; | 540 | int signr; |
571 | struct k_sigaction ka; | 541 | struct k_sigaction ka; |
542 | sigset_t *oldset; | ||
572 | 543 | ||
573 | /* | 544 | /* |
574 | * We want the common case to go fast, which | 545 | * We want the common case to go fast, which |
@@ -577,19 +548,27 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, unsigned int save_r0) | |||
577 | * if so. | 548 | * if so. |
578 | */ | 549 | */ |
579 | if (!user_mode(regs)) | 550 | if (!user_mode(regs)) |
580 | return 1; | 551 | return; |
581 | 552 | ||
582 | if (try_to_freeze()) | 553 | if (try_to_freeze()) |
583 | goto no_signal; | 554 | goto no_signal; |
584 | 555 | ||
585 | if (!oldset) | 556 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
557 | oldset = ¤t->saved_sigmask; | ||
558 | else | ||
586 | oldset = ¤t->blocked; | 559 | oldset = ¤t->blocked; |
587 | 560 | ||
588 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 561 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
589 | if (signr > 0) { | 562 | if (signr > 0) { |
590 | /* Whee! Actually deliver the signal. */ | 563 | /* Whee! Actually deliver the signal. */ |
591 | handle_signal(signr, &ka, &info, oldset, regs); | 564 | if (handle_signal(signr, &ka, &info, oldset, regs) == 0) { |
592 | return 1; | 565 | /* a signal was successfully delivered; the saved |
566 | * sigmask will have been stored in the signal frame, | ||
567 | * and will be restored by sigreturn, so we can simply | ||
568 | * clear the TIF_RESTORE_SIGMASK flag */ | ||
569 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
570 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
571 | } | ||
593 | } | 572 | } |
594 | 573 | ||
595 | no_signal: | 574 | no_signal: |
@@ -606,5 +585,19 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, unsigned int save_r0) | |||
606 | regs->regs[3] = __NR_restart_syscall; | 585 | regs->regs[3] = __NR_restart_syscall; |
607 | } | 586 | } |
608 | } | 587 | } |
609 | return 0; | 588 | |
589 | /* if there's no signal to deliver, we just put the saved sigmask | ||
590 | * back */ | ||
591 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
592 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
593 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
594 | } | ||
595 | } | ||
596 | |||
597 | asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0, | ||
598 | __u32 thread_info_flags) | ||
599 | { | ||
600 | /* deal with pending signal delivery */ | ||
601 | if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)) | ||
602 | do_signal(regs, save_r0); | ||
610 | } | 603 | } |
diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S index ea23b213c77f..768334e95075 100644 --- a/arch/sh/kernel/syscalls.S +++ b/arch/sh/kernel/syscalls.S | |||
@@ -319,34 +319,35 @@ ENTRY(sys_call_table) | |||
319 | .long sys_mq_getsetattr | 319 | .long sys_mq_getsetattr |
320 | .long sys_kexec_load | 320 | .long sys_kexec_load |
321 | .long sys_waitid | 321 | .long sys_waitid |
322 | .long sys_add_key /* 285 */ | 322 | .long sys_ni_syscall /* 285 */ |
323 | .long sys_add_key | ||
323 | .long sys_request_key | 324 | .long sys_request_key |
324 | .long sys_keyctl | 325 | .long sys_keyctl |
325 | .long sys_ioprio_set | 326 | .long sys_ioprio_set |
326 | .long sys_ioprio_get | 327 | .long sys_ioprio_get /* 290 */ |
327 | .long sys_inotify_init /* 290 */ | 328 | .long sys_inotify_init |
328 | .long sys_inotify_add_watch | 329 | .long sys_inotify_add_watch |
329 | .long sys_inotify_rm_watch | 330 | .long sys_inotify_rm_watch |
330 | .long sys_migrate_pages | 331 | .long sys_migrate_pages |
331 | .long sys_openat | 332 | .long sys_openat /* 295 */ |
332 | .long sys_mkdirat /* 295 */ | 333 | .long sys_mkdirat |
333 | .long sys_mknodat | 334 | .long sys_mknodat |
334 | .long sys_fchownat | 335 | .long sys_fchownat |
335 | .long sys_futimesat | 336 | .long sys_futimesat |
336 | .long sys_fstatat64 | 337 | .long sys_fstatat64 /* 300 */ |
337 | .long sys_unlinkat /* 300 */ | 338 | .long sys_unlinkat |
338 | .long sys_renameat | 339 | .long sys_renameat |
339 | .long sys_linkat | 340 | .long sys_linkat |
340 | .long sys_symlinkat | 341 | .long sys_symlinkat |
341 | .long sys_readlinkat | 342 | .long sys_readlinkat /* 305 */ |
342 | .long sys_fchmodat /* 305 */ | 343 | .long sys_fchmodat |
343 | .long sys_faccessat | 344 | .long sys_faccessat |
344 | .long sys_ni_syscall /* Reserved for pselect6 */ | 345 | .long sys_pselect6 |
345 | .long sys_ni_syscall /* Reserved for ppoll */ | 346 | .long sys_ppoll |
346 | .long sys_unshare | 347 | .long sys_unshare /* 310 */ |
347 | .long sys_set_robust_list /* 310 */ | 348 | .long sys_set_robust_list |
348 | .long sys_get_robust_list | 349 | .long sys_get_robust_list |
349 | .long sys_splice | 350 | .long sys_splice |
350 | .long sys_sync_file_range | 351 | .long sys_sync_file_range |
351 | .long sys_tee | 352 | .long sys_tee /* 315 */ |
352 | .long sys_vmsplice /* 315 */ | 353 | .long sys_vmsplice |