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