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;
}
|