7852f0afdb9afac7de16541f1e52e55bf4721448
[openembedded.git] /
1 From 8a7643b09856f4f661403dcedbe0455b3cbeeea9 Mon Sep 17 00:00:00 2001
2 From: Steven Newbury <s_j_newbury@yahoo.co.uk>
3 Date: Fri, 22 May 2009 14:25:40 +0200
4 Subject: [PATCH] implement TIF_RESTORE_SIGMASK support and enable the related
5  syscalls:
6
7 pselect6
8 ppoll
9 epoll_pwait
10
11 Based on http://www.spinics.net/lists/arm-kernel/msg38114.html
12 ---
13  arch/arm/include/asm/thread_info.h |    2 +
14  arch/arm/include/asm/unistd.h      |    7 ++-
15  arch/arm/kernel/calls.S            |    6 +-
16  arch/arm/kernel/signal.c           |   90 +++++++++++++++---------------------
17  4 files changed, 46 insertions(+), 59 deletions(-)
18
19 diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
20 index 4f88482..2cf0917 100644
21 --- a/arch/arm/include/asm/thread_info.h
22 +++ b/arch/arm/include/asm/thread_info.h
23 @@ -136,6 +136,7 @@ extern void vfp_sync_state(struct thread_info *thread);
24  #define TIF_SIGPENDING         0
25  #define TIF_NEED_RESCHED       1
26  #define TIF_SYSCALL_TRACE      8
27 +#define TIF_RESTORE_SIGMASK    9       /* restore signal mask in do_signal */
28  #define TIF_POLLING_NRFLAG     16
29  #define TIF_USING_IWMMXT       17
30  #define TIF_MEMDIE             18
31 @@ -144,6 +145,7 @@ extern void vfp_sync_state(struct thread_info *thread);
32  #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
33  #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
34  #define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
35 +#define _TIF_RESTORE_SIGMASK   (1 << TIF_RESTORE_SIGMASK)
36  #define _TIF_POLLING_NRFLAG    (1 << TIF_POLLING_NRFLAG)
37  #define _TIF_USING_IWMMXT      (1 << TIF_USING_IWMMXT)
38  #define _TIF_FREEZE            (1 << TIF_FREEZE)
39 diff --git a/arch/arm/include/asm/unistd.h b/arch/arm/include/asm/unistd.h
40 index 94cc58e..cd1eaa0 100644
41 --- a/arch/arm/include/asm/unistd.h
42 +++ b/arch/arm/include/asm/unistd.h
43 @@ -360,8 +360,8 @@
44  #define __NR_readlinkat                        (__NR_SYSCALL_BASE+332)
45  #define __NR_fchmodat                  (__NR_SYSCALL_BASE+333)
46  #define __NR_faccessat                 (__NR_SYSCALL_BASE+334)
47 -                                       /* 335 for pselect6 */
48 -                                       /* 336 for ppoll */
49 +#define __NR_pselect6                  (__NR_SYSCALL_BASE+335)
50 +#define __NR_ppoll                     (__NR_SYSCALL_BASE+336)
51  #define __NR_unshare                   (__NR_SYSCALL_BASE+337)
52  #define __NR_set_robust_list           (__NR_SYSCALL_BASE+338)
53  #define __NR_get_robust_list           (__NR_SYSCALL_BASE+339)
54 @@ -372,7 +372,7 @@
55  #define __NR_vmsplice                  (__NR_SYSCALL_BASE+343)
56  #define __NR_move_pages                        (__NR_SYSCALL_BASE+344)
57  #define __NR_getcpu                    (__NR_SYSCALL_BASE+345)
58 -                                       /* 346 for epoll_pwait */
59 +#define __NR_epoll_pwait               (__NR_SYSCALL_BASE+346)
60  #define __NR_kexec_load                        (__NR_SYSCALL_BASE+347)
61  #define __NR_utimensat                 (__NR_SYSCALL_BASE+348)
62  #define __NR_signalfd                  (__NR_SYSCALL_BASE+349)
63 @@ -430,6 +430,7 @@
64  #define __ARCH_WANT_SYS_SIGPENDING
65  #define __ARCH_WANT_SYS_SIGPROCMASK
66  #define __ARCH_WANT_SYS_RT_SIGACTION
67 +#define __ARCH_WANT_SYS_RT_SIGSUSPEND
68  
69  #if !defined(CONFIG_AEABI) || defined(CONFIG_OABI_COMPAT)
70  #define __ARCH_WANT_SYS_TIME
71 diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
72 index 1680e9e..534000d 100644
73 --- a/arch/arm/kernel/calls.S
74 +++ b/arch/arm/kernel/calls.S
75 @@ -344,8 +344,8 @@
76                 CALL(sys_readlinkat)
77                 CALL(sys_fchmodat)
78                 CALL(sys_faccessat)
79 -/* 335 */      CALL(sys_ni_syscall)            /* eventually pselect6 */
80 -               CALL(sys_ni_syscall)            /* eventually ppoll */
81 +/* 335 */      CALL(sys_pselect6)
82 +               CALL(sys_ppoll)
83                 CALL(sys_unshare)
84                 CALL(sys_set_robust_list)
85                 CALL(sys_get_robust_list)
86 @@ -355,7 +355,7 @@
87                 CALL(sys_vmsplice)
88                 CALL(sys_move_pages)
89  /* 345 */      CALL(sys_getcpu)
90 -               CALL(sys_ni_syscall)            /* eventually epoll_pwait */
91 +               CALL(sys_epoll_pwait)
92                 CALL(sys_kexec_load)
93                 CALL(sys_utimensat)
94                 CALL(sys_signalfd)
95 diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
96 index 80b8b5c..7645048 100644
97 --- a/arch/arm/kernel/signal.c
98 +++ b/arch/arm/kernel/signal.c
99 @@ -47,57 +47,23 @@ const unsigned long sigreturn_codes[7] = {
100         MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
101  };
102  
103 -static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall);
104 +static void do_signal(struct pt_regs * regs, int syscall);
105  
106  /*
107   * atomically swap in the new signal mask, and wait for a signal.
108   */
109 -asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask, struct pt_regs *regs)
110 +asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
111  {
112 -       sigset_t saveset;
113 -
114         mask &= _BLOCKABLE;
115         spin_lock_irq(&current->sighand->siglock);
116 -       saveset = current->blocked;
117 +       current->saved_sigmask = current->blocked;
118         siginitset(&current->blocked, mask);
119         recalc_sigpending();
120         spin_unlock_irq(&current->sighand->siglock);
121 -       regs->ARM_r0 = -EINTR;
122 -
123 -       while (1) {
124 -               current->state = TASK_INTERRUPTIBLE;
125 -               schedule();
126 -               if (do_signal(&saveset, regs, 0))
127 -                       return regs->ARM_r0;
128 -       }
129 -}
130 -
131 -asmlinkage int
132 -sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
133 -{
134 -       sigset_t saveset, newset;
135 -
136 -       /* XXX: Don't preclude handling different sized sigset_t's. */
137 -       if (sigsetsize != sizeof(sigset_t))
138 -               return -EINVAL;
139 -
140 -       if (copy_from_user(&newset, unewset, sizeof(newset)))
141 -               return -EFAULT;
142 -       sigdelsetmask(&newset, ~_BLOCKABLE);
143 -
144 -       spin_lock_irq(&current->sighand->siglock);
145 -       saveset = current->blocked;
146 -       current->blocked = newset;
147 -       recalc_sigpending();
148 -       spin_unlock_irq(&current->sighand->siglock);
149 -       regs->ARM_r0 = -EINTR;
150 -
151 -       while (1) {
152 -               current->state = TASK_INTERRUPTIBLE;
153 -               schedule();
154 -               if (do_signal(&saveset, regs, 0))
155 -                       return regs->ARM_r0;
156 -       }
157 +       current->state = TASK_INTERRUPTIBLE;
158 +       schedule();
159 +       set_thread_flag(TIF_RESTORE_SIGMASK);
160 +       return -ERESTARTNOHAND;
161  }
162  
163  asmlinkage int 
164 @@ -290,7 +256,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
165  
166  badframe:
167         force_sig(SIGSEGV, current);
168 -       return 0;
169 +       return -EFAULT;
170  }
171  
172  asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
173 @@ -325,7 +291,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
174  
175  badframe:
176         force_sig(SIGSEGV, current);
177 -       return 0;
178 +       return -EFAULT;
179  }
180  
181  static int
182 @@ -541,7 +507,7 @@ static inline void restart_syscall(struct pt_regs *regs)
183  /*
184   * OK, we're invoking a handler
185   */    
186 -static void
187 +static int
188  handle_signal(unsigned long sig, struct k_sigaction *ka,
189               siginfo_t *info, sigset_t *oldset,
190               struct pt_regs * regs, int syscall)
191 @@ -592,7 +558,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
192  
193         if (ret != 0) {
194                 force_sigsegv(sig, tsk);
195 -               return;
196 +               return ret;
197         }
198  
199         /*
200 @@ -606,6 +572,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
201         recalc_sigpending();
202         spin_unlock_irq(&tsk->sighand->siglock);
203  
204 +       return ret;
205  }
206  
207  /*
208 @@ -617,11 +584,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
209   * the kernel can handle, and then we build all the user-level signal handling
210   * stack-frames in one go after that.
211   */
212 -static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
213 +static void do_signal(struct pt_regs *regs, int syscall)
214  {
215         struct k_sigaction ka;
216         siginfo_t info;
217         int signr;
218 +       sigset_t *oldset;
219  
220         /*
221          * We want the common case to go fast, which
222 @@ -630,18 +598,29 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
223          * if so.
224          */
225         if (!user_mode(regs))
226 -               return 0;
227 +               return;
228  
229         if (try_to_freeze())
230                 goto no_signal;
231  
232         single_step_clear(current);
233  
234 +       if (test_thread_flag(TIF_RESTORE_SIGMASK))
235 +               oldset = &current->saved_sigmask;
236 +       else
237 +               oldset = &current->blocked;
238 +
239         signr = get_signal_to_deliver(&info, &ka, regs, NULL);
240         if (signr > 0) {
241 -               handle_signal(signr, &ka, &info, oldset, regs, syscall);
242 +               if (handle_signal(signr, &ka, &info, oldset, regs, syscall) == 0) {
243 +                       /* a signal was successfully delivered; the saved
244 +                        * sigmask will have been stored in the signal frame,
245 +                        * and will be restored by sigreturn, so we can simply
246 +                        * clear the TIF_RESTORE_SIGMASK flag */
247 +                       clear_thread_flag(TIF_RESTORE_SIGMASK);
248 +               }
249                 single_step_set(current);
250 -               return 1;
251 +               return;
252         }
253  
254   no_signal:
255 @@ -665,7 +644,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
256                                 usp = (u32 __user *)regs->ARM_sp;
257  
258                                 /*
259 -                                * Either we supports OABI only, or we have
260 +                                * Either we support OABI only, or we have
261                                  * EABI with the OABI compat layer enabled.
262                                  * In the later case we don't know if user
263                                  * space is EABI or not, and if not we must
264 @@ -695,12 +674,17 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
265                 }
266         }
267         single_step_set(current);
268 -       return 0;
269 +        /* if there's no signal to deliver, we just put the saved sigmask
270 +           back. */
271 +               if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
272 +                       clear_thread_flag(TIF_RESTORE_SIGMASK);
273 +                       sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
274 +               }
275  }
276  
277  asmlinkage void
278  do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
279  {
280 -       if (thread_flags & _TIF_SIGPENDING)
281 -               do_signal(&current->blocked, regs, syscall);
282 +       if (thread_flags & (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK))
283 +               do_signal(regs, syscall);
284  }
285 -- 
286 1.6.2.4
287