Formerly hurd/hurd/signal.h.~12~
[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 /* Initialize the signal code, and start the signal thread.  */
113
114 extern void _hurdsig_init (void);
115
116 /* Initialize proc server-assisted fault recovery for the signal thread.  */
117
118 extern void _hurdsig_fault_init (void);
119
120 /* Raise a signal as described by SIGNO and SIGCODE, on the thread whose
121    sigstate SS points to.  If SS is a null pointer, this instead affects
122    the calling thread.  */
123
124 extern void _hurd_raise_signal (struct hurd_sigstate *ss,
125                                 int signo, int sigcode);
126
127 /* Translate a Mach exception into a signal (machine-dependent).  */
128
129 extern void _hurd_exception2signal (int exception, int code, int subcode,
130                                     int *signo, int *sigcode);
131
132
133 /* Make the thread described by SS take the signal described by SIGNO and
134    SIGCODE.  SS->lock is held on entry, and released before return.  */
135
136 extern void _hurd_internal_post_signal (struct hurd_sigstate *ss,
137                                         int signo, int sigcode);
138
139 /* Set up STATE to handle signal SIGNO by running HANDLER.  FLAGS is the
140    `sa_flags' member from `struct sigaction'.  If the SA_ONSTACK bit is
141    set, *ALTSTACK describes the alternate signal stack to use.  The handler
142    is passed SIGNO, SIGCODE, and the returned `struct sigcontext' (which
143    resides on the stack the handler will use, and which describes the state
144    of the thread encoded in STATE before running the handler).  */
145
146 extern struct sigcontext *_hurd_setup_sighandler (int flags,
147                                                   __sighandler_t handler,
148                                                   struct sigaltstack *altstack,
149                                                   int signo, int sigcode,
150                                                   void *state);
151
152 /* Function run by the signal thread to receive from the signal port.  */
153
154 extern void _hurd_msgport_receive (void);
155
156 /* Return nonzero if STATE indicates a thread that is blocked in a mach_msg
157    system call (machine-dependent).  If returning nonzero, set *PORT to
158    the receive right that the thread is blocked on.  */
159
160 extern int _hurd_thread_state_msging_p (void *state, mach_port_t *port);
161
162 /* Set up STATE with a thread state that, when resumed, is
163    like `longjmp (_hurd_sigthread_fault_env, 1)'.  */
164
165 extern void _hurd_initialize_fault_recovery_state (void *state);
166
167
168 /* Function run for SIGINFO when its action is SIG_DFL and the current
169    process is the session leader.  */
170
171 extern void _hurd_siginfo_handler (int);
172
173
174 #ifdef notyet
175
176 /* Perform interruptible RPC CALL on PORT.
177    The args in CALL should be constant or local variable refs.
178    They may be evaluated many times, and must not change.
179    PORT must not be deallocated before this RPC is finished.  */
180 #define HURD_EINTR_RPC(port, call) \
181   ({
182     error_t __err;
183     struct hurd_sigstate *__ss
184       = _hurd_thread_sigstate (__mach_thread_self ());
185     __mutex_unlock (&__ss->lock); /* Lock not needed.  */
186     /* If we get a signal and should return EINTR, the signal thread will
187        clear this.  The RPC might return EINTR when some other thread gets
188        a signal, in which case we want to restart our call.  */
189     __ss->intr_restart = 1;
190     /* This one needs to be last.  A signal can arrive before here,
191        and if intr_port were set before intr_restart is
192        initialized, the signal thread would get confused.  */
193     __ss->intr_port = (port);
194     /* A signal may arrive here, after intr_port is set,
195        but before the mach_msg system call.  The signal handler might do an
196        interruptible RPC, and clobber intr_port; then it would not be set
197        properly when we actually did send the RPC, and a later signal
198        wouldn't interrupt that RPC.  So, _hurd_run_sighandler saves
199        intr_port in the sigcontext, and sigreturn restores it.  */
200   __do_call:
201     switch (__err = (call))
202       {
203       case EINTR:               /* RPC went out and was interrupted.  */
204       case MACH_SEND_INTERRUPTED: /* RPC didn't get out.  */
205         if (__ss->intr_restart)
206           /* Restart the interrupted call.  */
207           goto __do_call;
208         /* FALLTHROUGH */
209       case MACH_RCV_PORT_DIED:
210         /* Server didn't respond to interrupt_operation,
211            so the signal thread destroyed the reply port.  */
212         __err = EINTR;
213         break;
214       }
215     __ss->intr_port = MACH_PORT_NULL;
216     __err;
217   })
218
219 #endif /* notyet */
220
221 /* Mask of signals that cannot be caught, blocked, or ignored.  */
222 #define _SIG_CANT_MASK  (__sigmask (SIGSTOP) | __sigmask (SIGKILL))
223
224 /* Do an RPC to a process's message port.
225
226    Each argument is an expression which returns an error code; each
227    expression may be evaluated several times.  FETCH_MSGPORT_EXPR should
228    fetch the appropriate message port and store it in the local variable
229    `msgport'.  FETCH_REFPORT_EXPR should fetch the appropriate message port
230    and store it in the local variable `refport' (if no reference port is
231    needed in the call, then FETCH_REFPORT_EXPR should be simply
232    KERN_SUCCESS or 0).  Both of these are assumed to create user
233    references, which this macro deallocates.  RPC_EXPR should perform the
234    desired RPC operation using `msgport' and `refport'.
235
236    The reason for the complexity is that a process's message port and
237    reference port may change between fetching those ports and completing an
238    RPC using them (usually they change only when a process execs).  The RPC
239    will fail with MACH_SEND_INVALID_DEST if the msgport dies before we can
240    send the RPC request; or with MIG_SERVER_DIED if the msgport was
241    destroyed after we sent the RPC request but before it was serviced.  In
242    either of these cases, we retry the entire operation, discarding the old
243    message and reference ports and fetch them anew.  */
244
245 #define HURD_MSGPORT_RPC(fetch_msgport_expr, fetch_refport_expr, rpc_expr)   \
246 ({                                                                            \
247     error_t __err;                                                            \
248     mach_port_t msgport, refport = MACH_PORT_NULL;                            \
249     do                                                                        \
250       {                                                                       \
251         /* Get the message port.  */                                          \
252         if (__err = (fetch_msgport_expr))                                     \
253           break;                                                              \
254         /* Get the reference port.  */                                        \
255         if (__err = (fetch_refport_expr))                                     \
256           {                                                                   \
257             /* Couldn't get it; deallocate MSGPORT and fail.  */              \
258             __mach_port_deallocate (__mach_task_self (), msgport);            \
259             break;                                                            \
260           }                                                                   \
261         __err = (rpc_expr);                                                   \
262         __mach_port_deallocate (__mach_task_self (), msgport);                \
263         if (refport != MACH_PORT_NULL)                                        \
264           __mach_port_deallocate (__mach_task_self (), refport);              \
265       } while (__err != MACH_SEND_INVALID_DEST &&                             \
266                __err != MIG_SERVER_DIED);                                     \
267     __err;                                                                    \
268 })
269 \f
270 /* Some other parts of the library need to preempt signals, to detect
271    errors that should not result in a POSIX signal.  For example, when
272    some mapped region of memory is used, an extraneous SIGSEGV might be
273    generated when the mapping server returns an error for a page fault.  */
274
275 struct hurd_signal_preempt
276   {
277     /* Function to examine a thread receiving a given signal.  The handler
278        is called even for blocked signals.  This function is run in the
279        signal thread, with THREAD's sigstate locked; it should be as simple
280        and robust as possible.  THREAD is the thread which is about to
281        receive the signal.  SIGNO and SIGCODE would be passed to the normal
282        handler.
283
284        If the return value is SIG_DFL, normal signal processing continues.
285        If it is SIG_IGN, the signal is ignored.
286        Any other value is used in place of the normal handler.  */
287     sighandler_t (*handler) (thread_t thread, int signo, int sigcode);
288     int first, last;            /* Range of sigcodes this handler wants.  */
289     struct hurd_signal_preempt *next; /* Next handler on the chain. */
290   };
291
292 extern struct hurd_signal_preempt *_hurd_signal_preempt[NSIG];
293 extern struct mutex _hurd_signal_preempt_lock;
294
295
296 #ifndef _EXTERN_INLINE
297 #define _EXTERN_INLINE extern __inline
298 #endif
299
300 /* Initialize PREEMPTER with the information given and stick it in the
301    chain of preempters for SIGNO.  */
302
303 _EXTERN_INLINE int
304 hurd_preempt_signals (struct hurd_signal_preempt *preempter,
305                       int signo, int first_code, int last_code,
306                       sighandler_t (*handler) (thread_t, int, int))
307 {
308   if (signo <= 0 || signo >= NSIG)
309     {
310       errno = EINVAL;
311       return -1;
312     }
313   preempter->first = first_code;
314   preempter->last = last_code;
315   preempter->handler = handler;
316   __mutex_lock (&_hurd_signal_preempt_lock);
317   preempter->next = _hurd_signal_preempt[signo];
318   _hurd_signal_preempt[signo] = preempter;
319   __mutex_unlock (&_hurd_signal_preempt_lock);
320   return 0;
321 }
322
323 /* Remove PREEMPTER from the chain for SIGNO.  */
324
325 _EXTERN_INLINE int
326 hurd_unpreempt_signals (struct hurd_signal_preempt *preempter, int signo)
327 {
328   struct hurd_signal_preempt *p, *lastp;
329   if (signo <= 0 || signo >= NSIG)
330     {
331       errno = EINVAL;
332       return -1;
333     }
334   __mutex_lock (&_hurd_signal_preempt_lock);
335   for (p = _hurd_signal_preempt[signo], lastp = NULL;
336        p != NULL; lastp = p, p = p->next)
337     if (p == preempter)
338       {
339         (lastp == NULL ? _hurd_signal_preempt[signo] : lastp->next) = p->next;
340         __mutex_unlock (&_hurd_signal_preempt_lock);
341         return 0;
342       }
343   _hurd_signal_preempt[signo] = preempter;
344   __mutex_unlock (&_hurd_signal_preempt_lock);
345   errno = ENOENT;
346   return -1;
347 }
348
349
350 #endif  /* hurd/signal.h */