aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/signal32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/signal32.c')
-rw-r--r--arch/mips/kernel/signal32.c68
1 files changed, 41 insertions, 27 deletions
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 8a8b8dd90417..c07019575214 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -106,8 +106,6 @@ typedef struct compat_siginfo {
106 106
107#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 107#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
108 108
109extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);
110
111/* 32-bit compatibility types */ 109/* 32-bit compatibility types */
112 110
113#define _NSIG_BPW32 32 111#define _NSIG_BPW32 32
@@ -198,7 +196,7 @@ __attribute_used__ noinline static int
198_sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) 196_sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
199{ 197{
200 compat_sigset_t *uset; 198 compat_sigset_t *uset;
201 sigset_t newset, saveset; 199 sigset_t newset;
202 200
203 uset = (compat_sigset_t *) regs.regs[4]; 201 uset = (compat_sigset_t *) regs.regs[4];
204 if (get_sigset(&newset, uset)) 202 if (get_sigset(&newset, uset))
@@ -206,19 +204,15 @@ _sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
206 sigdelsetmask(&newset, ~_BLOCKABLE); 204 sigdelsetmask(&newset, ~_BLOCKABLE);
207 205
208 spin_lock_irq(&current->sighand->siglock); 206 spin_lock_irq(&current->sighand->siglock);
209 saveset = current->blocked; 207 current->saved_sigmask = current->blocked;
210 current->blocked = newset; 208 current->blocked = newset;
211 recalc_sigpending(); 209 recalc_sigpending();
212 spin_unlock_irq(&current->sighand->siglock); 210 spin_unlock_irq(&current->sighand->siglock);
213 211
214 regs.regs[2] = EINTR; 212 current->state = TASK_INTERRUPTIBLE;
215 regs.regs[7] = 1; 213 schedule();
216 while (1) { 214 set_thread_flag(TIF_RESTORE_SIGMASK);
217 current->state = TASK_INTERRUPTIBLE; 215 return -ERESTARTNOHAND;
218 schedule();
219 if (do_signal32(&saveset, &regs))
220 return -EINTR;
221 }
222} 216}
223 217
224save_static_function(sys32_rt_sigsuspend); 218save_static_function(sys32_rt_sigsuspend);
@@ -226,7 +220,7 @@ __attribute_used__ noinline static int
226_sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) 220_sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
227{ 221{
228 compat_sigset_t *uset; 222 compat_sigset_t *uset;
229 sigset_t newset, saveset; 223 sigset_t newset;
230 size_t sigsetsize; 224 size_t sigsetsize;
231 225
232 /* XXX Don't preclude handling different sized sigset_t's. */ 226 /* XXX Don't preclude handling different sized sigset_t's. */
@@ -240,19 +234,15 @@ _sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
240 sigdelsetmask(&newset, ~_BLOCKABLE); 234 sigdelsetmask(&newset, ~_BLOCKABLE);
241 235
242 spin_lock_irq(&current->sighand->siglock); 236 spin_lock_irq(&current->sighand->siglock);
243 saveset = current->blocked; 237 current->saved_sigmask = current->blocked;
244 current->blocked = newset; 238 current->blocked = newset;
245 recalc_sigpending(); 239 recalc_sigpending();
246 spin_unlock_irq(&current->sighand->siglock); 240 spin_unlock_irq(&current->sighand->siglock);
247 241
248 regs.regs[2] = EINTR; 242 current->state = TASK_INTERRUPTIBLE;
249 regs.regs[7] = 1; 243 schedule();
250 while (1) { 244 set_thread_flag(TIF_RESTORE_SIGMASK);
251 current->state = TASK_INTERRUPTIBLE; 245 return -ERESTARTNOHAND;
252 schedule();
253 if (do_signal32(&saveset, &regs))
254 return -EINTR;
255 }
256} 246}
257 247
258asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act, 248asmlinkage int sys32_sigaction(int sig, const struct sigaction32 *act,
@@ -783,7 +773,7 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info,
783 regs->regs[2] = EINTR; 773 regs->regs[2] = EINTR;
784 break; 774 break;
785 case ERESTARTSYS: 775 case ERESTARTSYS:
786 if(!(ka->sa.sa_flags & SA_RESTART)) { 776 if (!(ka->sa.sa_flags & SA_RESTART)) {
787 regs->regs[2] = EINTR; 777 regs->regs[2] = EINTR;
788 break; 778 break;
789 } 779 }
@@ -810,9 +800,10 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info,
810 return ret; 800 return ret;
811} 801}
812 802
813int do_signal32(sigset_t *oldset, struct pt_regs *regs) 803int do_signal32(struct pt_regs *regs)
814{ 804{
815 struct k_sigaction ka; 805 struct k_sigaction ka;
806 sigset_t *oldset;
816 siginfo_t info; 807 siginfo_t info;
817 int signr; 808 int signr;
818 809
@@ -827,12 +818,25 @@ int do_signal32(sigset_t *oldset, struct pt_regs *regs)
827 if (try_to_freeze()) 818 if (try_to_freeze())
828 goto no_signal; 819 goto no_signal;
829 820
830 if (!oldset) 821 if (test_thread_flag(TIF_RESTORE_SIGMASK))
822 oldset = &current->saved_sigmask;
823 else
831 oldset = &current->blocked; 824 oldset = &current->blocked;
832 825
833 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 826 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
834 if (signr > 0) 827 if (signr > 0) {
835 return handle_signal(signr, &info, &ka, oldset, regs); 828 /* Whee! Actually deliver the signal. */
829 if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
830 /*
831 * A signal was successfully delivered; the saved
832 * sigmask will have been stored in the signal frame,
833 * and will be restored by sigreturn, so we can simply
834 * clear the TIF_RESTORE_SIGMASK flag.
835 */
836 if (test_thread_flag(TIF_RESTORE_SIGMASK))
837 clear_thread_flag(TIF_RESTORE_SIGMASK);
838 }
839 }
836 840
837no_signal: 841no_signal:
838 /* 842 /*
@@ -853,6 +857,16 @@ no_signal:
853 regs->cp0_epc -= 4; 857 regs->cp0_epc -= 4;
854 } 858 }
855 } 859 }
860
861 /*
862 * If there's no signal to deliver, we just put the saved sigmask
863 * back
864 */
865 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
866 clear_thread_flag(TIF_RESTORE_SIGMASK);
867 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
868 }
869
856 return 0; 870 return 0;
857} 871}
858 872