CRISv32: handle multiple signals
Al Viro noted that CRIS fails to handle multiple signals. This fixes the problem for CRISv32 by making it use a C work_pending handling loop similar to the ARM implementation in 0a267fa6a15d41c ("ARM: 7472/1: pull all work_pending logics into C function"). This also happens to fixes the warnings which currently trigger on CRISv32 due to do_signal() being called with interrupts disabled. Test case (should die of the SIGSEGV which gets raised when setting up the stack for SIGALRM, but instead reaches and executes the _exit(1)): #include <unistd.h> #include <signal.h> #include <sys/time.h> #include <err.h> static void handler(int sig) { } int main(int argc, char *argv[]) { int ret; struct itimerval t1 = { .it_value = {1} }; stack_t ss = { .ss_sp = NULL, .ss_size = SIGSTKSZ, }; struct sigaction action = { .sa_handler = handler, .sa_flags = SA_ONSTACK, }; ret = sigaltstack(&ss, NULL); if (ret < 0) err(1, "sigaltstack"); sigaction(SIGALRM, &action, NULL); setitimer(ITIMER_REAL, &t1, NULL); pause(); _exit(1); return 0; } Reported-by: Al Viro <viro@ZenIV.linux.org.uk> Link: http://lkml.kernel.org/r/20121208074429.GC4939@ZenIV.linux.org.uk Signed-off-by: Rabin Vincent <rabin@rab.in> Signed-off-by: Jesper Nilsson <jespern@axis.com>
This commit is contained in:
committed by
Jesper Nilsson
parent
0f72e5c0df
commit
9a7449d3e9
@ -280,44 +280,15 @@ _syscall_exit_work:
|
||||
|
||||
.type _work_pending,@function
|
||||
_work_pending:
|
||||
addoq +TI_flags, $r0, $acr
|
||||
move.d [$acr], $r10
|
||||
btstq TIF_NEED_RESCHED, $r10 ; Need resched?
|
||||
bpl _work_notifysig ; No, must be signal/notify.
|
||||
nop
|
||||
.size _work_pending, . - _work_pending
|
||||
|
||||
.type _work_resched,@function
|
||||
_work_resched:
|
||||
move.d $r9, $r1 ; Preserve R9.
|
||||
jsr schedule
|
||||
nop
|
||||
move.d $r1, $r9
|
||||
di
|
||||
|
||||
addoq +TI_flags, $r0, $acr
|
||||
move.d [$acr], $r1
|
||||
and.d _TIF_WORK_MASK, $r1 ; Ignore sycall trace counter.
|
||||
beq _Rexit
|
||||
nop
|
||||
btstq TIF_NEED_RESCHED, $r1
|
||||
bmi _work_resched ; current->work.need_resched.
|
||||
nop
|
||||
.size _work_resched, . - _work_resched
|
||||
|
||||
.type _work_notifysig,@function
|
||||
_work_notifysig:
|
||||
;; Deal with pending signals and notify-resume requests.
|
||||
|
||||
addoq +TI_flags, $r0, $acr
|
||||
move.d [$acr], $r12 ; The thread_info_flags parameter.
|
||||
move.d $sp, $r11 ; The regs param.
|
||||
jsr do_notify_resume
|
||||
move.d $r9, $r10 ; do_notify_resume syscall/irq param.
|
||||
jsr do_work_pending
|
||||
move.d $r9, $r10 ; The syscall/irq param.
|
||||
|
||||
ba _Rexit
|
||||
nop
|
||||
.size _work_notifysig, . - _work_notifysig
|
||||
.size _work_pending, . - _work_pending
|
||||
|
||||
;; We get here as a sidetrack when we've entered a syscall with the
|
||||
;; trace-bit set. We need to call do_syscall_trace and then continue
|
||||
|
@ -42,3 +42,26 @@ void do_notify_resume(int canrestart, struct pt_regs *regs,
|
||||
tracehook_notify_resume(regs);
|
||||
}
|
||||
}
|
||||
|
||||
void do_work_pending(int syscall, struct pt_regs *regs,
|
||||
unsigned int thread_flags)
|
||||
{
|
||||
do {
|
||||
if (likely(thread_flags & _TIF_NEED_RESCHED)) {
|
||||
schedule();
|
||||
} else {
|
||||
if (unlikely(!user_mode(regs)))
|
||||
return;
|
||||
local_irq_enable();
|
||||
if (thread_flags & _TIF_SIGPENDING) {
|
||||
do_signal(syscall, regs);
|
||||
syscall = 0;
|
||||
} else {
|
||||
clear_thread_flag(TIF_NOTIFY_RESUME);
|
||||
tracehook_notify_resume(regs);
|
||||
}
|
||||
}
|
||||
local_irq_disable();
|
||||
thread_flags = current_thread_info()->flags;
|
||||
} while (thread_flags & _TIF_WORK_MASK);
|
||||
}
|
||||
|
Reference in New Issue
Block a user