Formerly hurd/hurd/signal.h.~10~
[kopensolaris-gnu/glibc.git] / hurd / hurd / signal.h
1 /* Implementing POSIX.1 signals under the Hurd.
2 Copyright (C) 1993, 1994 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB.  If
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA.  */
19
20 #ifndef _HURD_SIGNAL_H
21
22 #define _HURD_SIGNAL_H  1
23 #include <features.h>
24 /* Make sure <signal.h> is going to define NSIG.  */
25 #ifndef __USE_GNU
26 #error "Must have `_GNU_SOURCE' feature test macro to use this file"
27 #endif
28
29 #define __need_NULL
30 #include <stddef.h>
31
32 #include <mach/mach_types.h>
33 #include <mach/port.h>
34 #include <mach/message.h>
35 #include <hurd/hurd_types.h>
36 #include <signal.h>
37 #include <errno.h>
38
39 #include <mutex.h>
40 #include <lock-intern.h>
41
42
43 /* Per-thread signal state.  */
44
45 struct hurd_sigstate
46   {
47     /* XXX should be in cthread variable (?) */
48     thread_t thread;
49     struct hurd_sigstate *next; /* Linked-list of thread sigstates.  */
50
51     struct mutex lock;          /* Locks the rest of this structure.  */
52     sigset_t blocked;
53     sigset_t pending;
54     struct sigaction actions[NSIG];
55     struct sigaltstack sigaltstack;
56     int sigcodes[NSIG];         /* Codes for pending signals.  */
57
58     int suspended;              /* If nonzero, sig_post signals `arrived'.  */
59 #ifdef noteven
60     struct condition arrived;
61 #endif
62
63 #if 0
64     int vforked;                /* Nonzero if this thread is a vfork child.  */
65     struct
66       {
67         process_t proc;
68         file_t ccdir, cwdir, crdir, auth;
69         mode_t umask;
70         int ctty_fstype;
71         fsid_t ctty_fsid;
72         ino_t ctty_fileid;
73         struct hurd_dtable *dtable;
74         jmp_buf continuation;
75       } *vfork_saved;
76 #endif
77
78     /* Not locked.  Used only by this thread,
79        or by signal thread with this thread suspended.  */
80     volatile mach_port_t intr_port; /* Port interruptible RPC was sent on.  */
81     volatile int intr_restart;  /* If nonzero, restart interrupted RPC.  */
82   };
83
84 /* Linked list of states of all threads whose state has been asked for.  */
85
86 extern struct hurd_sigstate *_hurd_sigstates;
87
88 extern struct mutex _hurd_siglock; /* Locks _hurd_sigstates.  */
89
90 /* Get the sigstate of a given thread, taking its lock.  */
91
92 extern struct hurd_sigstate *_hurd_thread_sigstate (thread_t);
93 \f
94 /* Thread listening on our message port; also called the "signal thread".  */
95
96 extern thread_t _hurd_msgport_thread;
97
98 /* Our message port.  We hold the receive right and _hurd_msgport_thread
99    listens for messages on it.  We also hold a send right, for convenience.  */
100
101 extern mach_port_t _hurd_msgport;
102
103
104 /* Thread to receive process-global signals.  */
105
106 extern thread_t _hurd_sigthread;
107
108
109 /* Resource limit on core file size.  Enforced by hurdsig.c.  */
110 extern int _hurd_core_limit;
111 \f
112 /* Raise a signal as described by SIGNO and SIGCODE, on the thread whose
113    sigstate SS points to.  If SS is a null pointer, this instead affects
114    the calling thread.  */
115
116 extern void _hurd_raise_signal (struct hurd_sigstate *ss,
117                                 int signo, int sigcode);
118
119 /* Translate a Mach exception into a signal (machine-dependent).  */
120
121 extern void _hurd_exception2signal (int exception, int code, int subcode,
122                                     int *signo, int *sigcode);
123
124
125 /* Make the thread described by SS take the signal described by SIGNO and
126    SIGCODE.  SS->lock is held on entry, and released before return.  */
127
128 extern void _hurd_internal_post_signal (struct hurd_sigstate *ss,
129                                         int signo, int sigcode);
130
131 /* Set up STATE to handle signal SIGNO by running HANDLER.  FLAGS is the
132    `sa_flags' member from `struct sigaction'.  If the SA_ONSTACK bit is
133    set, *ALTSTACK describes the alternate signal stack to use.  The handler
134    is passed SIGNO, SIGCODE, and the returned `struct sigcontext' (which
135    resides on the stack the handler will use, and which describes the state
136    of the thread encoded in STATE before running the handler).  */
137
138 extern struct sigcontext *_hurd_setup_sighandler (int flags,
139                                                   __sighandler_t handler,
140                                                   struct sigaltstack *altstack,
141                                                   int signo, int sigcode,
142                                                   void *state);
143
144 /* Function run by the signal thread to receive from the signal port.  */
145
146 extern void _hurd_msgport_receive (void);
147
148 /* Return nonzero if STATE indicates a thread that is blocked in a mach_msg
149    system call (machine-dependent).  */
150
151 extern int _hurd_thread_state_msging_p (void *state);
152
153 /* Start THREAD running FUNCTION (machine-dependent).  */
154
155 extern kern_return_t _hurd_start_sigthread (thread_t thread,
156                                             void (*function) (void));
157
158 /* Set up STATE with a thread state that, when resumed, is
159    like `longjmp (_hurd_sigthread_fault_env, 1)'.  */
160
161 extern void _hurd_initialize_fault_recovery_state (void *state);
162
163
164 /* Function run for SIGINFO when its action is SIG_DFL and the current
165    process is the session leader.  */
166
167 extern void _hurd_siginfo_handler (int);
168
169
170 #ifdef notyet
171
172 /* Perform interruptible RPC CALL on PORT.
173    The args in CALL should be constant or local variable refs.
174    They may be evaluated many times, and must not change.
175    PORT must not be deallocated before this RPC is finished.  */
176 #define HURD_EINTR_RPC(port, call) \
177   ({
178     error_t __err;
179     struct hurd_sigstate *__ss
180       = _hurd_thread_sigstate (__mach_thread_self ());
181     __mutex_unlock (&__ss->lock); /* Lock not needed.  */
182     /* If we get a signal and should return EINTR, the signal thread will
183        clear this.  The RPC might return EINTR when some other thread gets
184        a signal, in which case we want to restart our call.  */
185     __ss->intr_restart = 1;
186     /* This one needs to be last.  A signal can arrive before here,
187        and if intr_port were set before intr_restart is
188        initialized, the signal thread would get confused.  */
189     __ss->intr_port = (port);
190     /* A signal may arrive here, after intr_port is set,
191        but before the mach_msg system call.  The signal handler might do an
192        interruptible RPC, and clobber intr_port; then it would not be set
193        properly when we actually did send the RPC, and a later signal
194        wouldn't interrupt that RPC.  So, _hurd_run_sighandler saves
195        intr_port in the sigcontext, and sigreturn restores it.  */
196   __do_call:
197     switch (__err = (call))
198       {
199       case EINTR:               /* RPC went out and was interrupted.  */
200       case MACH_SEND_INTERRUPTED: /* RPC didn't get out.  */
201         if (__ss->intr_restart)
202           /* Restart the interrupted call.  */
203           goto __do_call;
204         /* FALLTHROUGH */
205       case MACH_RCV_PORT_DIED:
206         /* Server didn't respond to interrupt_operation,
207            so the signal thread destroyed the reply port.  */
208         __err = EINTR;
209         break;
210       }
211     __ss->intr_port = MACH_PORT_NULL;
212     __err;
213   })
214
215 #endif /* notyet */
216
217 /* Mask of signals that cannot be caught, blocked, or ignored.  */
218 #define _SIG_CANT_MASK  (__sigmask (SIGSTOP) | __sigmask (SIGKILL))
219
220 /* Do an RPC to a process's message port.
221
222    Each argument is an expression which returns an error code; each
223    expression may be evaluated several times.  FETCH_MSGPORT_EXPR should
224    fetch the appropriate message port and store it in the local variable
225    `msgport'.  FETCH_REFPORT_EXPR should fetch the appropriate message port
226    and store it in the local variable `refport' (if no reference port is
227    needed in the call, then FETCH_REFPORT_EXPR should be simply
228    KERN_SUCCESS or 0).  Both of these are assumed to create user
229    references, which this macro deallocates.  RPC_EXPR should perform the
230    desired RPC operation using `msgport' and `refport'.
231
232    The reason for the complexity is that a process's message port and
233    reference port may change between fetching those ports and completing an
234    RPC using them (usually they change only when a process execs).  The RPC
235    will fail with MACH_SEND_INVALID_DEST if the msgport dies before we can
236    send the RPC request; or with MIG_SERVER_DIED if the msgport was
237    destroyed after we sent the RPC request but before it was serviced.  In
238    either of these cases, we retry the entire operation, discarding the old
239    message and reference ports and fetch them anew.  */
240
241 #define HURD_MSGPORT_RPC(fetch_msgport_expr, fetch_refport_expr, rpc_expr)   \
242 ({                                                                            \
243     error_t __err;                                                            \
244     mach_port_t msgport, refport = MACH_PORT_NULL;                            \
245     do                                                                        \
246       {                                                                       \
247         /* Get the message port.  */                                          \
248         if (__err = (fetch_msgport_expr))                                     \
249           break;                                                              \
250         /* Get the reference port.  */                                        \
251         if (__err = (fetch_refport_expr))                                     \
252           {                                                                   \
253             /* Couldn't get it; deallocate MSGPORT and fail.  */              \
254             __mach_port_deallocate (__mach_task_self (), msgport);            \
255             break;                                                            \
256           }                                                                   \
257         __err = (rpc_expr);                                                   \
258         __mach_port_deallocate (__mach_task_self (), msgport);                \
259         if (refport != MACH_PORT_NULL)                                        \
260           __mach_port_deallocate (__mach_task_self (), refport);              \
261       } while (__err != MACH_SEND_INVALID_DEST &&                             \
262                __err != MIG_SERVER_DIED);                                     \
263     __err;                                                                    \
264 })
265 \f
266 /* Some other parts of the library need to preempt signals, to detect
267    errors that should not result in a POSIX signal.  For example, when
268    some mapped region of memory is used, an extraneous SIGSEGV might be
269    generated when the mapping server returns an error for a page fault.  */
270
271 struct hurd_signal_preempt
272   {
273     /* Function to examine a thread receiving a given signal.  The handler
274        is called even for blocked signals.  This function is run in the
275        signal thread, with THREAD's sigstate locked; it should be as simple
276        and robust as possible.  THREAD is the thread which is about to
277        receive the signal.  SIGNO and SIGCODE would be passed to the normal
278        handler.
279
280        If the return value is SIG_DFL, normal signal processing continues.
281        If it is SIG_IGN, the signal is ignored.
282        Any other value is used in place of the normal handler.  */
283     sighandler_t (*handler) (thread_t thread, int signo, int sigcode);
284     int first, last;            /* Range of sigcodes this handler wants.  */
285     struct hurd_signal_preempt *next; /* Next handler on the chain. */
286   };
287
288 extern struct hurd_signal_preempt *_hurd_signal_preempt[NSIG];
289 extern struct mutex _hurd_signal_preempt_lock;
290
291
292 #ifndef _EXTERN_INLINE
293 #define _EXTERN_INLINE extern __inline
294 #endif
295
296 /* Initialize PREEMPTER with the information given and stick it in the
297    chain of preempters for SIGNO.  */
298
299 _EXTERN_INLINE int
300 hurd_preempt_signals (struct hurd_signal_preempt *preempter,
301                       int signo, int first_code, int last_code,
302                       sighandler_t (*handler) (thread_t, int, int))
303 {
304   if (signo <= 0 || signo >= NSIG)
305     {
306       errno = EINVAL;
307       return -1;
308     }
309   preempter->first = first_code;
310   preempter->last = last_code;
311   preempter->handler = handler;
312   __mutex_lock (&_hurd_signal_preempt_lock);
313   preempter->next = _hurd_signal_preempt[signo];
314   _hurd_signal_preempt[signo] = preempter;
315   __mutex_unlock (&_hurd_signal_preempt_lock);
316   return 0;
317 }
318
319 /* Remove PREEMPTER from the chain for SIGNO.  */
320
321 _EXTERN_INLINE int
322 hurd_unpreempt_signals (struct hurd_signal_preempt *preempter, int signo)
323 {
324   struct hurd_signal_preempt *p, *lastp;
325   if (signo <= 0 || signo >= NSIG)
326     {
327       errno = EINVAL;
328       return -1;
329     }
330   __mutex_lock (&_hurd_signal_preempt_lock);
331   for (p = _hurd_signal_preempt[signo], lastp = NULL;
332        p != NULL; lastp = p, p = p->next)
333     if (p == preempter)
334       {
335         (lastp == NULL ? _hurd_signal_preempt[signo] : lastp->next) = p->next;
336         __mutex_unlock (&_hurd_signal_preempt_lock);
337         return 0;
338       }
339   _hurd_signal_preempt[signo] = preempter;
340   __mutex_unlock (&_hurd_signal_preempt_lock);
341   errno = ENOENT;
342   return -1;
343 }
344
345
346 #endif  /* hurd/signal.h */