Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a7449d3 authored by Rabin Vincent's avatar Rabin Vincent Committed by Jesper Nilsson
Browse files

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 0a267fa6
("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: default avatarAl Viro <viro@ZenIV.linux.org.uk>
Link: http://lkml.kernel.org/r/20121208074429.GC4939@ZenIV.linux.org.uk


Signed-off-by: default avatarRabin Vincent <rabin@rab.in>
Signed-off-by: default avatarJesper Nilsson <jespern@axis.com>
parent 0f72e5c0
Loading
Loading
Loading
Loading
+3 −32
Original line number Diff line number Diff line
@@ -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
+23 −0
Original line number Diff line number Diff line
@@ -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);
}