sh: pselect6 and ppoll, along with signal trampoline rework.
authorPaul Mundt <lethal@linux-sh.org>
Wed, 27 Sep 2006 08:27:00 +0000 (17:27 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Wed, 27 Sep 2006 08:27:00 +0000 (17:27 +0900)
This implements support for ppoll() and pselect6()..

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/kernel/entry.S
arch/sh/kernel/signal.c
arch/sh/kernel/syscalls.S
include/asm-sh/thread_info.h
include/asm-sh/unistd.h

index fcbf50d..fd5fe23 100644 (file)
@@ -371,12 +371,12 @@ work_pending:
        ! r8: current_thread_info
        ! t:  result of "tst    #_TIF_NEED_RESCHED, r0"
        bf/s    work_resched
-        tst    #_TIF_SIGPENDING, r0
+        tst    #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
 work_notifysig:
        bt/s    restore_all
         mov    r15, r4
-       mov     #0, r5
-       mov     r12, r6         ! set arg2(save_r0)
+       mov     r12, r5         ! set arg1(save_r0)
+       mov     r0, r6
        mov.l   2f, r1
        mova    restore_all, r0
        jmp     @r1
@@ -414,7 +414,7 @@ work_resched:
 
        .align  2
 1:     .long   schedule
-2:     .long   do_signal
+2:     .long   do_notify_resume
 
        .align  2
 syscall_exit_work:
index eb6a3b9..2f1c954 100644 (file)
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
 
-#define DEBUG_SIG 0
+#undef DEBUG
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset,
-                        unsigned int save_r0);
-
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
@@ -44,51 +41,17 @@ sys_sigsuspend(old_sigset_t mask,
               unsigned long r5, unsigned long r6, unsigned long r7,
               struct pt_regs regs)
 {
-       sigset_t saveset;
-
        mask &= _BLOCKABLE;
        spin_lock_irq(&current->sighand->siglock);
-       saveset = current->blocked;
+       current->saved_sigmask = current->blocked;
        siginitset(&current->blocked, mask);
        recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
 
-       regs.regs[0] = -EINTR;
-       while (1) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule();
-               if (do_signal(&regs, &saveset, regs.regs[0]))
-                       return -EINTR;
-       }
-}
-
-asmlinkage int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
-                 unsigned long r6, unsigned long r7,
-                 struct pt_regs regs)
-{
-       sigset_t saveset, newset;
-
-       /* XXX: Don't preclude handling different sized sigset_t's.  */
-       if (sigsetsize != sizeof(sigset_t))
-               return -EINVAL;
-
-       if (copy_from_user(&newset, unewset, sizeof(newset)))
-               return -EFAULT;
-       sigdelsetmask(&newset, ~_BLOCKABLE);
-       spin_lock_irq(&current->sighand->siglock);
-       saveset = current->blocked;
-       current->blocked = newset;
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       regs.regs[0] = -EINTR;
-       while (1) {
-               current->state = TASK_INTERRUPTIBLE;
-               schedule();
-               if (do_signal(&regs, &saveset, regs.regs[0]))
-                       return -EINTR;
-       }
+       current->state = TASK_INTERRUPTIBLE;
+       schedule();
+       set_thread_flag(TIF_RESTORE_SIGMASK);
+       return -ERESTARTNOHAND;
 }
 
 asmlinkage int 
@@ -349,7 +312,7 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
        return (void __user *)((sp - frame_size) & -8ul);
 }
 
-static void setup_frame(int sig, struct k_sigaction *ka,
+static int setup_frame(int sig, struct k_sigaction *ka,
                        sigset_t *set, struct pt_regs *regs)
 {
        struct sigframe __user *frame;
@@ -369,10 +332,9 @@ static void setup_frame(int sig, struct k_sigaction *ka,
 
        err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
 
-       if (_NSIG_WORDS > 1) {
+       if (_NSIG_WORDS > 1)
                err |= __copy_to_user(frame->extramask, &set->sig[1],
                                      sizeof(frame->extramask));
-       }
 
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
@@ -403,21 +365,22 @@ static void setup_frame(int sig, struct k_sigaction *ka,
 
        set_fs(USER_DS);
 
-#if DEBUG_SIG
-       printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
-               current->comm, current->pid, frame, regs->pc, regs->pr);
-#endif
+       pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
+                current->comm, current->pid, frame, regs->pc, regs->pr);
 
        flush_cache_sigtramp(regs->pr);
+
        if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
                flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
-       return;
+
+       return 0;
 
 give_sigsegv:
        force_sigsegv(sig, current);
+       return -EFAULT;
 }
 
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                           sigset_t *set, struct pt_regs *regs)
 {
        struct rt_sigframe __user *frame;
@@ -478,28 +441,31 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 
        set_fs(USER_DS);
 
-#if DEBUG_SIG
-       printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
-               current->comm, current->pid, frame, regs->pc, regs->pr);
-#endif
+       pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
+                current->comm, current->pid, frame, regs->pc, regs->pr);
 
        flush_cache_sigtramp(regs->pr);
+
        if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
                flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
-       return;
+
+       return 0;
 
 give_sigsegv:
        force_sigsegv(sig, current);
+       return -EFAULT;
 }
 
 /*
  * OK, we're invoking a handler
  */
 
-static void
+static int
 handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
              sigset_t *oldset, struct pt_regs *regs)
 {
+       int ret;
+
        /* Are we from a system call? */
        if (regs->tra >= 0) {
                /* If so, check system call restarting.. */
@@ -540,19 +506,23 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
 
        /* Set up the stack frame */
        if (ka->sa.sa_flags & SA_SIGINFO)
-               setup_rt_frame(sig, ka, info, oldset, regs);
+               ret = setup_rt_frame(sig, ka, info, oldset, regs);
        else
-               setup_frame(sig, ka, oldset, regs);
+               ret = setup_frame(sig, ka, oldset, regs);
 
        if (ka->sa.sa_flags & SA_ONESHOT)
                ka->sa.sa_handler = SIG_DFL;
 
-       spin_lock_irq(&current->sighand->siglock);
-       sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
-       if (!(ka->sa.sa_flags & SA_NODEFER))
-               sigaddset(&current->blocked,sig);
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
+       if (ret == 0) {
+               spin_lock_irq(&current->sighand->siglock);
+               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
+                       sigaddset(&current->blocked,sig);
+               recalc_sigpending();
+               spin_unlock_irq(&current->sighand->siglock);
+       }
+
+       return ret;
 }
 
 /*
@@ -564,11 +534,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
  * the kernel can handle, and then we build all the user-level signal handling
  * stack-frames in one go after that.
  */
-int do_signal(struct pt_regs *regs, sigset_t *oldset, unsigned int save_r0)
+static void do_signal(struct pt_regs *regs, unsigned int save_r0)
 {
        siginfo_t info;
        int signr;
        struct k_sigaction ka;
+       sigset_t *oldset;
 
        /*
         * 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)
         * if so.
         */
        if (!user_mode(regs))
-               return 1;
+               return;
 
        if (try_to_freeze())
                goto no_signal;
 
-       if (!oldset)
+       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+               oldset = &current->saved_sigmask;
+       else
                oldset = &current->blocked;
 
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
        if (signr > 0) {
                /* Whee!  Actually deliver the signal.  */
-               handle_signal(signr, &ka, &info, oldset, regs);
-               return 1;
+               if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
+                       /* a signal was successfully delivered; the saved
+                        * sigmask will have been stored in the signal frame,
+                        * and will be restored by sigreturn, so we can simply
+                        * clear the TIF_RESTORE_SIGMASK flag */
+                       if (test_thread_flag(TIF_RESTORE_SIGMASK))
+                               clear_thread_flag(TIF_RESTORE_SIGMASK);
+               }
        }
 
  no_signal:
@@ -606,5 +585,19 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, unsigned int save_r0)
                        regs->regs[3] = __NR_restart_syscall;
                }
        }
-       return 0;
+
+       /* if there's no signal to deliver, we just put the saved sigmask
+        * back */
+       if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+               clear_thread_flag(TIF_RESTORE_SIGMASK);
+               sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+       }
+}
+
+asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,
+                                __u32 thread_info_flags)
+{
+       /* deal with pending signal delivery */
+       if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+               do_signal(regs, save_r0);
 }
index ea23b21..768334e 100644 (file)
@@ -319,34 +319,35 @@ ENTRY(sys_call_table)
        .long sys_mq_getsetattr
        .long sys_kexec_load
        .long sys_waitid
-       .long sys_add_key               /* 285 */
+       .long sys_ni_syscall            /* 285 */
+       .long sys_add_key
        .long sys_request_key
        .long sys_keyctl
        .long sys_ioprio_set
-       .long sys_ioprio_get
-       .long sys_inotify_init          /* 290 */
+       .long sys_ioprio_get            /* 290 */
+       .long sys_inotify_init
        .long sys_inotify_add_watch
        .long sys_inotify_rm_watch
        .long sys_migrate_pages
-       .long sys_openat
-       .long sys_mkdirat               /* 295 */
+       .long sys_openat                /* 295 */
+       .long sys_mkdirat
        .long sys_mknodat
        .long sys_fchownat
        .long sys_futimesat
-       .long sys_fstatat64
-       .long sys_unlinkat              /* 300 */
+       .long sys_fstatat64             /* 300 */
+       .long sys_unlinkat
        .long sys_renameat
        .long sys_linkat
        .long sys_symlinkat
-       .long sys_readlinkat
-       .long sys_fchmodat              /* 305 */
+       .long sys_readlinkat            /* 305 */
+       .long sys_fchmodat
        .long sys_faccessat
-       .long sys_ni_syscall            /* Reserved for pselect6 */
-       .long sys_ni_syscall            /* Reserved for ppoll */
-       .long sys_unshare
-       .long sys_set_robust_list       /* 310 */
+       .long sys_pselect6
+       .long sys_ppoll
+       .long sys_unshare               /* 310 */
+       .long sys_set_robust_list
        .long sys_get_robust_list
        .long sys_splice
        .long sys_sync_file_range
-       .long sys_tee
-       .long sys_vmsplice              /* 315 */
+       .long sys_tee                   /* 315 */
+       .long sys_vmsplice
index b986a19..5eb874b 100644 (file)
@@ -94,6 +94,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_NOTIFY_RESUME      1       /* resumption notification requested */
 #define TIF_SIGPENDING         2       /* signal pending */
 #define TIF_NEED_RESCHED       3       /* rescheduling necessary */
+#define TIF_RESTORE_SIGMASK    4       /* restore signal mask in do_signal() */
 #define TIF_USEDFPU            16      /* FPU was used by this task this quantum (SMP) */
 #define TIF_POLLING_NRFLAG     17      /* true if poll_idle() is polling TIF_NEED_RESCHED */
 #define TIF_MEMDIE             18
@@ -102,6 +103,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
+#define _TIF_RESTORE_SIGMASK   (1<<TIF_RESTORE_SIGMASK)
 #define _TIF_USEDFPU           (1<<TIF_USEDFPU)
 #define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
 
index 49c6a6e..080e572 100644 (file)
 #define __NR_mq_getsetattr      (__NR_mq_open+5)
 #define __NR_kexec_load                283
 #define __NR_waitid            284
-#define __NR_add_key           285
-#define __NR_request_key       286
-#define __NR_keyctl            287
-#define __NR_ioprio_set                288
-#define __NR_ioprio_get                289
-#define __NR_inotify_init      290
-#define __NR_inotify_add_watch 291
-#define __NR_inotify_rm_watch  292
-#define __NR_migrate_pages     293
-#define __NR_openat            294
-#define __NR_mkdirat           295
-#define __NR_mknodat           296
-#define __NR_fchownat          297
-#define __NR_futimesat         298
-#define __NR_fstatat64         299
-#define __NR_unlinkat          300
-#define __NR_renameat          301
-#define __NR_linkat            302
-#define __NR_symlinkat         303
-#define __NR_readlinkat                304
-#define __NR_fchmodat          305
-#define __NR_faccessat         305
-#define __NR_pselect6          307
-#define __NR_ppoll             308
-#define __NR_unshare           309
-#define __NR_set_robust_list   310
-#define __NR_get_robust_list   311
-#define __NR_splice            312
-#define __NR_sync_file_range   313
-#define __NR_tee               314
-#define __NR_vmsplice          315
+/* #define __NR_sys_setaltroot 285 */
+#define __NR_add_key           286
+#define __NR_request_key       287
+#define __NR_keyctl            288
+#define __NR_ioprio_set                289
+#define __NR_ioprio_get                290
+#define __NR_inotify_init      291
+#define __NR_inotify_add_watch 292
+#define __NR_inotify_rm_watch  293
+#define __NR_migrate_pages     294
+#define __NR_openat            295
+#define __NR_mkdirat           296
+#define __NR_mknodat           297
+#define __NR_fchownat          298
+#define __NR_futimesat         299
+#define __NR_newfstatat                300
+#define __NR_unlinkat          301
+#define __NR_renameat          302
+#define __NR_linkat            303
+#define __NR_symlinkat         304
+#define __NR_readlinkat                305
+#define __NR_fchmodat          306
+#define __NR_faccessat         307
+#define __NR_pselect6          308
+#define __NR_ppoll             309
+#define __NR_unshare           310
+#define __NR_set_robust_list   311
+#define __NR_get_robust_list   312
+#define __NR_splice            313
+#define __NR_sync_file_range   314
+#define __NR_tee               315
+#define __NR_vmsplice          316
 
-#define NR_syscalls 316
+#define NR_syscalls 317
 
 #ifdef __KERNEL__
 
@@ -466,6 +467,7 @@ __syscall_return(type,__sc0); \
 #define __ARCH_WANT_SYS_SIGPENDING
 #define __ARCH_WANT_SYS_SIGPROCMASK
 #define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
 
 #ifdef __KERNEL_SYSCALLS__