summaryrefslogtreecommitdiff
path: root/signal/signal-dispatch.c
blob: 40440b70b5869245c8fd37e50d6e8ccdf6e6016d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/* signal-dispatch.c - Signal dispatcher.
   Copyright (C) 2008 Free Software Foundation, Inc.
   Written by Neal H. Walfield <neal@gnu.org>.

   This file is part of the GNU Hurd.

   The GNU Hurd is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 3 of
   the License, or (at your option) any later version.

   The GNU Hurd is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this program.  If not, see
   <http://www.gnu.org/licenses/>.  */

#include "sig-internal.h"

/* This is the signal handler entry point.  A thread is forced into
   this state when it receives a signal.  We need to save the thread's
   state and then invoke the high-level signal dispatcher.  SS->LOCK
   is locked by the caller.  */
void
signal_dispatch (struct signal_state *ss, siginfo_t *si)
{
  SIGNAL_DISPATCH_ENTRY;

  int signo = si->si_signo;

  assert (signo > 0 && signo < NSIG);
  assert (pthread_mutex_trylock (&ss->lock) == EBUSY);

  do
    {
      if ((sigmask (signo) & STOPSIGS))
	/* Stop signals clear a pending SIGCONT even if they
	   are handled or ignored (but not if preempted).  */
	{
	  sigdelset (&ss->pending, SIGCONT);
	  sigdelset (&process_pending, SIGCONT);
	}
      else if ((signo == SIGCONT))
	/* Even if handled or ignored (but not preempted), SIGCONT
	   clears stop signals and resumes the process.  */
	{
	  ss->pending &= ~STOPSIGS;
	  process_pending &= ~STOPSIGS;
	}

      void (*handler)(int, siginfo_t *, void *)
	= ss->actions[signo - 1].sa_sigaction;

      /* Reset to SIG_DFL if requested.  SIGILL and SIGTRAP cannot
	 be automatically reset when delivered; the system silently
	 enforces this restriction (sigaction).  */
      if (ss->actions[signo - 1].sa_flags & SA_RESETHAND
	  && signo != SIGILL && signo != SIGTRAP)
	ss->actions[signo - 1].sa_handler = SIG_DFL;

      sigset_t orig_blocked = ss->blocked;
      /* Block requested signals while running the handler.  */
      ss->blocked |= ss->actions[signo - 1].sa_mask;

      /* Block SIGNO unless we're asked not to.  */
      if (! (ss->actions[signo - 1].sa_flags & (SA_RESETHAND | SA_NODEFER)))
	sigaddset (&ss->blocked, signo);

      sigdelset (&ss->pending, signo);
      pthread_mutex_unlock (&ss->lock);

      pthread_mutex_lock (&sig_lock);
      sigdelset (&process_pending, signo);
      pthread_mutex_unlock (&sig_lock);

      if (handler == (void *) SIG_DFL)
	{
	  enum sig_action action = default_action (signo);

	  if (action == sig_terminate || action == sig_core)
	    _exit (128 + signo);

	  if (action == sig_stop)
	    /* XXX: Implement me.  */
	    panic ("Stopping process unimplemented.");

	  if (action == sig_cont)
	    /* XXX: Implement me.  */;
	    panic ("Continuing process unimplemented.");
	}
      else if (handler == (void *) SIG_IGN)
	;
      else
	handler (signo, si, NULL);

      pthread_mutex_lock (&ss->lock);

      /* "When a thread's signal mask is changed in a signal-catching
	 function that is installed by sigaction(), the restoration of
	 the signal mask on return from the signal-catching function
	 overrides that change (see sigaction())" (sigprocmask).  */
      ss->blocked = orig_blocked;

      sigset_t pending = ~ss->blocked & ss->pending;
      if (! pending)
	pending = ~ss->blocked & process_pending;
      signo = l4_lsb64 (pending);
    }
  while (signo);

  pthread_mutex_unlock (&ss->lock);

  SIGNAL_DISPATCH_EXIT;
}