source: trunk/target/linux/generic-2.6/patches-2.6.30/965-arm_restore_sigmask_v2.patch @ 17685

Last change on this file since 17685 was 17685, checked in by juhosg, 7 years ago

kernel: refresh 2.6.30 patches

File size: 11.4 KB
  • arch/arm/include/asm/thread_info.h

    From: Mikael Pettersson <mikpe@it.uu.se>
    Date: Sat, 15 Aug 2009 11:58:11 +0000 (+0100)
    Subject: ARM: 5677/1: ARM support for TIF_RESTORE_SIGMASK/pselect6/ppoll/epoll_pwait
    X-Git-Tag: next-20090817~86^2~1^6
    X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fnext%2Flinux-next.git;a=commitdiff_plain;h=369842658a36bcea28ecb643ba4bdb53919330dd
    
    ARM: 5677/1: ARM support for TIF_RESTORE_SIGMASK/pselect6/ppoll/epoll_pwait
    
    This patch adds support for TIF_RESTORE_SIGMASK to ARM's
    signal handling, which allows to hook up the pselect6, ppoll,
    and epoll_pwait syscalls on ARM.
    
    Tested here with eabi userspace and a test program with a
    deliberate race between a child's exit and the parent's
    sigprocmask/select sequence. Using sys_pselect6() instead
    of sigprocmask/select reliably prevents the race.
    
    The other arch's support for TIF_RESTORE_SIGMASK has evolved
    over time:
    
    In 2.6.16:
    - add TIF_RESTORE_SIGMASK which parallels TIF_SIGPENDING
    - test both when checking for pending signal [changed later]
    - reimplement sys_sigsuspend() to use current->saved_sigmask,
      TIF_RESTORE_SIGMASK [changed later], and -ERESTARTNOHAND;
      ditto for sys_rt_sigsuspend(), but drop private code and
      use common code via __ARCH_WANT_SYS_RT_SIGSUSPEND;
    - there are now no "extra" calls to do_signal() so its oldset
      parameter is always &current->blocked so need not be passed,
      also its return value is changed to void
    - change handle_signal() to return 0/-errno
    - change do_signal() to honor TIF_RESTORE_SIGMASK:
      + get oldset from current->saved_sigmask if TIF_RESTORE_SIGMASK
        is set
      + if handle_signal() was successful then clear TIF_RESTORE_SIGMASK
      + if no signal was delivered and TIF_RESTORE_SIGMASK is set then
        clear it and restore the sigmask
    - hook up sys_pselect6() and sys_ppoll()
    
    In 2.6.19:
    - hook up sys_epoll_pwait()
    
    In 2.6.26:
    - allow archs to override how TIF_RESTORE_SIGMASK is implemented;
      default set_restore_sigmask() sets both TIF_RESTORE_SIGMASK and
      TIF_SIGPENDING; archs need now just test TIF_SIGPENDING again
      when checking for pending signal work; some archs now implement
      TIF_RESTORE_SIGMASK as a secondary/non-atomic thread flag bit
    - call set_restore_sigmask() in sys_sigsuspend() instead of setting
      TIF_RESTORE_SIGMASK
    
    In 2.6.29-rc:
    - kill sys_pselect7() which no arch wanted
    
    So for 2.6.31-rc6/ARM this patch does the following:
    - Add TIF_RESTORE_SIGMASK. Use the generic set_restore_sigmask()
      which sets both TIF_SIGPENDING and TIF_RESTORE_SIGMASK, so
      TIF_RESTORE_SIGMASK need not claim one of the scarce low thread
      flags, and existing TIF_SIGPENDING and _TIF_WORK_MASK tests need
      not be extended for TIF_RESTORE_SIGMASK.
    - sys_sigsuspend() is reimplemented to use current->saved_sigmask
      and set_restore_sigmask(), making it identical to most other archs
    - The private code for sys_rt_sigsuspend() is removed, instead
      generic code supplies it via __ARCH_WANT_SYS_RT_SIGSUSPEND.
    - sys_sigsuspend() and sys_rt_sigsuspend() no longer need a pt_regs
      parameter, so their assembly code wrappers are removed.
    - handle_signal() is changed to return 0 on success or -errno.
    - The oldset parameter to do_signal() is now redundant and removed,
      and the return value is now also redundant and changed to void.
    - do_signal() is changed to honor TIF_RESTORE_SIGMASK:
      + get oldset from current->saved_sigmask if TIF_RESTORE_SIGMASK
        is set
      + if handle_signal() was successful then clear TIF_RESTORE_SIGMASK
      + if no signal was delivered and TIF_RESTORE_SIGMASK is set then
        clear it and restore the sigmask
    - Hook up sys_pselect6, sys_ppoll, and sys_epoll_pwait.
    
    Signed-off-by: Mikael Pettersson <mikpe@it.uu.se>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
    ---
    
    a b extern void vfp_sync_state(struct thread 
    140140#define TIF_USING_IWMMXT        17 
    141141#define TIF_MEMDIE              18 
    142142#define TIF_FREEZE              19 
     143#define TIF_RESTORE_SIGMASK     20 
    143144 
    144145#define _TIF_SIGPENDING         (1 << TIF_SIGPENDING) 
    145146#define _TIF_NEED_RESCHED       (1 << TIF_NEED_RESCHED) 
    extern void vfp_sync_state(struct thread 
    147148#define _TIF_POLLING_NRFLAG     (1 << TIF_POLLING_NRFLAG) 
    148149#define _TIF_USING_IWMMXT       (1 << TIF_USING_IWMMXT) 
    149150#define _TIF_FREEZE             (1 << TIF_FREEZE) 
     151#define _TIF_RESTORE_SIGMASK    (1 << TIF_RESTORE_SIGMASK) 
    150152 
    151153/* 
    152154 * Change these and you break ASM code in entry-common.S 
  • arch/arm/include/asm/unistd.h

    a b  
    360360#define __NR_readlinkat                 (__NR_SYSCALL_BASE+332) 
    361361#define __NR_fchmodat                   (__NR_SYSCALL_BASE+333) 
    362362#define __NR_faccessat                  (__NR_SYSCALL_BASE+334) 
    363                                         /* 335 for pselect6 */ 
    364                                         /* 336 for ppoll */ 
     363#define __NR_pselect6                   (__NR_SYSCALL_BASE+335) 
     364#define __NR_ppoll                      (__NR_SYSCALL_BASE+336) 
    365365#define __NR_unshare                    (__NR_SYSCALL_BASE+337) 
    366366#define __NR_set_robust_list            (__NR_SYSCALL_BASE+338) 
    367367#define __NR_get_robust_list            (__NR_SYSCALL_BASE+339) 
     
    372372#define __NR_vmsplice                   (__NR_SYSCALL_BASE+343) 
    373373#define __NR_move_pages                 (__NR_SYSCALL_BASE+344) 
    374374#define __NR_getcpu                     (__NR_SYSCALL_BASE+345) 
    375                                         /* 346 for epoll_pwait */ 
     375#define __NR_epoll_pwait                (__NR_SYSCALL_BASE+346) 
    376376#define __NR_kexec_load                 (__NR_SYSCALL_BASE+347) 
    377377#define __NR_utimensat                  (__NR_SYSCALL_BASE+348) 
    378378#define __NR_signalfd                   (__NR_SYSCALL_BASE+349) 
     
    430430#define __ARCH_WANT_SYS_SIGPENDING 
    431431#define __ARCH_WANT_SYS_SIGPROCMASK 
    432432#define __ARCH_WANT_SYS_RT_SIGACTION 
     433#define __ARCH_WANT_SYS_RT_SIGSUSPEND 
    433434 
    434435#if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT) 
    435436#define __ARCH_WANT_SYS_TIME 
  • arch/arm/kernel/calls.S

    a b  
    8181                CALL(sys_ni_syscall)            /* was sys_ssetmask */ 
    8282/* 70 */        CALL(sys_setreuid16) 
    8383                CALL(sys_setregid16) 
    84                 CALL(sys_sigsuspend_wrapper) 
     84                CALL(sys_sigsuspend) 
    8585                CALL(sys_sigpending) 
    8686                CALL(sys_sethostname) 
    8787/* 75 */        CALL(sys_setrlimit) 
     
    188188                CALL(sys_rt_sigpending) 
    189189                CALL(sys_rt_sigtimedwait) 
    190190                CALL(sys_rt_sigqueueinfo) 
    191                 CALL(sys_rt_sigsuspend_wrapper) 
     191                CALL(sys_rt_sigsuspend) 
    192192/* 180 */       CALL(ABI(sys_pread64, sys_oabi_pread64)) 
    193193                CALL(ABI(sys_pwrite64, sys_oabi_pwrite64)) 
    194194                CALL(sys_chown16) 
     
    344344                CALL(sys_readlinkat) 
    345345                CALL(sys_fchmodat) 
    346346                CALL(sys_faccessat) 
    347 /* 335 */       CALL(sys_ni_syscall)            /* eventually pselect6 */ 
    348                 CALL(sys_ni_syscall)            /* eventually ppoll */ 
     347/* 335 */       CALL(sys_pselect6) 
     348                CALL(sys_ppoll) 
    349349                CALL(sys_unshare) 
    350350                CALL(sys_set_robust_list) 
    351351                CALL(sys_get_robust_list) 
     
    355355                CALL(sys_vmsplice) 
    356356                CALL(sys_move_pages) 
    357357/* 345 */       CALL(sys_getcpu) 
    358                 CALL(sys_ni_syscall)            /* eventually epoll_pwait */ 
     358                CALL(sys_epoll_pwait) 
    359359                CALL(sys_kexec_load) 
    360360                CALL(sys_utimensat) 
    361361                CALL(sys_signalfd) 
  • arch/arm/kernel/entry-common.S

    a b sys_clone_wrapper: 
    370370                b       sys_clone 
    371371ENDPROC(sys_clone_wrapper) 
    372372 
    373 sys_sigsuspend_wrapper: 
    374                 add     r3, sp, #S_OFF 
    375                 b       sys_sigsuspend 
    376 ENDPROC(sys_sigsuspend_wrapper) 
    377  
    378 sys_rt_sigsuspend_wrapper: 
    379                 add     r2, sp, #S_OFF 
    380                 b       sys_rt_sigsuspend 
    381 ENDPROC(sys_rt_sigsuspend_wrapper) 
    382  
    383373sys_sigreturn_wrapper: 
    384374                add     r0, sp, #S_OFF 
    385375                b       sys_sigreturn 
  • arch/arm/kernel/signal.c

    a b const unsigned long sigreturn_codes[7] = 
    4747        MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN, 
    4848}; 
    4949 
    50 static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall); 
    51  
    5250/* 
    5351 * atomically swap in the new signal mask, and wait for a signal. 
    5452 */ 
    55 asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask, struct pt_regs *regs) 
     53asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask) 
    5654{ 
    57         sigset_t saveset; 
    58  
    5955        mask &= _BLOCKABLE; 
    6056        spin_lock_irq(&current->sighand->siglock); 
    61         saveset = current->blocked; 
     57        current->saved_sigmask = current->blocked; 
    6258        siginitset(&current->blocked, mask); 
    6359        recalc_sigpending(); 
    6460        spin_unlock_irq(&current->sighand->siglock); 
    65         regs->ARM_r0 = -EINTR; 
    66  
    67         while (1) { 
    68                 current->state = TASK_INTERRUPTIBLE; 
    69                 schedule(); 
    70                 if (do_signal(&saveset, regs, 0)) 
    71                         return regs->ARM_r0; 
    72         } 
    73 } 
    74  
    75 asmlinkage int 
    76 sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs) 
    77 { 
    78         sigset_t saveset, newset; 
    79  
    80         /* XXX: Don't preclude handling different sized sigset_t's. */ 
    81         if (sigsetsize != sizeof(sigset_t)) 
    82                 return -EINVAL; 
    83  
    84         if (copy_from_user(&newset, unewset, sizeof(newset))) 
    85                 return -EFAULT; 
    86         sigdelsetmask(&newset, ~_BLOCKABLE); 
    87  
    88         spin_lock_irq(&current->sighand->siglock); 
    89         saveset = current->blocked; 
    90         current->blocked = newset; 
    91         recalc_sigpending(); 
    92         spin_unlock_irq(&current->sighand->siglock); 
    93         regs->ARM_r0 = -EINTR; 
    9461 
    95         while (1) { 
    96                 current->state = TASK_INTERRUPTIBLE; 
    97                 schedule(); 
    98                 if (do_signal(&saveset, regs, 0)) 
    99                         return regs->ARM_r0; 
    100         } 
     62        current->state = TASK_INTERRUPTIBLE; 
     63        schedule(); 
     64        set_restore_sigmask(); 
     65        return -ERESTARTNOHAND; 
    10166} 
    10267 
    10368asmlinkage int  
    static inline void restart_syscall(struc 
    541506/* 
    542507 * OK, we're invoking a handler 
    543508 */      
    544 static void 
     509static int 
    545510handle_signal(unsigned long sig, struct k_sigaction *ka, 
    546511              siginfo_t *info, sigset_t *oldset, 
    547512              struct pt_regs * regs, int syscall) 
    handle_signal(unsigned long sig, struct  
    592557 
    593558        if (ret != 0) { 
    594559                force_sigsegv(sig, tsk); 
    595                 return; 
     560                return ret; 
    596561        } 
    597562 
    598563        /* 
    handle_signal(unsigned long sig, struct  
    606571        recalc_sigpending(); 
    607572        spin_unlock_irq(&tsk->sighand->siglock); 
    608573 
     574        return 0; 
    609575} 
    610576 
    611577/* 
    handle_signal(unsigned long sig, struct  
    617583 * the kernel can handle, and then we build all the user-level signal handling 
    618584 * stack-frames in one go after that. 
    619585 */ 
    620 static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) 
     586static void do_signal(struct pt_regs *regs, int syscall) 
    621587{ 
    622588        struct k_sigaction ka; 
    623589        siginfo_t info; 
    624590        int signr; 
     591        sigset_t *oldset; 
    625592 
    626593        /* 
    627594         * We want the common case to go fast, which 
    static int do_signal(sigset_t *oldset, s 
    630597         * if so. 
    631598         */ 
    632599        if (!user_mode(regs)) 
    633                 return 0; 
     600                return; 
    634601 
    635602        if (try_to_freeze()) 
    636603                goto no_signal; 
    637604 
    638605        single_step_clear(current); 
    639606 
     607        if (test_thread_flag(TIF_RESTORE_SIGMASK)) 
     608                oldset = &current->saved_sigmask; 
     609        else 
     610                oldset = &current->blocked; 
     611 
    640612        signr = get_signal_to_deliver(&info, &ka, regs, NULL); 
    641613        if (signr > 0) { 
    642                 handle_signal(signr, &ka, &info, oldset, regs, syscall); 
     614                if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 0) { 
     615                        /* 
     616                         * A signal was successfully delivered; the saved 
     617                         * sigmask will have been stored in the signal frame, 
     618                         * and will be restored by sigreturn, so we can simply 
     619                         * clear the TIF_RESTORE_SIGMASK flag. 
     620                         */ 
     621                        if (test_thread_flag(TIF_RESTORE_SIGMASK)) 
     622                                clear_thread_flag(TIF_RESTORE_SIGMASK); 
     623                } 
    643624                single_step_set(current); 
    644                 return 1; 
     625                return; 
    645626        } 
    646627 
    647628 no_signal: 
    static int do_signal(sigset_t *oldset, s 
    693674                    regs->ARM_r0 == -ERESTARTNOINTR) { 
    694675                        restart_syscall(regs); 
    695676                } 
     677 
     678                /* If there's no signal to deliver, we just put the saved sigmask 
     679                 * back. 
     680                 */ 
     681                if (test_thread_flag(TIF_RESTORE_SIGMASK)) { 
     682                        clear_thread_flag(TIF_RESTORE_SIGMASK); 
     683                        sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL); 
     684                } 
    696685        } 
    697686        single_step_set(current); 
    698         return 0; 
    699687} 
    700688 
    701689asmlinkage void 
    702690do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) 
    703691{ 
    704692        if (thread_flags & _TIF_SIGPENDING) 
    705                 do_signal(&current->blocked, regs, syscall); 
     693                do_signal(regs, syscall); 
    706694} 
Note: See TracBrowser for help on using the repository browser.