diff options
-rw-r--r-- | arch/um/kernel/signal_kern.c | 79 | ||||
-rw-r--r-- | include/asm-um/thread_info.h | 13 |
2 files changed, 43 insertions, 49 deletions
diff --git a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c index 7b0e0e81c161..7a54708db50c 100644 --- a/arch/um/kernel/signal_kern.c +++ b/arch/um/kernel/signal_kern.c | |||
@@ -99,31 +99,46 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr, | |||
99 | return err; | 99 | return err; |
100 | } | 100 | } |
101 | 101 | ||
102 | static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset) | 102 | static int kern_do_signal(struct pt_regs *regs) |
103 | { | 103 | { |
104 | struct k_sigaction ka_copy; | 104 | struct k_sigaction ka_copy; |
105 | siginfo_t info; | 105 | siginfo_t info; |
106 | sigset_t *oldset; | ||
106 | int sig, handled_sig = 0; | 107 | int sig, handled_sig = 0; |
107 | 108 | ||
109 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
110 | oldset = ¤t->saved_sigmask; | ||
111 | else | ||
112 | oldset = ¤t->blocked; | ||
113 | |||
108 | while((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0){ | 114 | while((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0){ |
109 | handled_sig = 1; | 115 | handled_sig = 1; |
110 | /* Whee! Actually deliver the signal. */ | 116 | /* Whee! Actually deliver the signal. */ |
111 | if(!handle_signal(regs, sig, &ka_copy, &info, oldset)) | 117 | if(!handle_signal(regs, sig, &ka_copy, &info, oldset)){ |
118 | /* a signal was successfully delivered; the saved | ||
119 | * sigmask will have been stored in the signal frame, | ||
120 | * and will be restored by sigreturn, so we can simply | ||
121 | * clear the TIF_RESTORE_SIGMASK flag */ | ||
122 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
123 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
112 | break; | 124 | break; |
125 | } | ||
113 | } | 126 | } |
114 | 127 | ||
115 | /* Did we come from a system call? */ | 128 | /* Did we come from a system call? */ |
116 | if(!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)){ | 129 | if(!handled_sig && (PT_REGS_SYSCALL_NR(regs) >= 0)){ |
117 | /* Restart the system call - no handlers present */ | 130 | /* Restart the system call - no handlers present */ |
118 | if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND || | 131 | switch(PT_REGS_SYSCALL_RET(regs)){ |
119 | PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS || | 132 | case -ERESTARTNOHAND: |
120 | PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOINTR){ | 133 | case -ERESTARTSYS: |
134 | case -ERESTARTNOINTR: | ||
121 | PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); | 135 | PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); |
122 | PT_REGS_RESTART_SYSCALL(regs); | 136 | PT_REGS_RESTART_SYSCALL(regs); |
123 | } | 137 | break; |
124 | else if(PT_REGS_SYSCALL_RET(regs) == -ERESTART_RESTARTBLOCK){ | 138 | case -ERESTART_RESTARTBLOCK: |
125 | PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall; | 139 | PT_REGS_SYSCALL_RET(regs) = __NR_restart_syscall; |
126 | PT_REGS_RESTART_SYSCALL(regs); | 140 | PT_REGS_RESTART_SYSCALL(regs); |
141 | break; | ||
127 | } | 142 | } |
128 | } | 143 | } |
129 | 144 | ||
@@ -137,12 +152,19 @@ static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
137 | if(current->ptrace & PT_DTRACE) | 152 | if(current->ptrace & PT_DTRACE) |
138 | current->thread.singlestep_syscall = | 153 | current->thread.singlestep_syscall = |
139 | is_syscall(PT_REGS_IP(¤t->thread.regs)); | 154 | is_syscall(PT_REGS_IP(¤t->thread.regs)); |
155 | |||
156 | /* if there's no signal to deliver, we just put the saved sigmask | ||
157 | * back */ | ||
158 | if (!handled_sig && test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
159 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
160 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
161 | } | ||
140 | return(handled_sig); | 162 | return(handled_sig); |
141 | } | 163 | } |
142 | 164 | ||
143 | int do_signal(void) | 165 | int do_signal(void) |
144 | { | 166 | { |
145 | return(kern_do_signal(¤t->thread.regs, ¤t->blocked)); | 167 | return(kern_do_signal(¤t->thread.regs)); |
146 | } | 168 | } |
147 | 169 | ||
148 | /* | 170 | /* |
@@ -150,27 +172,22 @@ int do_signal(void) | |||
150 | */ | 172 | */ |
151 | long sys_sigsuspend(int history0, int history1, old_sigset_t mask) | 173 | long sys_sigsuspend(int history0, int history1, old_sigset_t mask) |
152 | { | 174 | { |
153 | sigset_t saveset; | ||
154 | |||
155 | mask &= _BLOCKABLE; | 175 | mask &= _BLOCKABLE; |
156 | spin_lock_irq(¤t->sighand->siglock); | 176 | spin_lock_irq(¤t->sighand->siglock); |
157 | saveset = current->blocked; | 177 | current->saved_sigmask = current->blocked; |
158 | siginitset(¤t->blocked, mask); | 178 | siginitset(¤t->blocked, mask); |
159 | recalc_sigpending(); | 179 | recalc_sigpending(); |
160 | spin_unlock_irq(¤t->sighand->siglock); | 180 | spin_unlock_irq(¤t->sighand->siglock); |
161 | 181 | ||
162 | PT_REGS_SYSCALL_RET(¤t->thread.regs) = -EINTR; | 182 | current->state = TASK_INTERRUPTIBLE; |
163 | while (1) { | 183 | schedule(); |
164 | current->state = TASK_INTERRUPTIBLE; | 184 | set_thread_flag(TIF_RESTORE_SIGMASK); |
165 | schedule(); | 185 | return -ERESTARTNOHAND; |
166 | if(kern_do_signal(¤t->thread.regs, &saveset)) | ||
167 | return(-EINTR); | ||
168 | } | ||
169 | } | 186 | } |
170 | 187 | ||
171 | long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) | 188 | long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) |
172 | { | 189 | { |
173 | sigset_t saveset, newset; | 190 | sigset_t newset; |
174 | 191 | ||
175 | /* XXX: Don't preclude handling different sized sigset_t's. */ | 192 | /* XXX: Don't preclude handling different sized sigset_t's. */ |
176 | if (sigsetsize != sizeof(sigset_t)) | 193 | if (sigsetsize != sizeof(sigset_t)) |
@@ -181,32 +198,18 @@ long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) | |||
181 | sigdelsetmask(&newset, ~_BLOCKABLE); | 198 | sigdelsetmask(&newset, ~_BLOCKABLE); |
182 | 199 | ||
183 | spin_lock_irq(¤t->sighand->siglock); | 200 | spin_lock_irq(¤t->sighand->siglock); |
184 | saveset = current->blocked; | 201 | current->saved_sigmask = current->blocked; |
185 | current->blocked = newset; | 202 | current->blocked = newset; |
186 | recalc_sigpending(); | 203 | recalc_sigpending(); |
187 | spin_unlock_irq(¤t->sighand->siglock); | 204 | spin_unlock_irq(¤t->sighand->siglock); |
188 | 205 | ||
189 | PT_REGS_SYSCALL_RET(¤t->thread.regs) = -EINTR; | 206 | current->state = TASK_INTERRUPTIBLE; |
190 | while (1) { | 207 | schedule(); |
191 | current->state = TASK_INTERRUPTIBLE; | 208 | set_thread_flag(TIF_RESTORE_SIGMASK); |
192 | schedule(); | 209 | return -ERESTARTNOHAND; |
193 | if (kern_do_signal(¤t->thread.regs, &saveset)) | ||
194 | return(-EINTR); | ||
195 | } | ||
196 | } | 210 | } |
197 | 211 | ||
198 | long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) | 212 | long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss) |
199 | { | 213 | { |
200 | return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); | 214 | return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); |
201 | } | 215 | } |
202 | |||
203 | /* | ||
204 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
205 | * Emacs will notice this stuff at the end of the file and automatically | ||
206 | * adjust the settings for this buffer only. This must remain at the end | ||
207 | * of the file. | ||
208 | * --------------------------------------------------------------------------- | ||
209 | * Local variables: | ||
210 | * c-file-style: "linux" | ||
211 | * End: | ||
212 | */ | ||
diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h index 705c71972c32..17b6b07c4332 100644 --- a/include/asm-um/thread_info.h +++ b/include/asm-um/thread_info.h | |||
@@ -69,6 +69,7 @@ static inline struct thread_info *current_thread_info(void) | |||
69 | #define TIF_RESTART_BLOCK 4 | 69 | #define TIF_RESTART_BLOCK 4 |
70 | #define TIF_MEMDIE 5 | 70 | #define TIF_MEMDIE 5 |
71 | #define TIF_SYSCALL_AUDIT 6 | 71 | #define TIF_SYSCALL_AUDIT 6 |
72 | #define TIF_RESTORE_SIGMASK 7 | ||
72 | 73 | ||
73 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) | 74 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) |
74 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) | 75 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) |
@@ -76,16 +77,6 @@ static inline struct thread_info *current_thread_info(void) | |||
76 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) | 77 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) |
77 | #define _TIF_MEMDIE (1 << TIF_MEMDIE) | 78 | #define _TIF_MEMDIE (1 << TIF_MEMDIE) |
78 | #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) | 79 | #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) |
80 | #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) | ||
79 | 81 | ||
80 | #endif | 82 | #endif |
81 | |||
82 | /* | ||
83 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
84 | * Emacs will notice this stuff at the end of the file and automatically | ||
85 | * adjust the settings for this buffer only. This must remain at the end | ||
86 | * of the file. | ||
87 | * --------------------------------------------------------------------------- | ||
88 | * Local variables: | ||
89 | * c-file-style: "linux" | ||
90 | * End: | ||
91 | */ | ||