Skip to content

Commit

Permalink
CRISv32: handle multiple signals
Browse files Browse the repository at this point in the history
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 0a267fa
("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>
  • Loading branch information
vitkyrka authored and Jesper Nilsson committed Mar 25, 2015
1 parent 0f72e5c commit 9a7449d
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 32 deletions.
35 changes: 3 additions & 32 deletions arch/cris/arch-v32/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 23 additions & 0 deletions arch/cris/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit 9a7449d

Please sign in to comment.