x86: do_signal: simplify the TS_RESTORE_SIGMASK logic
PATCH 1/1 x86: do_signal: simplify the TS_RESTORE_SIGMASK logic
1. do_signal() looks at TS_RESTORE_SIGMASK and calculates the mask which should be stored in the signal frame, then it passes "oldset" to the callees, down to setup_rt_frame().
This is ugly, setup_rt_frame() can do this itself and nobody else needs this sigset_t. Move this code into setup_rt_frame.
2. do_signal() also clears TS_RESTORE_SIGMASK if handle_signal() succeeds.
We can move this to setup_rt_frame() as well, this avoids the unnecessary checks and makes the logic more clear.
3. use set_current_blocked() instead of sigprocmask(SIG_SETMASK), sigprocmask() should be avoided.
---
arch/x86/kernel/signal.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-)
arch/x86/kernel/signal.c renamed from arch/x86/kernel/signal.c~2_restore_sigmask +10 -19
@@ -653,11 +653,15 @@ int ia32_setup_frame(int sig, struct k_sstatic int setup_rt_frame (int sig,struct k_sigaction *ka,siginfo_t *info, -sigset_t *set,struct pt_regs *regs) +struct pt_regs *regs) {int usig =signr_convert (sig); +sigset_t *set = ¤t->blocked;int ret; +if (current_thread_info ()->status &TS_RESTORE_SIGMASK ) + set = ¤t->saved_sigmask; +/* Set up the stack frame */ if (is_ia32) {if (ka->sa.sa_flags &SA_SIGINFO )
@@ -672,12 +676,13 @@ setup_rt_frame(int sig, struct k_sigactireturn -EFAULT ; } +current_thread_info ()->status &= ~TS_RESTORE_SIGMASK ;return ret; }static int handle_signal (unsigned long sig,siginfo_t *info,struct k_sigaction *ka, -sigset_t *oldset,struct pt_regs *regs) +struct pt_regs *regs) {sigset_t blocked;int ret;
@@ -712,7 +717,7 @@ handle_signal(unsigned long sig, siginfo likely(test_and_clear_thread_flag(TIF_FORCED_TF))) regs->flags &= ~X86_EFLAGS_TF; - ret =setup_rt_frame (sig, ka, info, oldset, regs); + ret =setup_rt_frame (sig, ka, info, regs);if (ret)return ret;
@@ -758,7 +763,6 @@ static void do_signal(struct pt_regs *restruct k_sigaction ka;siginfo_t info;int signr; -sigset_t *oldset;/* * We want the common case to go fast, which is why we may in certain
@@ -770,23 +774,10 @@ static void do_signal(struct pt_regs *reif (!user_mode (regs))return ; -if (current_thread_info ()->status &TS_RESTORE_SIGMASK ) - oldset = ¤t->saved_sigmask; -else - oldset = ¤t->blocked; - signr =get_signal_to_deliver (&info, &ka, regs,NULL );if (signr >0 ) {/* Whee! Actually deliver the signal. */ -if (handle_signal (signr, &info, &ka, 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 TS_RESTORE_SIGMASK flag. -*/ -current_thread_info ()->status &= ~TS_RESTORE_SIGMASK ; - } +handle_signal (signr, &info, &ka, regs);return ; }
@@ -814,7 +805,7 @@ static void do_signal(struct pt_regs *re*/ if (current_thread_info ()->status &TS_RESTORE_SIGMASK ) {current_thread_info ()->status &= ~TS_RESTORE_SIGMASK ; -sigprocmask (SIG_SETMASK , ¤t->saved_sigmask,NULL ); +set_current_blocked (¤t->saved_sigmask); } }
arch/x86/kernel/signal.c setup_rt_frame(int sig, struct k_sigacti · line 680
Quoted 9 lines · Oleg Nesterov
2.
do_signal()also clearsTS_RESTORE_SIGMASKifhandle_signal()succeeds.We can move this to
setup_rt_frame()as well, this avoids the unnecessary checks and makes the logic more clear.arch/x86/kernel/signal.c renamed from arch/x86/kernel/signal.c~2_restore_sigmask +1
-0+current_thread_info ()->status &= ~TS_RESTORE_SIGMASK ;return ret;
This is broken. If setup_rt_frame() fails, you don't want to do that.
Quoted 6 lines · Al Viro
Quoted 3 lines · Oleg Nesterov
2.
do_signal()also clearsTS_RESTORE_SIGMASKifhandle_signal()succeeds.
Quoted 8 lines
arch/x86/kernel/signal.c setup_rt_frame(int sig, struct k_sigacti · line 680
Quoted 6 lines
We can move this to
setup_rt_frame()as well, this avoids the unnecessary checks and makes the logic more clear.arch/x86/kernel/signal.c renamed from arch/x86/kernel/signal.c~2_restore_sigmask +1
-0+current_thread_info ()->status &= ~TS_RESTORE_SIGMASK ;return ret;This is broken.
You know, I was also going to change this "return ret", "return 0" looks more clear to me. But then I should have renamed "ret", and I decided to leave it alone.
Quoted 1 line
If
setup_rt_frame()fails, you don't want to do that.
Sure. Please look at the code, it does
if (ret) {
force_sigsegv(sig, current);
return -EFAULT;
}
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
return ret;We clear TS_RESTORE_SIGMASK only if we return 0.
Oleg.
Quoted 7 lines · On Sun, 10 Jul 2011 20:22:03 +0200 Oleg Nesterov <[email protected]> wrote:
1.
do_signal()looks atTS_RESTORE_SIGMASKand calculates the mask which should be stored in the signal frame, then it passes "oldset" to the callees, down tosetup_rt_frame().This is ugly,
setup_rt_frame()can do this itself and nobody else needs thissigset_t. Move this code intosetup_rt_frame.
Quoted 8 lines
2.
do_signal()also clearsTS_RESTORE_SIGMASKifhandle_signal()succeeds.We can move this to
setup_rt_frame()as well, this avoids the unnecessary checks and makes the logic more clear.3. use
set_current_blocked()instead ofsigprocmask(SIG_SETMASK),sigprocmask()should be avoided.
Could you please mention commit e6fa16ab "signal: sigprocmask() should do retarget_shared_pending()", since it's not immediately obvious in this changelog why sigprocmask() should be avoided.
Quoted 1 line
Signed-off-by Oleg Nesterov <[email protected]>
FWIW,
Signature · 1 line
Matt Fleming, Intel Open Source Technology Center
Quoted 17 lines · Matt Fleming
Quoted 13 lines · On Sun, 10 Jul 2011 20:22:03 +0200 Oleg Nesterov <[email protected]> wrote:
1.
do_signal()looks atTS_RESTORE_SIGMASKand calculates the mask which should be stored in the signal frame, then it passes "oldset" to the callees, down tosetup_rt_frame().This is ugly,
setup_rt_frame()can do this itself and nobody else needs thissigset_t. Move this code intosetup_rt_frame.2.
do_signal()also clearsTS_RESTORE_SIGMASKifhandle_signal()succeeds.We can move this to
setup_rt_frame()as well, this avoids the unnecessary checks and makes the logic more clear.
Quoted 6 lines
Quoted 2 lines
3. use
set_current_blocked()instead ofsigprocmask(SIG_SETMASK),sigprocmask()should be avoided.Could you please mention commit
e6fa16ab"signal:sigprocmask()should doretarget_shared_pending()", since it's not immediately obvious in this changelog whysigprocmask()should be avoided.
Well, sigprocmask(SIG_SETMASK) is fine from the correctness pov, it calls set_current_blocked().
sigprocmask() should be avoided because it is strange interface. It has numeruos callers, but in fact almost all of them could use set_current_blocked() (ignoring sys_rt_sigprocmask).
Linus suggested to simply kill sigprocmask(). I am not sure, but at least it shouldn't be abused and its last argument is confusing.
Quoted 1 line
Reviewed-by Matt Fleming <[email protected]>
Thanks for looking!
Oleg.
[tip:x86/signal] x86, do_signal: Simplify the TS_RESTORE_SIGMASK logic
In reply to Oleg NesterovCommit-ID: 9b429620740945363b746414e8b9a84b8119914c Gitweb: http://git.kernel.org/tip/9b429620740945363b746414e8b9a84b8119914c Author: Oleg Nesterov <[email protected]> AuthorDate: Sun, 10 Jul 2011 20:22:03 +0200 Committer: H. Peter Anvin <[email protected]> CommitDate: Thu, 14 Jul 2011 21:22:11 -0700
x86, do_signal: Simplify the TS_RESTORE_SIGMASK logic
1. do_signal() looks at TS_RESTORE_SIGMASK and calculates the mask which should be stored in the signal frame, then it passes "oldset" to the callees, down to setup_rt_frame().
This is ugly, setup_rt_frame() can do this itself and nobody else needs this sigset_t. Move this code into setup_rt_frame.
2. do_signal() also clears TS_RESTORE_SIGMASK if handle_signal() succeeds.
We can move this to setup_rt_frame() as well, this avoids the unnecessary checks and makes the logic more clear.
3. use set_current_blocked() instead of sigprocmask(SIG_SETMASK), sigprocmask() should be avoided.
--- arch/x86/kernel/signal.c | 29 ++++++++++------------------- 1 files changed, 10 insertions(+), 19 deletions(-)
arch/x86/kernel/signal.c +10 -19
@@ -651,11 +651,15 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,static int setup_rt_frame (int sig,struct k_sigaction *ka,siginfo_t *info, -sigset_t *set,struct pt_regs *regs) +struct pt_regs *regs) {int usig =signr_convert (sig); +sigset_t *set = ¤t->blocked;int ret; +if (current_thread_info ()->status &TS_RESTORE_SIGMASK ) + set = ¤t->saved_sigmask; +/* Set up the stack frame */ if (is_ia32) {if (ka->sa.sa_flags &SA_SIGINFO )
@@ -670,12 +674,13 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,return -EFAULT ; } +current_thread_info ()->status &= ~TS_RESTORE_SIGMASK ;return ret; }static int handle_signal (unsigned long sig,siginfo_t *info,struct k_sigaction *ka, -sigset_t *oldset,struct pt_regs *regs) +struct pt_regs *regs) {sigset_t blocked;int ret;
@@ -710,7 +715,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, likely(test_and_clear_thread_flag(TIF_FORCED_TF))) regs->flags &= ~X86_EFLAGS_TF; - ret =setup_rt_frame (sig, ka, info, oldset, regs); + ret =setup_rt_frame (sig, ka, info, regs);if (ret)return ret;
@@ -765,7 +770,6 @@ static void do_signal(struct pt_regs *regs)struct k_sigaction ka;siginfo_t info;int signr; -sigset_t *oldset;/* * We want the common case to go fast, which is why we may in certain
@@ -777,23 +781,10 @@ static void do_signal(struct pt_regs *regs)if (!user_mode (regs))return ; -if (current_thread_info ()->status &TS_RESTORE_SIGMASK ) - oldset = ¤t->saved_sigmask; -else - oldset = ¤t->blocked; - signr =get_signal_to_deliver (&info, &ka, regs,NULL );if (signr >0 ) {/* Whee! Actually deliver the signal. */ -if (handle_signal (signr, &info, &ka, 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 TS_RESTORE_SIGMASK flag. -*/ -current_thread_info ()->status &= ~TS_RESTORE_SIGMASK ; - } +handle_signal (signr, &info, &ka, regs);return ; }
@@ -821,7 +812,7 @@ static void do_signal(struct pt_regs *regs)*/ if (current_thread_info ()->status &TS_RESTORE_SIGMASK ) {current_thread_info ()->status &= ~TS_RESTORE_SIGMASK ; -sigprocmask (SIG_SETMASK , ¤t->saved_sigmask,NULL ); +set_current_blocked (¤t->saved_sigmask); } }