Formerly ../hurd/hurdkill.c.~5~
[kopensolaris-gnu/glibc.git] / hurd / hurdsig.c
1 /* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public License as
6 published by the Free Software Foundation; either version 2 of the
7 License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with the GNU C Library; see the file COPYING.LIB.  If
16 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
17 Cambridge, MA 02139, USA.  */
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <gnu-stabs.h>
22 #include <hurd.h>
23 #include <hurd/signal.h>
24 #include <cthreads.h>           /* For `struct mutex'.  */
25 #include <string.h>
26 #include "hurdmalloc.h"         /* XXX */
27
28 struct mutex _hurd_siglock;
29 int _hurd_stopped;
30
31 /* Port that receives signals and other miscellaneous messages.  */
32 mach_port_t _hurd_msgport;
33
34 /* Thread listening on it.  */
35 thread_t _hurd_msgport_thread;
36
37 /* Thread which receives task-global signals.  */
38 thread_t _hurd_sigthread;
39
40 /* Linked-list of per-thread signal state.  */
41 struct hurd_sigstate *_hurd_sigstates;
42
43 struct hurd_sigstate *
44 _hurd_thread_sigstate (thread_t thread)
45 {
46   struct hurd_sigstate *ss;
47   __mutex_lock (&_hurd_siglock);
48   for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
49     if (ss->thread == thread)
50       break;
51   if (ss == NULL)
52     {
53       ss = malloc (sizeof (*ss));
54       if (ss == NULL)
55         __libc_fatal ("hurd: Can't allocate thread sigstate\n");
56       memset (ss, 0, sizeof (*ss));
57       ss->thread = thread;
58       __mutex_init (&ss->lock);
59       ss->next = _hurd_sigstates;
60       _hurd_sigstates = ss;
61     }
62   __mutex_lock (&ss->lock);
63   __mutex_unlock (&_hurd_siglock);
64   return ss;
65 }
66 \f
67 #include <hurd/fd.h>
68 #include <hurd/core.h>
69 #include <hurd/paths.h>
70 #include <setjmp.h>
71 #include <fcntl.h>
72 #include <sys/wait.h>
73 #include "thread_state.h"
74 #include <hurd/msg_server.h>
75 #include <hurd/msg_reply.h>     /* For __sig_post_reply.  */
76
77 jmp_buf _hurd_sigthread_fault_env;
78
79 int _hurd_core_limit;   /* XXX */
80
81 /* Call the core server to mummify us before we die.
82    Returns nonzero if a core file was written.  */
83 static int
84 write_corefile (int signo, int sigcode)
85 {
86   error_t err;
87   volatile mach_port_t coreserver;
88   volatile file_t file;
89   char *volatile name;
90   char *volatile target;
91
92   /* XXX RLIMIT_CORE */
93
94   coreserver = MACH_PORT_NULL;
95   if (!setjmp (_hurd_sigthread_fault_env))
96     {
97       name = getenv ("CORESERVER");
98       if (name != NULL)
99         coreserver = __path_lookup (name, 0, 0);
100     }
101
102   if (coreserver == MACH_PORT_NULL)
103     coreserver = __path_lookup (_SERVERS_CORE, 0, 0);
104   if (coreserver == MACH_PORT_NULL)
105     return 0;
106
107   file = MACH_PORT_NULL;
108   name = NULL;
109   if (!setjmp (_hurd_sigthread_fault_env))
110     {
111       name = getenv ("COREFILE");
112       if (name != NULL)
113         file = __path_lookup (name, O_WRONLY|O_CREAT, 0666 & ~_hurd_umask);
114     }
115   if (name == NULL || file == MACH_PORT_NULL)
116     {
117       name = (char *) "core";
118       file = __path_lookup (name, O_WRONLY|O_CREAT, 0666 & ~_hurd_umask);
119     }
120
121   if (file == MACH_PORT_NULL)
122     return 0;
123
124   if (setjmp (_hurd_sigthread_fault_env))
125     /* We bombed in getenv.  */
126     target = NULL;
127   else
128     {
129       target = getenv ("GNUTARGET");
130       /* Fault now if TARGET is a bogus string.  */
131       (void) strlen (target);
132     }
133
134   err = __core_dump_task (coreserver,
135                           __mach_task_self (),
136                           file,
137                           signo, sigcode,
138                           target);
139   __mach_port_deallocate (__mach_task_self (), coreserver);
140   __mach_port_deallocate (__mach_task_self (), file);
141   if (err)
142     (void) remove (name);
143   return !err;
144 }
145
146
147 /* How long to give servers to respond to
148    interrupt_operation before giving up on them.  */
149 mach_msg_timeout_t _hurd_interrupt_timeout = 1000; /* One second.  */
150
151 /* SS->thread is suspended.  Fills STATE in with its registers.
152    SS->lock is held and kept.  */
153 static inline void
154 abort_rpcs (struct hurd_sigstate *ss, int signo, void *state)
155 {
156   unsigned int count = MACHINE_THREAD_STATE_COUNT;
157   __thread_abort (ss->thread);
158   if (__thread_get_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
159                           state, &count) != KERN_SUCCESS ||
160       count != MACHINE_THREAD_STATE_COUNT)
161     /* What kind of thread?? */
162     return;                     /* XXX */
163
164   if (ss->intr_port != MACH_PORT_NULL)
165     {
166       /* Abort whatever the thread is doing.
167          If it is in the mach_msg syscall doing the send,
168          the syscall will return MACH_SEND_INTERRUPTED.  */
169       mach_port_t msging_port;
170       if (_hurd_thread_state_msging_p (state, &msging_port))
171         {
172           /* The thread was waiting for the RPC to return.
173              Abort the operation.  The RPC will return EINTR.  */
174
175           struct
176             {
177               mach_msg_header_t header;
178               mach_msg_type_t type;
179               kern_return_t retcode;
180             } msg;
181           kern_return_t err;
182
183           msg.header.msgh_remote_port = ss->intr_port;
184           msg.header.msgh_local_port = __mach_reply_port ();
185           msg.header.msgh_seqno = 0;
186           msg.header.msgh_id = 33000; /* interrupt_operation XXX */
187           err = __mach_msg (&msg.header,
188                             MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_TIMEOUT,
189                             sizeof (msg.header), sizeof (msg),
190                             msg.header.msgh_local_port,
191                             _hurd_interrupt_timeout,
192                             MACH_PORT_NULL);
193           if (err != MACH_MSG_SUCCESS)
194             /* The interrupt didn't work.
195                Destroy the receive right the thread is blocked on.  */
196             __mach_port_destroy (__mach_task_self (), msging_port);
197           else
198             /* In case the server returned something screwy.  */
199             __mach_msg_destroy (&msg.header);
200
201           /* Tell the thread whether it should restart the
202              operation or return EINTR when it wakes up.  */
203           ss->intr_restart = ss->actions[signo].sa_flags & SA_RESTART;
204         }
205
206       /* If the thread is anywhere before the system call trap,
207          it will start the operation after the signal is handled.
208          
209          If the thread is after the system call trap, but before it has
210          cleared SS->intr_port, the operation is already finished.  */
211     }
212 }
213
214 /* Abort the RPCs being run by all threads but this one;
215    all other threads should be suspended.  */
216 static inline void
217 abort_all_rpcs (int signo, void *state)
218 {
219   thread_t me = __mach_thread_self ();
220   thread_t *threads;
221   mach_msg_type_number_t nthreads, i;
222
223   __task_threads (__mach_task_self (), &threads, &nthreads);
224   for (i = 0; i < nthreads; ++i)
225     {
226       if (threads[i] != me)
227         {
228           struct hurd_sigstate *ss = _hurd_thread_sigstate (threads[i]);
229           abort_rpcs (ss, signo, state);
230           __mutex_unlock (&ss->lock);
231         }
232       __mach_port_deallocate (__mach_task_self (), threads[i]);
233     }
234 }
235
236
237 struct hurd_signal_preempt *_hurd_signal_preempt[NSIG];
238 struct mutex _hurd_signal_preempt_lock;
239
240
241 /* Fetch the MiG reply port in use by the thread whose interrupted state is
242    described by *THREAD_STATE, and ensure that the thread will not try to
243    use it again.  */
244
245 static mach_port_t
246 interrupted_reply_port (struct machine_thread_state *thread_state)
247 {
248   mach_port_t port, *portloc;
249
250   if (setjmp (_hurd_sigthread_fault_env))
251     /* Faulted trying to read the stack.  */
252     return MACH_PORT_NULL;
253
254   portloc = (mach_port_t *) __hurd_threadvar_location_from_sp
255     (_HURD_THREADVAR_MIG_REPLY, (void *) thread_state->SP);
256
257   port = *portloc;
258   *portloc = MACH_PORT_NULL;
259   return port;
260 }
261
262
263 /* Deliver a signal.
264    SS->lock is held on entry and released before return.  */
265 void
266 _hurd_internal_post_signal (struct hurd_sigstate *ss,
267                             int signo, int sigcode,
268                             mach_port_t reply_port,
269                             mach_msg_type_name_t reply_port_type)
270 {
271   struct machine_thread_state thread_state;
272   enum { stop, ignore, core, term, handle } act;
273   sighandler_t handler;
274   struct hurd_signal_preempt *pe;
275   sighandler_t (*preempt) (thread_t, int, int) = NULL;
276
277   /* Check SS for pending signals and post them.  SS->lock is held on entry.
278      Return zero if no signals were pending.  If pending signals were posted,
279      unlock SS->lock and return nonzero.  */
280   inline int check_pending (struct hurd_sigstate *ss)
281     {
282       int signo;
283
284       if (ss->pending)
285         for (signo = 1; signo < NSIG; ++signo)
286           if (__sigismember (&ss->pending, signo))
287             {
288               __sigdelset (&ss->pending, signo);
289               _hurd_internal_post_signal (ss, signo, ss->sigcodes[signo],
290                                           reply_port, reply_port_type);
291               /* _hurd_internal_post_signal called us on SS before
292                  returning, so no need to keep looping.  */
293               return 1;
294             }
295
296       return 0;
297     }
298
299   /* Check for a preempted signal.  */
300   __mutex_lock (&_hurd_signal_preempt_lock);
301   for (pe = _hurd_signal_preempt[signo]; pe != NULL; pe = pe->next)
302     if (sigcode >= pe->first && sigcode <= pe->last)
303       {
304         preempt = pe->handler;
305         break;
306       }
307   __mutex_unlock (&_hurd_signal_preempt_lock);
308
309   handler = SIG_DFL;
310   if (preempt)
311     /* Let the preempting handler examine the thread.
312        If it returns SIG_DFL, we run the normal handler;
313        otherwise we use the handler it returns.  */
314     handler = (*preempt) (ss->thread, signo, sigcode);
315   if (handler == SIG_DFL)
316     handler = ss->actions[signo].sa_handler;
317
318   if (handler == SIG_DFL)
319     /* Figure out the default action for this signal.  */
320     switch (signo)
321       {
322       case 0:
323         /* A sig_post msg with SIGNO==0 is sent to
324            tell us to check for pending signals.  */
325         act = ignore;
326         break;
327
328       case SIGTTIN:
329       case SIGTTOU:
330       case SIGSTOP:
331       case SIGTSTP:
332         ss->pending &= ~sigmask (SIGCONT);
333         act = stop;
334         break;
335
336       case SIGCONT:
337         ss->pending &= ~(sigmask (SIGSTOP) | sigmask (SIGTSTP) |
338                          sigmask (SIGTTIN) | sigmask (SIGTTOU));
339         /* Fall through.  */
340       case SIGIO:
341       case SIGURG:
342       case SIGCHLD:
343       case SIGWINCH:
344         act = ignore;
345         break;
346
347       case SIGQUIT:
348       case SIGILL:
349       case SIGTRAP:
350       case SIGIOT:
351       case SIGEMT:
352       case SIGFPE:
353       case SIGBUS:
354       case SIGSEGV:
355       case SIGSYS:
356         act = core;
357         break;
358
359       case SIGINFO:
360         if (_hurd_pgrp == _hurd_pid)
361           {
362             /* We are the process group leader.  Since there is no
363                user-specified handler for SIGINFO, we use a default one
364                which prints something interesting.  We use the normal
365                handler mechanism instead of just doing it here to avoid the
366                signal thread faulting or blocking in this potentially hairy
367                operation.  */
368             act = handle;
369             handler = _hurd_siginfo_handler;
370           }
371         else
372           act = ignore;
373         break;
374
375       default:
376         act = term;
377         break;
378       }
379   else if (handler == SIG_IGN)
380     act = ignore;
381   else
382     act = handle;
383
384   if (_hurd_orphaned && act == stop &&
385       (signo & (__sigmask (SIGTTIN) | __sigmask (SIGTTOU) |
386                 __sigmask (SIGTSTP))))
387     {
388       /* If we would ordinarily stop for a job control signal, but we are
389          orphaned so noone would ever notice and continue us again, we just
390          quietly die, alone and in the dark.  */
391       sigcode = signo;
392       signo = SIGKILL;
393       act = term;
394     }
395
396   /* Handle receipt of a blocked signal.  */
397   if ((__sigismember (&ss->blocked, signo) && act != ignore) ||
398       (signo != SIGKILL && _hurd_stopped))
399     {
400       __sigaddset (&ss->pending, signo);
401       /* Save the code to be given to the handler when SIGNO is unblocked.  */
402       ss->sigcodes[signo] = sigcode;
403       act = ignore;
404     }
405
406   /* Perform the chosen action for the signal.  */
407   switch (act)
408     {
409     case stop:
410       /* Stop all other threads and mark ourselves stopped.  */
411       __USEPORT (PROC,
412                  ({
413                    /* Hold the siglock while stopping other threads to be
414                       sure it is not held by another thread afterwards.  */
415                    __mutex_unlock (&ss->lock);
416                    __mutex_lock (&_hurd_siglock);
417                    __proc_dostop (port, __mach_thread_self ());
418                    __mutex_unlock (&_hurd_siglock);
419                    abort_all_rpcs (signo, &thread_state);
420                    __proc_mark_stop (port, signo);
421                  }));
422       _hurd_stopped = 1;
423
424       __mutex_lock (&ss->lock);
425       if (ss->suspended)
426         {
427           /* There is a sigsuspend waiting.  Tell it to wake up.  */
428           ss->suspended = 0;
429 #ifdef noteven
430           __condition_signal (&ss->arrived);
431 #else
432           __mutex_unlock (&ss->lock);
433 #endif
434         }
435       else
436         __mutex_unlock (&ss->lock);
437
438       break;
439
440     case ignore:
441       /* Nobody cares about this signal.  */
442       break;
443
444     case term:                  /* Time to die.  */
445     case core:                  /* And leave a rotting corpse.  */
446       /* Have the proc server stop all other threads in our task.  */
447       __USEPORT (PROC, __proc_dostop (port, __mach_thread_self ()));
448       /* Abort all server operations now in progress.  */
449       abort_all_rpcs (signo, &thread_state);
450       /* The signal can now be considered delivered.
451          Don't make the killer wait for us to dump core.  */
452       if (reply_port)
453         __sig_post_reply (reply_port, reply_port_type, 0);
454       /* Tell proc how we died and then stick the saber in the gut.  */
455       _hurd_exit (W_EXITCODE (0, signo) |
456                   /* Do a core dump if desired.  Only set the wait status
457                      bit saying we in fact dumped core if the operation was
458                      actually succesful.  */
459                   (act == core && write_corefile (signo, sigcode) ?
460                    WCOREFLAG : 0));
461       /* NOTREACHED */
462
463     case handle:
464       /* Call a handler for this signal.  */
465       {
466         struct sigcontext *scp;
467
468         /* Stop the thread and abort its pending RPC operations.  */
469         __thread_suspend (ss->thread);
470         abort_rpcs (ss, signo, &thread_state);
471
472         /* Call the machine-dependent function to set the thread up
473            to run the signal handler, and preserve its old context.  */
474         scp = _hurd_setup_sighandler (ss->actions[signo].sa_flags,
475                                       handler,
476                                       &ss->sigaltstack,
477                                       signo, sigcode,
478                                       &thread_state);
479
480         /* Set the machine-independent parts of the signal context.  */
481         scp->sc_mask = ss->blocked;
482         scp->sc_intr_port = ss->intr_port;
483         /* Fetch the thread variable for the MiG reply port,
484            and set it to MACH_PORT_NULL.  */
485         scp->sc_reply_port = interrupted_reply_port (&thread_state);
486
487         /* Block SIGNO and requested signals while running the handler.  */
488         ss->blocked |= __sigmask (signo) | ss->actions[signo].sa_mask;
489
490         /* Start the thread running the handler.  */
491         __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
492                             (int *) &thread_state, MACHINE_THREAD_STATE_COUNT);
493         __thread_resume (ss->thread);
494         break;
495       }
496     }
497
498   /* The signal has either been ignored or is now being handled.  We can
499      consider it delivered and reply to the killer.  The exception is
500      signal 0, which can be sent by a user thread to make us check for
501      pending signals.  In that case we want to deliver the pending signals
502      before replying.  */
503   if (signo != 0 && reply_port)
504     {
505       __sig_post_reply (reply_port, reply_port_type, 0);
506       reply_port = MACH_PORT_NULL;
507     }
508
509   /* We get here only if we are handling or ignoring the signal;
510      otherwise we are stopped or dead by now.  We still hold SS->lock.
511      Check for pending signals, and loop to post them.  */
512   if (! check_pending (ss))
513     {
514       /* No more signals pending; SS->lock is still locked.  */
515       if (ss->suspended)
516         {
517           /* There is a sigsuspend waiting.  Tell it to wake up.  */
518           ss->suspended = 0;
519 #ifdef noteven
520           __condition_signal (&ss->arrived);
521 #else
522           __mutex_unlock (&ss->lock);
523 #endif
524         }
525       else
526         __mutex_unlock (&ss->lock);
527     }
528
529   /* No pending signals left undelivered for this thread.
530      If we were sent signal 0, we need to check for pending
531      signals for all threads.  */
532   if (signo == 0)
533     {
534       __mutex_lock (&_hurd_siglock);
535       for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
536         {
537           __mutex_lock (&ss->lock);
538           if (! check_pending (ss))
539             __mutex_unlock (&ss->lock);
540         }
541       __mutex_unlock (&_hurd_siglock);
542     }
543
544   /* All pending signals delivered to all threads.
545      Now we can send the reply message even for signal 0.  */
546   if (reply_port)
547     __sig_post_reply (reply_port, reply_port_type, 0);
548 }
549
550 /* Implement the sig_post RPC from <hurd/msg.defs>;
551    sent when someone wants us to get a signal.  */
552 kern_return_t
553 _S_sig_post (mach_port_t me,
554              mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
555              int signo,
556              mach_port_t refport)
557 {
558   struct hurd_sigstate *ss;
559
560   if (signo < 0 || signo >= NSIG)
561     return EINVAL;
562
563   if (refport == __mach_task_self ())
564     /* Can send any signal.  */
565     goto win;
566
567   /* Avoid needing to check for this below.  */
568   if (refport == MACH_PORT_NULL)
569     return EPERM;
570
571   switch (signo)
572     {
573     case SIGINT:
574     case SIGQUIT:
575     case SIGTSTP:
576     case SIGHUP:
577     case SIGINFO:
578       /* Job control signals can be sent by the controlling terminal.  */
579       if (__USEPORT (CTTYID, port == refport))
580         goto win;
581       break;
582
583     case SIGCONT:
584       {
585         /* A continue signal can be sent by anyone in the session.  */
586         mach_port_t sessport;
587         if (! __USEPORT (PROC, __proc_getsidport (port, &sessport)))
588           { 
589             int win = refport == sessport;
590             __mach_port_deallocate (__mach_task_self (), sessport);
591             if (win)
592               goto win;
593           }
594       }
595       break;
596
597     case SIGIO:
598     case SIGURG:
599       {
600         /* Any io object a file descriptor refers to might send us
601            one of these signals using its async ID port for REFPORT.
602
603            This is pretty wide open; it is not unlikely that some random
604            process can at least open for reading something we have open,
605            get its async ID port, and send us a spurious SIGIO or SIGURG
606            signal.  But BSD is actually wider open than that!--you can set
607            the owner of an io object to any process or process group
608            whatsoever and send them gratuitous signals.
609
610            Someday we could implement some reasonable scheme for
611            authorizing SIGIO and SIGURG signals properly.  */
612
613         int d;
614         __mutex_lock (&_hurd_dtable_lock);
615         for (d = 0; (unsigned int) d < (unsigned int) _hurd_dtablesize; ++d)
616           {
617             struct hurd_userlink ulink;
618             io_t port;
619             mach_port_t asyncid;
620             if (_hurd_dtable[d] == NULL)
621               continue;
622             port = _hurd_port_get (&_hurd_dtable[d]->port, &ulink);
623             if (! __io_get_icky_async_id (port, &asyncid))
624               {
625                 if (refport == asyncid)
626                   /* Break out of the loop on the next iteration.  */
627                   d = -1;
628                 __mach_port_deallocate (__mach_task_self (), asyncid);
629               }
630             _hurd_port_free (&_hurd_dtable[d]->port, &ulink, port);
631           }
632         /* If we found a lucky winner, we've set D to -1 in the loop.  */
633         if (d < 0)
634           goto win;
635       }
636     }
637
638   /* If this signal is legit, we have done `goto win' by now.
639      When we return the error, mig deallocates REFPORT.  */
640   return EPERM;
641
642  win:
643   /* Deallocate the REFPORT send right; we are done with it.  */
644   __mach_port_deallocate (__mach_task_self (), refport);
645
646   /* Get a hold of the designated signal-receiving thread.  */
647   ss = _hurd_thread_sigstate (_hurd_sigthread);
648
649   /* Post the signal; this will reply when the signal can be considered
650      delivered.  */
651   _hurd_internal_post_signal (ss, signo, 0, reply_port, reply_port_type);
652
653   return MIG_NO_REPLY;          /* Already replied.  */
654 }
655 \f
656 extern void __mig_init (void *);
657
658 #include <mach/task_special_ports.h>
659
660 /* Initialize the message port and _hurd_sigthread and start the signal
661    thread.  */
662
663 void
664 _hurdsig_init (void)
665 {
666   error_t err;
667   vm_size_t stacksize;
668
669   __mutex_init (&_hurd_siglock);
670
671   if (err = __mach_port_allocate (__mach_task_self (),
672                                   MACH_PORT_RIGHT_RECEIVE,
673                                   &_hurd_msgport))
674     __libc_fatal ("hurd: Can't create message port receive right\n");
675   
676   /* Make a send right to the signal port.  */
677   if (err = __mach_port_insert_right (__mach_task_self (),
678                                       _hurd_msgport,
679                                       _hurd_msgport,
680                                       MACH_MSG_TYPE_MAKE_SEND))
681     __libc_fatal ("hurd: Can't create send right to message port\n");
682
683   /* Set the default thread to receive task-global signals
684      to this one, the main (first) user thread.  */
685   _hurd_sigthread = __mach_thread_self ();
686
687   /* Start the signal thread listening on the message port.  */
688
689   if (err = __thread_create (__mach_task_self (), &_hurd_msgport_thread))
690     __libc_fatal ("hurd: Can't create signal thread\n");
691
692   stacksize = __vm_page_size * 4; /* Small stack for signal thread.  */
693   if (err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread,
694                                  _hurd_msgport_receive,
695                                  (vm_address_t *) &__hurd_sigthread_stack_base,
696                                  &stacksize))
697     __libc_fatal ("hurd: Can't setup signal thread\n");
698
699   __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize;
700   __hurd_sigthread_variables =
701     malloc (__hurd_threadvar_max * sizeof (unsigned long int));
702   if (__hurd_sigthread_variables == NULL)
703     __libc_fatal ("hurd: Can't allocate thread variables for signal thread\n");
704
705   /* Reinitialize the MiG support routines so they will use a per-thread
706      variable for the cached reply port.  */
707   __mig_init ((void *) __hurd_sigthread_stack_base);
708
709   if (err = __thread_resume (_hurd_msgport_thread))
710     __libc_fatal ("hurd: Can't resume signal thread\n");
711     
712 #if 0                           /* Don't confuse poor gdb.  */
713   /* Receive exceptions on the signal port.  */
714   __task_set_special_port (__mach_task_self (),
715                            TASK_EXCEPTION_PORT, _hurd_msgport);
716 #endif
717 }
718 \f
719 /* Send exceptions for the signal thread to the proc server.
720    It will forward the message on to our message port,
721    and then restore the thread's state to code which
722    does `longjmp (_hurd_sigthread_fault_env, 1)'.  */
723
724 void
725 _hurdsig_fault_init (void)
726 {
727   error_t err;
728   mach_port_t sigexc;
729   struct machine_thread_state state;
730
731   if (err = __mach_port_allocate (__mach_task_self (),
732                                   MACH_PORT_RIGHT_RECEIVE, &sigexc))
733     __libc_fatal ("hurd: Can't create receive right for signal thread exc\n");
734
735   /* Set up STATE with a thread state that will longjmp immediately.  */
736   _hurd_initialize_fault_recovery_state (&state);
737
738 #if 0                           /* Don't confuse gdb.  */
739   __thread_set_special_port (_hurd_msgport_thread,
740                              THREAD_EXCEPTION_PORT, sigexc);
741 #endif
742
743   if (err = __USEPORT
744       (PROC,
745        __proc_handle_exceptions (port,
746                                  sigexc,
747                                  _hurd_msgport, MACH_MSG_TYPE_COPY_SEND,
748                                  MACHINE_THREAD_STATE_FLAVOR,
749                                  (int *) &state, MACHINE_THREAD_STATE_COUNT)))
750     __libc_fatal ("hurd: proc won't handle signal thread exceptions\n");
751 }
752 \f                               /* XXXX */
753 static void
754 reauth_proc (mach_port_t new)
755 {
756   mach_port_t ignore;
757
758   /* Reauthenticate with the proc server.  */
759   if (! HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
760                        __proc_reauthenticate (port, _hurd_pid) ||
761                        __auth_user_authenticate (new, port, _hurd_pid,
762                                                  &ignore))
763       && ignore != MACH_PORT_NULL)
764     __mach_port_deallocate (__mach_task_self (), ignore);
765 }
766 text_set_element (__hurd_reauth_hook, reauth_proc);