Back to index

glibc  2.9
hurdsig.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991,92,93,94,95,96,97,98,99,2000,2001,2002,2005,2008
00002        Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <string.h>
00023 
00024 #include <cthreads.h>              /* For `struct mutex'.  */
00025 #include <mach.h>
00026 #include <mach/thread_switch.h>
00027 
00028 #include <hurd.h>
00029 #include <hurd/id.h>
00030 #include <hurd/signal.h>
00031 
00032 #include "hurdfault.h"
00033 #include "hurdmalloc.h"            /* XXX */
00034 #include "../locale/localeinfo.h"
00035 
00036 const char *_hurdsig_getenv (const char *);
00037 
00038 struct mutex _hurd_siglock;
00039 int _hurd_stopped;
00040 
00041 /* Port that receives signals and other miscellaneous messages.  */
00042 mach_port_t _hurd_msgport;
00043 
00044 /* Thread listening on it.  */
00045 thread_t _hurd_msgport_thread;
00046 
00047 /* Thread which receives task-global signals.  */
00048 thread_t _hurd_sigthread;
00049 
00050 /* These are set up by _hurdsig_init.  */
00051 unsigned long int __hurd_sigthread_stack_base;
00052 unsigned long int __hurd_sigthread_stack_end;
00053 unsigned long int *__hurd_sigthread_variables;
00054 
00055 /* Linked-list of per-thread signal state.  */
00056 struct hurd_sigstate *_hurd_sigstates;
00057 
00058 /* Timeout for RPC's after interrupt_operation. */
00059 mach_msg_timeout_t _hurd_interrupted_rpc_timeout = 3000;
00060 
00061 static void
00062 default_sigaction (struct sigaction actions[NSIG])
00063 {
00064   int signo;
00065 
00066   __sigemptyset (&actions[0].sa_mask);
00067   actions[0].sa_flags = SA_RESTART;
00068   actions[0].sa_handler = SIG_DFL;
00069 
00070   for (signo = 1; signo < NSIG; ++signo)
00071     actions[signo] = actions[0];
00072 }
00073 
00074 struct hurd_sigstate *
00075 _hurd_thread_sigstate (thread_t thread)
00076 {
00077   struct hurd_sigstate *ss;
00078   __mutex_lock (&_hurd_siglock);
00079   for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
00080     if (ss->thread == thread)
00081        break;
00082   if (ss == NULL)
00083     {
00084       ss = malloc (sizeof (*ss));
00085       if (ss == NULL)
00086        __libc_fatal ("hurd: Can't allocate thread sigstate\n");
00087       ss->thread = thread;
00088       __spin_lock_init (&ss->lock);
00089 
00090       /* Initialize default state.  */
00091       __sigemptyset (&ss->blocked);
00092       __sigemptyset (&ss->pending);
00093       memset (&ss->sigaltstack, 0, sizeof (ss->sigaltstack));
00094       ss->preemptors = NULL;
00095       ss->suspended = MACH_PORT_NULL;
00096       ss->intr_port = MACH_PORT_NULL;
00097       ss->context = NULL;
00098 
00099       /* Initialize the sigaction vector from the default signal receiving
00100         thread's state, and its from the system defaults.  */
00101       if (thread == _hurd_sigthread)
00102        default_sigaction (ss->actions);
00103       else
00104        {
00105          struct hurd_sigstate *s;
00106          for (s = _hurd_sigstates; s != NULL; s = s->next)
00107            if (s->thread == _hurd_sigthread)
00108              break;
00109          if (s)
00110            {
00111              __spin_lock (&s->lock);
00112              memcpy (ss->actions, s->actions, sizeof (s->actions));
00113              __spin_unlock (&s->lock);
00114            }
00115          else
00116            default_sigaction (ss->actions);
00117        }
00118 
00119       ss->next = _hurd_sigstates;
00120       _hurd_sigstates = ss;
00121     }
00122   __mutex_unlock (&_hurd_siglock);
00123   return ss;
00124 }
00125 
00126 /* Signal delivery itself is on this page.  */
00127 
00128 #include <hurd/fd.h>
00129 #include <hurd/crash.h>
00130 #include <hurd/resource.h>
00131 #include <hurd/paths.h>
00132 #include <setjmp.h>
00133 #include <fcntl.h>
00134 #include <sys/wait.h>
00135 #include <thread_state.h>
00136 #include <hurd/msg_server.h>
00137 #include <hurd/msg_reply.h> /* For __msg_sig_post_reply.  */
00138 #include <hurd/interrupt.h>
00139 #include <assert.h>
00140 #include <unistd.h>
00141 
00142 
00143 /* Call the crash dump server to mummify us before we die.
00144    Returns nonzero if a core file was written.  */
00145 static int
00146 write_corefile (int signo, const struct hurd_signal_detail *detail)
00147 {
00148   error_t err;
00149   mach_port_t coreserver;
00150   file_t file, coredir;
00151   const char *name;
00152 
00153   /* Don't bother locking since we just read the one word.  */
00154   rlim_t corelimit = _hurd_rlimits[RLIMIT_CORE].rlim_cur;
00155 
00156   if (corelimit == 0)
00157     /* No core dumping, thank you very much.  Note that this makes
00158        `ulimit -c 0' prevent crash-suspension too, which is probably
00159        what the user wanted.  */
00160     return 0;
00161 
00162   /* XXX RLIMIT_CORE:
00163      When we have a protocol to make the server return an error
00164      for RLIMIT_FSIZE, then tell the corefile fs server the RLIMIT_CORE
00165      value in place of the RLIMIT_FSIZE value.  */
00166 
00167   /* First get a port to the core dumping server.  */
00168   coreserver = MACH_PORT_NULL;
00169   name = _hurdsig_getenv ("CRASHSERVER");
00170   if (name != NULL)
00171     coreserver = __file_name_lookup (name, 0, 0);
00172   if (coreserver == MACH_PORT_NULL)
00173     coreserver = __file_name_lookup (_SERVERS_CRASH, 0, 0);
00174   if (coreserver == MACH_PORT_NULL)
00175     return 0;
00176 
00177   /* Get a port to the directory where the new core file will reside.  */
00178   file = MACH_PORT_NULL;
00179   name = _hurdsig_getenv ("COREFILE");
00180   if (name == NULL)
00181     name = "core";
00182   coredir = __file_name_split (name, (char **) &name);
00183   if (coredir != MACH_PORT_NULL)
00184     /* Create the new file, but don't link it into the directory yet.  */
00185     __dir_mkfile (coredir, O_WRONLY|O_CREAT,
00186                 0600 & ~_hurd_umask, /* XXX ? */
00187                 &file);
00188 
00189   /* Call the core dumping server to write the core file.  */
00190   err = __crash_dump_task (coreserver,
00191                         __mach_task_self (),
00192                         file,
00193                         signo, detail->code, detail->error,
00194                         detail->exc, detail->exc_code, detail->exc_subcode,
00195                         _hurd_ports[INIT_PORT_CTTYID].port,
00196                         MACH_MSG_TYPE_COPY_SEND);
00197   __mach_port_deallocate (__mach_task_self (), coreserver);
00198 
00199   if (! err && file != MACH_PORT_NULL)
00200     /* The core dump into FILE succeeded, so now link it into the
00201        directory.  */
00202     err = __dir_link (coredir, file, name, 1);
00203   __mach_port_deallocate (__mach_task_self (), file);
00204   __mach_port_deallocate (__mach_task_self (), coredir);
00205   return !err && file != MACH_PORT_NULL;
00206 }
00207 
00208 
00209 /* The lowest-numbered thread state flavor value is 1,
00210    so we use bit 0 in machine_thread_all_state.set to
00211    record whether we have done thread_abort.  */
00212 #define THREAD_ABORTED 1
00213 
00214 /* SS->thread is suspended.  Abort the thread and get its basic state.  */
00215 static void
00216 abort_thread (struct hurd_sigstate *ss, struct machine_thread_all_state *state,
00217              void (*reply) (void))
00218 {
00219   if (!(state->set & THREAD_ABORTED))
00220     {
00221       error_t err = __thread_abort (ss->thread);
00222       assert_perror (err);
00223       /* Clear all thread state flavor set bits, because thread_abort may
00224         have changed the state.  */
00225       state->set = THREAD_ABORTED;
00226     }
00227 
00228   if (reply)
00229     (*reply) ();
00230 
00231   machine_get_basic_state (ss->thread, state);
00232 }
00233 
00234 /* Find the location of the MiG reply port cell in use by the thread whose
00235    state is described by THREAD_STATE.  If SIGTHREAD is nonzero, make sure
00236    that this location can be set without faulting, or else return NULL.  */
00237 
00238 static mach_port_t *
00239 interrupted_reply_port_location (struct machine_thread_all_state *thread_state,
00240                              int sigthread)
00241 {
00242   mach_port_t *portloc = (mach_port_t *) __hurd_threadvar_location_from_sp
00243     (_HURD_THREADVAR_MIG_REPLY, (void *) thread_state->basic.SP);
00244 
00245   if (sigthread && _hurdsig_catch_memory_fault (portloc))
00246     /* Faulted trying to read the stack.  */
00247     return NULL;
00248 
00249   /* Fault now if this pointer is bogus.  */
00250   *(volatile mach_port_t *) portloc = *portloc;
00251 
00252   if (sigthread)
00253     _hurdsig_end_catch_fault ();
00254 
00255   return portloc;
00256 }
00257 
00258 #include <hurd/sigpreempt.h>
00259 #include <intr-msg.h>
00260 
00261 /* Timeout on interrupt_operation calls.  */
00262 mach_msg_timeout_t _hurdsig_interrupt_timeout = 1000;
00263 
00264 /* SS->thread is suspended.
00265 
00266    Abort any interruptible RPC operation the thread is doing.
00267 
00268    This uses only the constant member SS->thread and the unlocked, atomically
00269    set member SS->intr_port, so no locking is needed.
00270 
00271    If successfully sent an interrupt_operation and therefore the thread should
00272    wait for its pending RPC to return (possibly EINTR) before taking the
00273    incoming signal, returns the reply port to be received on.  Otherwise
00274    returns MACH_PORT_NULL.
00275 
00276    SIGNO is used to find the applicable SA_RESTART bit.  If SIGNO is zero,
00277    the RPC fails with EINTR instead of restarting (thread_cancel).
00278 
00279    *STATE_CHANGE is set nonzero if STATE->basic was modified and should
00280    be applied back to the thread if it might ever run again, else zero.  */
00281 
00282 mach_port_t
00283 _hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
00284                    struct machine_thread_all_state *state, int *state_change,
00285                    void (*reply) (void))
00286 {
00287   extern const void _hurd_intr_rpc_msg_in_trap;
00288   mach_port_t rcv_port = MACH_PORT_NULL;
00289   mach_port_t intr_port;
00290 
00291   *state_change = 0;
00292 
00293   intr_port = ss->intr_port;
00294   if (intr_port == MACH_PORT_NULL)
00295     /* No interruption needs done.  */
00296     return MACH_PORT_NULL;
00297 
00298   /* Abort the thread's kernel context, so any pending message send or
00299      receive completes immediately or aborts.  */
00300   abort_thread (ss, state, reply);
00301 
00302   if (state->basic.PC < (natural_t) &_hurd_intr_rpc_msg_in_trap)
00303     {
00304       /* The thread is about to do the RPC, but hasn't yet entered
00305         mach_msg.  Mutate the thread's state so it knows not to try
00306         the RPC.  */
00307       INTR_MSG_BACK_OUT (&state->basic);
00308       MACHINE_THREAD_STATE_SET_PC (&state->basic,
00309                                &_hurd_intr_rpc_msg_in_trap);
00310       state->basic.SYSRETURN = MACH_SEND_INTERRUPTED;
00311       *state_change = 1;
00312     }
00313   else if (state->basic.PC == (natural_t) &_hurd_intr_rpc_msg_in_trap &&
00314           /* The thread was blocked in the system call.  After thread_abort,
00315              the return value register indicates what state the RPC was in
00316              when interrupted.  */
00317           state->basic.SYSRETURN == MACH_RCV_INTERRUPTED)
00318       {
00319        /* The RPC request message was sent and the thread was waiting for
00320           the reply message; now the message receive has been aborted, so
00321           the mach_msg call will return MACH_RCV_INTERRUPTED.  We must tell
00322           the server to interrupt the pending operation.  The thread must
00323           wait for the reply message before running the signal handler (to
00324           guarantee that the operation has finished being interrupted), so
00325           our nonzero return tells the trampoline code to finish the message
00326           receive operation before running the handler.  */
00327 
00328        mach_port_t *reply = interrupted_reply_port_location (state,
00329                                                        sigthread);
00330        error_t err = __interrupt_operation (intr_port, _hurdsig_interrupt_timeout);
00331 
00332        if (err)
00333          {
00334            if (reply)
00335              {
00336               /* The interrupt didn't work.
00337                  Destroy the receive right the thread is blocked on.  */
00338               __mach_port_destroy (__mach_task_self (), *reply);
00339               *reply = MACH_PORT_NULL;
00340              }
00341 
00342            /* The system call return value register now contains
00343               MACH_RCV_INTERRUPTED; when mach_msg resumes, it will retry the
00344               call.  Since we have just destroyed the receive right, the
00345               retry will fail with MACH_RCV_INVALID_NAME.  Instead, just
00346               change the return value here to EINTR so mach_msg will not
00347               retry and the EINTR error code will propagate up.  */
00348            state->basic.SYSRETURN = EINTR;
00349            *state_change = 1;
00350          }
00351        else if (reply)
00352          rcv_port = *reply;
00353 
00354        /* All threads whose RPCs were interrupted by the interrupt_operation
00355           call above will retry their RPCs unless we clear SS->intr_port.
00356           So we clear it for the thread taking a signal when SA_RESTART is
00357           clear, so that its call returns EINTR.  */
00358        if (! signo || !(ss->actions[signo].sa_flags & SA_RESTART))
00359          ss->intr_port = MACH_PORT_NULL;
00360       }
00361 
00362   return rcv_port;
00363 }
00364 
00365 
00366 /* Abort the RPCs being run by all threads but this one;
00367    all other threads should be suspended.  If LIVE is nonzero, those
00368    threads may run again, so they should be adjusted as necessary to be
00369    happy when resumed.  STATE is clobbered as a scratch area; its initial
00370    contents are ignored, and its contents on return are not useful.  */
00371 
00372 static void
00373 abort_all_rpcs (int signo, struct machine_thread_all_state *state, int live)
00374 {
00375   /* We can just loop over the sigstates.  Any thread doing something
00376      interruptible must have one.  We needn't bother locking because all
00377      other threads are stopped.  */
00378 
00379   struct hurd_sigstate *ss;
00380   size_t nthreads;
00381   mach_port_t *reply_ports;
00382 
00383   /* First loop over the sigstates to count them.
00384      We need to know how big a vector we will need for REPLY_PORTS.  */
00385   nthreads = 0;
00386   for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
00387     ++nthreads;
00388 
00389   reply_ports = alloca (nthreads * sizeof *reply_ports);
00390 
00391   nthreads = 0;
00392   for (ss = _hurd_sigstates; ss != NULL; ss = ss->next, ++nthreads)
00393     if (ss->thread == _hurd_msgport_thread)
00394       reply_ports[nthreads] = MACH_PORT_NULL;
00395     else
00396       {
00397        int state_changed;
00398        state->set = 0;             /* Reset scratch area.  */
00399 
00400        /* Abort any operation in progress with interrupt_operation.
00401           Record the reply port the thread is waiting on.
00402           We will wait for all the replies below.  */
00403        reply_ports[nthreads] = _hurdsig_abort_rpcs (ss, signo, 1,
00404                                                state, &state_changed,
00405                                                NULL);
00406        if (live)
00407          {
00408            if (reply_ports[nthreads] != MACH_PORT_NULL)
00409              {
00410               /* We will wait for the reply to this RPC below, so the
00411                  thread must issue a new RPC rather than waiting for the
00412                  reply to the one it sent.  */
00413               state->basic.SYSRETURN = EINTR;
00414               state_changed = 1;
00415              }
00416            if (state_changed)
00417              /* Aborting the RPC needed to change this thread's state,
00418                and it might ever run again.  So write back its state.  */
00419              __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
00420                               (natural_t *) &state->basic,
00421                               MACHINE_THREAD_STATE_COUNT);
00422          }
00423       }
00424 
00425   /* Wait for replies from all the successfully interrupted RPCs.  */
00426   while (nthreads-- > 0)
00427     if (reply_ports[nthreads] != MACH_PORT_NULL)
00428       {
00429        error_t err;
00430        mach_msg_header_t head;
00431        err = __mach_msg (&head, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, sizeof head,
00432                        reply_ports[nthreads],
00433                        _hurd_interrupted_rpc_timeout, MACH_PORT_NULL);
00434        switch (err)
00435          {
00436          case MACH_RCV_TIMED_OUT:
00437          case MACH_RCV_TOO_LARGE:
00438            break;
00439 
00440          default:
00441            assert_perror (err);
00442          }
00443       }
00444 }
00445 
00446 struct hurd_signal_preemptor *_hurdsig_preemptors = 0;
00447 sigset_t _hurdsig_preempted_set;
00448 
00449 /* XXX temporary to deal with spelling fix */
00450 weak_alias (_hurdsig_preemptors, _hurdsig_preempters)
00451 
00452 /* Mask of stop signals.  */
00453 #define STOPSIGS (sigmask (SIGTTIN) | sigmask (SIGTTOU) | \
00454                 sigmask (SIGSTOP) | sigmask (SIGTSTP))
00455 
00456 /* Deliver a signal.  SS is not locked.  */
00457 void
00458 _hurd_internal_post_signal (struct hurd_sigstate *ss,
00459                          int signo, struct hurd_signal_detail *detail,
00460                          mach_port_t reply_port,
00461                          mach_msg_type_name_t reply_port_type,
00462                          int untraced)
00463 {
00464   error_t err;
00465   struct machine_thread_all_state thread_state;
00466   enum { stop, ignore, core, term, handle } act;
00467   sighandler_t handler;
00468   sigset_t pending;
00469   int ss_suspended;
00470 
00471   /* Reply to this sig_post message.  */
00472   __typeof (__msg_sig_post_reply) *reply_rpc
00473     = (untraced ? __msg_sig_post_untraced_reply : __msg_sig_post_reply);
00474   void reply (void)
00475     {
00476       error_t err;
00477       if (reply_port == MACH_PORT_NULL)
00478        return;
00479       err = (*reply_rpc) (reply_port, reply_port_type, 0);
00480       reply_port = MACH_PORT_NULL;
00481       if (err != MACH_SEND_INVALID_DEST) /* Ignore dead reply port.  */
00482        assert_perror (err);
00483     }
00484 
00485   /* Mark the signal as pending.  */
00486   void mark_pending (void)
00487     {
00488       __sigaddset (&ss->pending, signo);
00489       /* Save the details to be given to the handler when SIGNO is
00490         unblocked.  */
00491       ss->pending_data[signo] = *detail;
00492     }
00493 
00494   /* Suspend the process with SIGNO.  */
00495   void suspend (void)
00496     {
00497       /* Stop all other threads and mark ourselves stopped.  */
00498       __USEPORT (PROC,
00499                ({
00500                  /* Hold the siglock while stopping other threads to be
00501                     sure it is not held by another thread afterwards.  */
00502                  __mutex_lock (&_hurd_siglock);
00503                  __proc_dostop (port, _hurd_msgport_thread);
00504                  __mutex_unlock (&_hurd_siglock);
00505                  abort_all_rpcs (signo, &thread_state, 1);
00506                  reply ();
00507                  __proc_mark_stop (port, signo, detail->code);
00508                }));
00509       _hurd_stopped = 1;
00510     }
00511   /* Resume the process after a suspension.  */
00512   void resume (void)
00513     {
00514       /* Resume the process from being stopped.  */
00515       thread_t *threads;
00516       mach_msg_type_number_t nthreads, i;
00517       error_t err;
00518 
00519       if (! _hurd_stopped)
00520        return;
00521 
00522       /* Tell the proc server we are continuing.  */
00523       __USEPORT (PROC, __proc_mark_cont (port));
00524       /* Fetch ports to all our threads and resume them.  */
00525       err = __task_threads (__mach_task_self (), &threads, &nthreads);
00526       assert_perror (err);
00527       for (i = 0; i < nthreads; ++i)
00528        {
00529          if (threads[i] != _hurd_msgport_thread &&
00530              (act != handle || threads[i] != ss->thread))
00531            {
00532              err = __thread_resume (threads[i]);
00533              assert_perror (err);
00534            }
00535          err = __mach_port_deallocate (__mach_task_self (),
00536                                    threads[i]);
00537          assert_perror (err);
00538        }
00539       __vm_deallocate (__mach_task_self (),
00540                      (vm_address_t) threads,
00541                      nthreads * sizeof *threads);
00542       _hurd_stopped = 0;
00543       if (act == handle)
00544        /* The thread that will run the handler is already suspended.  */
00545        ss_suspended = 1;
00546     }
00547 
00548   if (signo == 0)
00549     {
00550       if (untraced)
00551        /* This is PTRACE_CONTINUE.  */
00552        resume ();
00553 
00554       /* This call is just to check for pending signals.  */
00555       __spin_lock (&ss->lock);
00556       goto check_pending_signals;
00557     }
00558 
00559  post_signal:
00560 
00561   thread_state.set = 0;            /* We know nothing.  */
00562 
00563   __spin_lock (&ss->lock);
00564 
00565   /* Check for a preempted signal.  Preempted signals can arrive during
00566      critical sections.  */
00567   {
00568     inline sighandler_t try_preemptor (struct hurd_signal_preemptor *pe)
00569       {                            /* PE cannot be null.  */
00570        do
00571          {
00572            if (HURD_PREEMPT_SIGNAL_P (pe, signo, detail->code))
00573              {
00574               if (pe->preemptor)
00575                 {
00576                   sighandler_t handler = (*pe->preemptor) (pe, ss,
00577                                                       &signo, detail);
00578                   if (handler != SIG_ERR)
00579                     return handler;
00580                 }
00581               else
00582                 return pe->handler;
00583              }
00584            pe = pe->next;
00585          } while (pe != 0);
00586        return SIG_ERR;
00587       }
00588 
00589     handler = ss->preemptors ? try_preemptor (ss->preemptors) : SIG_ERR;
00590 
00591     /* If no thread-specific preemptor, check for a global one.  */
00592     if (handler == SIG_ERR && __sigismember (&_hurdsig_preempted_set, signo))
00593       {
00594        __mutex_lock (&_hurd_siglock);
00595        handler = try_preemptor (_hurdsig_preemptors);
00596        __mutex_unlock (&_hurd_siglock);
00597       }
00598   }
00599 
00600   ss_suspended = 0;
00601 
00602   if (handler == SIG_IGN)
00603     /* Ignore the signal altogether.  */
00604     act = ignore;
00605   else if (handler != SIG_ERR)
00606     /* Run the preemption-provided handler.  */
00607     act = handle;
00608   else
00609     {
00610       /* No preemption.  Do normal handling.  */
00611 
00612       if (!untraced && __sigismember (&_hurdsig_traced, signo))
00613        {
00614          /* We are being traced.  Stop to tell the debugger of the signal.  */
00615          if (_hurd_stopped)
00616            /* Already stopped.  Mark the signal as pending;
00617               when resumed, we will notice it and stop again.  */
00618            mark_pending ();
00619          else
00620            suspend ();
00621          __spin_unlock (&ss->lock);
00622          reply ();
00623          return;
00624        }
00625 
00626       handler = ss->actions[signo].sa_handler;
00627 
00628       if (handler == SIG_DFL)
00629        /* Figure out the default action for this signal.  */
00630        switch (signo)
00631          {
00632          case 0:
00633            /* A sig_post msg with SIGNO==0 is sent to
00634               tell us to check for pending signals.  */
00635            act = ignore;
00636            break;
00637 
00638          case SIGTTIN:
00639          case SIGTTOU:
00640          case SIGSTOP:
00641          case SIGTSTP:
00642            act = stop;
00643            break;
00644 
00645          case SIGCONT:
00646          case SIGIO:
00647          case SIGURG:
00648          case SIGCHLD:
00649          case SIGWINCH:
00650            act = ignore;
00651            break;
00652 
00653          case SIGQUIT:
00654          case SIGILL:
00655          case SIGTRAP:
00656          case SIGIOT:
00657          case SIGEMT:
00658          case SIGFPE:
00659          case SIGBUS:
00660          case SIGSEGV:
00661          case SIGSYS:
00662            act = core;
00663            break;
00664 
00665          case SIGINFO:
00666            if (_hurd_pgrp == _hurd_pid)
00667              {
00668               /* We are the process group leader.  Since there is no
00669                  user-specified handler for SIGINFO, we use a default one
00670                  which prints something interesting.  We use the normal
00671                  handler mechanism instead of just doing it here to avoid
00672                  the signal thread faulting or blocking in this
00673                  potentially hairy operation.  */
00674               act = handle;
00675               handler = _hurd_siginfo_handler;
00676              }
00677            else
00678              act = ignore;
00679            break;
00680 
00681          default:
00682            act = term;
00683            break;
00684          }
00685       else if (handler == SIG_IGN)
00686        act = ignore;
00687       else
00688        act = handle;
00689 
00690       if (__sigmask (signo) & STOPSIGS)
00691        /* Stop signals clear a pending SIGCONT even if they
00692           are handled or ignored (but not if preempted).  */
00693        __sigdelset (&ss->pending, SIGCONT);
00694       else
00695        {
00696          if (signo == SIGCONT)
00697            /* Even if handled or ignored (but not preempted), SIGCONT clears
00698               stop signals and resumes the process.  */
00699            ss->pending &= ~STOPSIGS;
00700 
00701          if (_hurd_stopped && act != stop && (untraced || signo == SIGCONT))
00702            resume ();
00703        }
00704     }
00705 
00706   if (_hurd_orphaned && act == stop &&
00707       (__sigmask (signo) & (__sigmask (SIGTTIN) | __sigmask (SIGTTOU) |
00708                          __sigmask (SIGTSTP))))
00709     {
00710       /* If we would ordinarily stop for a job control signal, but we are
00711         orphaned so noone would ever notice and continue us again, we just
00712         quietly die, alone and in the dark.  */
00713       detail->code = signo;
00714       signo = SIGKILL;
00715       act = term;
00716     }
00717 
00718   /* Handle receipt of a blocked signal, or any signal while stopped.  */
00719   if (act != ignore &&             /* Signals ignored now are forgotten now.  */
00720       __sigismember (&ss->blocked, signo) ||
00721       (signo != SIGKILL && _hurd_stopped))
00722     {
00723       mark_pending ();
00724       act = ignore;
00725     }
00726 
00727   /* Perform the chosen action for the signal.  */
00728   switch (act)
00729     {
00730     case stop:
00731       if (_hurd_stopped)
00732        {
00733          /* We are already stopped, but receiving an untraced stop
00734             signal.  Instead of resuming and suspending again, just
00735             notify the proc server of the new stop signal.  */
00736          error_t err = __USEPORT (PROC, __proc_mark_stop
00737                                (port, signo, detail->code));
00738          assert_perror (err);
00739        }
00740       else
00741        /* Suspend the process.  */
00742        suspend ();
00743       break;
00744 
00745     case ignore:
00746       if (detail->exc)
00747        /* Blocking or ignoring a machine exception is fatal.
00748           Otherwise we could just spin on the faulting instruction.  */
00749        goto fatal;
00750 
00751       /* Nobody cares about this signal.  If there was a call to resume
00752         above in SIGCONT processing and we've left a thread suspended,
00753         now's the time to set it going. */
00754       if (ss_suspended)
00755        {
00756          err = __thread_resume (ss->thread);
00757          assert_perror (err);
00758          ss_suspended = 0;
00759        }
00760       break;
00761 
00762     sigbomb:
00763       /* We got a fault setting up the stack frame for the handler.
00764         Nothing to do but die; BSD gets SIGILL in this case.  */
00765       detail->code = signo; /* XXX ? */
00766       signo = SIGILL;
00767 
00768     fatal:
00769       act = core;
00770       /* FALLTHROUGH */
00771 
00772     case term:                     /* Time to die.  */
00773     case core:                     /* And leave a rotting corpse.  */
00774       /* Have the proc server stop all other threads in our task.  */
00775       err = __USEPORT (PROC, __proc_dostop (port, _hurd_msgport_thread));
00776       assert_perror (err);
00777       /* No more user instructions will be executed.
00778         The signal can now be considered delivered.  */
00779       reply ();
00780       /* Abort all server operations now in progress.  */
00781       abort_all_rpcs (signo, &thread_state, 0);
00782 
00783       {
00784        int status = W_EXITCODE (0, signo);
00785        /* Do a core dump if desired.  Only set the wait status bit saying we
00786           in fact dumped core if the operation was actually successful.  */
00787        if (act == core && write_corefile (signo, detail))
00788          status |= WCOREFLAG;
00789        /* Tell proc how we died and then stick the saber in the gut.  */
00790        _hurd_exit (status);
00791        /* NOTREACHED */
00792       }
00793 
00794     case handle:
00795       /* Call a handler for this signal.  */
00796       {
00797        struct sigcontext *scp, ocontext;
00798        int wait_for_reply, state_changed;
00799 
00800        /* Stop the thread and abort its pending RPC operations.  */
00801        if (! ss_suspended)
00802          {
00803            err = __thread_suspend (ss->thread);
00804            assert_perror (err);
00805          }
00806 
00807        /* Abort the thread's kernel context, so any pending message send
00808           or receive completes immediately or aborts.  If an interruptible
00809           RPC is in progress, abort_rpcs will do this.  But we must always
00810           do it before fetching the thread's state, because
00811           thread_get_state is never kosher before thread_abort.  */
00812        abort_thread (ss, &thread_state, NULL);
00813 
00814        if (ss->context)
00815          {
00816            /* We have a previous sigcontext that sigreturn was about
00817               to restore when another signal arrived.  */
00818 
00819            mach_port_t *loc;
00820 
00821            if (_hurdsig_catch_memory_fault (ss->context))
00822              {
00823               /* We faulted reading the thread's stack.  Forget that
00824                  context and pretend it wasn't there.  It almost
00825                  certainly crash if this handler returns, but that's it's
00826                  problem.  */
00827               ss->context = NULL;
00828              }
00829            else
00830              {
00831               /* Copy the context from the thread's stack before
00832                  we start diddling the stack to set up the handler.  */
00833               ocontext = *ss->context;
00834               ss->context = &ocontext;
00835              }
00836            _hurdsig_end_catch_fault ();
00837 
00838            if (! machine_get_basic_state (ss->thread, &thread_state))
00839              goto sigbomb;
00840            loc = interrupted_reply_port_location (&thread_state, 1);
00841            if (loc && *loc != MACH_PORT_NULL)
00842              /* This is the reply port for the context which called
00843                sigreturn.  Since we are abandoning that context entirely
00844                and restoring SS->context instead, destroy this port.  */
00845              __mach_port_destroy (__mach_task_self (), *loc);
00846 
00847            /* The thread was in sigreturn, not in any interruptible RPC.  */
00848            wait_for_reply = 0;
00849 
00850            assert (! __spin_lock_locked (&ss->critical_section_lock));
00851          }
00852        else
00853          {
00854            int crit = __spin_lock_locked (&ss->critical_section_lock);
00855 
00856            wait_for_reply
00857              = (_hurdsig_abort_rpcs (ss,
00858                                   /* In a critical section, any RPC
00859                                     should be cancelled instead of
00860                                     restarted, regardless of
00861                                     SA_RESTART, so the entire
00862                                     "atomic" operation can be aborted
00863                                     as a unit.  */
00864                                   crit ? 0 : signo, 1,
00865                                   &thread_state, &state_changed,
00866                                   &reply)
00867                != MACH_PORT_NULL);
00868 
00869            if (crit)
00870              {
00871               /* The thread is in a critical section.  Mark the signal as
00872                  pending.  When it finishes the critical section, it will
00873                  check for pending signals.  */
00874               mark_pending ();
00875               if (state_changed)
00876                 /* Some cases of interrupting an RPC must change the
00877                    thread state to back out the call.  Normally this
00878                    change is rolled into the warping to the handler and
00879                    sigreturn, but we are not running the handler now
00880                    because the thread is in a critical section.  Instead,
00881                    mutate the thread right away for the RPC interruption
00882                    and resume it; the RPC will return early so the
00883                    critical section can end soon.  */
00884                 __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
00885                                   (natural_t *) &thread_state.basic,
00886                                   MACHINE_THREAD_STATE_COUNT);
00887               /* */
00888               ss->intr_port = MACH_PORT_NULL;
00889               __thread_resume (ss->thread);
00890               break;
00891              }
00892          }
00893 
00894        /* Call the machine-dependent function to set the thread up
00895           to run the signal handler, and preserve its old context.  */
00896        scp = _hurd_setup_sighandler (ss, handler, signo, detail,
00897                                   wait_for_reply, &thread_state);
00898        if (scp == NULL)
00899          goto sigbomb;
00900 
00901        /* Set the machine-independent parts of the signal context.  */
00902 
00903        {
00904          /* Fetch the thread variable for the MiG reply port,
00905             and set it to MACH_PORT_NULL.  */
00906          mach_port_t *loc = interrupted_reply_port_location (&thread_state,
00907                                                        1);
00908          if (loc)
00909            {
00910              scp->sc_reply_port = *loc;
00911              *loc = MACH_PORT_NULL;
00912            }
00913          else
00914            scp->sc_reply_port = MACH_PORT_NULL;
00915 
00916          /* Save the intr_port in use by the interrupted code,
00917             and clear the cell before running the trampoline.  */
00918          scp->sc_intr_port = ss->intr_port;
00919          ss->intr_port = MACH_PORT_NULL;
00920 
00921          if (ss->context)
00922            {
00923              /* After the handler runs we will restore to the state in
00924                SS->context, not the state of the thread now.  So restore
00925                that context's reply port and intr port.  */
00926 
00927              scp->sc_reply_port = ss->context->sc_reply_port;
00928              scp->sc_intr_port = ss->context->sc_intr_port;
00929 
00930              ss->context = NULL;
00931            }
00932        }
00933 
00934        /* Backdoor extra argument to signal handler.  */
00935        scp->sc_error = detail->error;
00936 
00937        /* Block requested signals while running the handler.  */
00938        scp->sc_mask = ss->blocked;
00939        __sigorset (&ss->blocked, &ss->blocked, &ss->actions[signo].sa_mask);
00940 
00941        /* Also block SIGNO unless we're asked not to.  */
00942        if (! (ss->actions[signo].sa_flags & (SA_RESETHAND | SA_NODEFER)))
00943          __sigaddset (&ss->blocked, signo);
00944 
00945        /* Reset to SIG_DFL if requested.  SIGILL and SIGTRAP cannot
00946            be automatically reset when delivered; the system silently
00947            enforces this restriction.  */
00948        if (ss->actions[signo].sa_flags & SA_RESETHAND
00949            && signo != SIGILL && signo != SIGTRAP)
00950          ss->actions[signo].sa_handler = SIG_DFL;
00951 
00952        /* Start the thread running the handler (or possibly waiting for an
00953           RPC reply before running the handler).  */
00954        err = __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
00955                               (natural_t *) &thread_state.basic,
00956                               MACHINE_THREAD_STATE_COUNT);
00957        assert_perror (err);
00958        err = __thread_resume (ss->thread);
00959        assert_perror (err);
00960        thread_state.set = 0;       /* Everything we know is now wrong.  */
00961        break;
00962       }
00963     }
00964 
00965   /* The signal has either been ignored or is now being handled.  We can
00966      consider it delivered and reply to the killer.  */
00967   reply ();
00968 
00969   /* We get here unless the signal was fatal.  We still hold SS->lock.
00970      Check for pending signals, and loop to post them.  */
00971   {
00972     /* Return nonzero if SS has any signals pending we should worry about.
00973        We don't worry about any pending signals if we are stopped, nor if
00974        SS is in a critical section.  We are guaranteed to get a sig_post
00975        message before any of them become deliverable: either the SIGCONT
00976        signal, or a sig_post with SIGNO==0 as an explicit poll when the
00977        thread finishes its critical section.  */
00978     inline int signals_pending (void)
00979       {
00980        if (_hurd_stopped || __spin_lock_locked (&ss->critical_section_lock))
00981          return 0;
00982        return pending = ss->pending & ~ss->blocked;
00983       }
00984 
00985   check_pending_signals:
00986     untraced = 0;
00987 
00988     if (signals_pending ())
00989       {
00990        for (signo = 1; signo < NSIG; ++signo)
00991          if (__sigismember (&pending, signo))
00992            {
00993            deliver_pending:
00994              __sigdelset (&ss->pending, signo);
00995              *detail = ss->pending_data[signo];
00996              __spin_unlock (&ss->lock);
00997              goto post_signal;
00998            }
00999       }
01000 
01001     /* No pending signals left undelivered for this thread.
01002        If we were sent signal 0, we need to check for pending
01003        signals for all threads.  */
01004     if (signo == 0)
01005       {
01006        __spin_unlock (&ss->lock);
01007        __mutex_lock (&_hurd_siglock);
01008        for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
01009          {
01010            __spin_lock (&ss->lock);
01011            for (signo = 1; signo < NSIG; ++signo)
01012              if (__sigismember (&ss->pending, signo)
01013                 && (!__sigismember (&ss->blocked, signo)
01014                     /* We "deliver" immediately pending blocked signals whose
01015                       action might be to ignore, so that if ignored they are
01016                       dropped right away.  */
01017                     || ss->actions[signo].sa_handler == SIG_IGN
01018                     || ss->actions[signo].sa_handler == SIG_DFL))
01019               {
01020                 mutex_unlock (&_hurd_siglock);
01021                 goto deliver_pending;
01022               }
01023            __spin_unlock (&ss->lock);
01024          }
01025        __mutex_unlock (&_hurd_siglock);
01026       }
01027     else
01028       {
01029        /* No more signals pending; SS->lock is still locked.
01030           Wake up any sigsuspend call that is blocking SS->thread.  */
01031        if (ss->suspended != MACH_PORT_NULL)
01032          {
01033            /* There is a sigsuspend waiting.  Tell it to wake up.  */
01034            error_t err;
01035            mach_msg_header_t msg;
01036            msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND, 0);
01037            msg.msgh_remote_port = ss->suspended;
01038            msg.msgh_local_port = MACH_PORT_NULL;
01039            /* These values do not matter.  */
01040            msg.msgh_id = 8675309; /* Jenny, Jenny.  */
01041            ss->suspended = MACH_PORT_NULL;
01042            err = __mach_msg (&msg, MACH_SEND_MSG, sizeof msg, 0,
01043                            MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
01044                            MACH_PORT_NULL);
01045            assert_perror (err);
01046          }
01047        __spin_unlock (&ss->lock);
01048       }
01049   }
01050 
01051   /* All pending signals delivered to all threads.
01052      Now we can send the reply message even for signal 0.  */
01053   reply ();
01054 }
01055 
01056 /* Decide whether REFPORT enables the sender to send us a SIGNO signal.
01057    Returns zero if so, otherwise the error code to return to the sender.  */
01058 
01059 static error_t
01060 signal_allowed (int signo, mach_port_t refport)
01061 {
01062   if (signo < 0 || signo >= NSIG)
01063     return EINVAL;
01064 
01065   if (refport == __mach_task_self ())
01066     /* Can send any signal.  */
01067     goto win;
01068 
01069   /* Avoid needing to check for this below.  */
01070   if (refport == MACH_PORT_NULL)
01071     return EPERM;
01072 
01073   switch (signo)
01074     {
01075     case SIGINT:
01076     case SIGQUIT:
01077     case SIGTSTP:
01078     case SIGHUP:
01079     case SIGINFO:
01080     case SIGTTIN:
01081     case SIGTTOU:
01082     case SIGWINCH:
01083       /* Job control signals can be sent by the controlling terminal.  */
01084       if (__USEPORT (CTTYID, port == refport))
01085        goto win;
01086       break;
01087 
01088     case SIGCONT:
01089       {
01090        /* A continue signal can be sent by anyone in the session.  */
01091        mach_port_t sessport;
01092        if (! __USEPORT (PROC, __proc_getsidport (port, &sessport)))
01093          {
01094            __mach_port_deallocate (__mach_task_self (), sessport);
01095            if (refport == sessport)
01096              goto win;
01097          }
01098       }
01099       break;
01100 
01101     case SIGIO:
01102     case SIGURG:
01103       {
01104        /* Any io object a file descriptor refers to might send us
01105           one of these signals using its async ID port for REFPORT.
01106 
01107           This is pretty wide open; it is not unlikely that some random
01108           process can at least open for reading something we have open,
01109           get its async ID port, and send us a spurious SIGIO or SIGURG
01110           signal.  But BSD is actually wider open than that!--you can set
01111           the owner of an io object to any process or process group
01112           whatsoever and send them gratuitous signals.
01113 
01114           Someday we could implement some reasonable scheme for
01115           authorizing SIGIO and SIGURG signals properly.  */
01116 
01117        int d;
01118        int lucky = 0;              /* True if we find a match for REFPORT.  */
01119        __mutex_lock (&_hurd_dtable_lock);
01120        for (d = 0; !lucky && (unsigned) d < (unsigned) _hurd_dtablesize; ++d)
01121          {
01122            struct hurd_userlink ulink;
01123            io_t port;
01124            mach_port_t asyncid;
01125            if (_hurd_dtable[d] == NULL)
01126              continue;
01127            port = _hurd_port_get (&_hurd_dtable[d]->port, &ulink);
01128            if (! __io_get_icky_async_id (port, &asyncid))
01129              {
01130               if (refport == asyncid)
01131                 /* Break out of the loop on the next iteration.  */
01132                 lucky = 1;
01133               __mach_port_deallocate (__mach_task_self (), asyncid);
01134              }
01135            _hurd_port_free (&_hurd_dtable[d]->port, &ulink, port);
01136          }
01137        /* If we found a lucky winner, we've set D to -1 in the loop.  */
01138        if (lucky)
01139          goto win;
01140       }
01141     }
01142 
01143   /* If this signal is legit, we have done `goto win' by now.
01144      When we return the error, mig deallocates REFPORT.  */
01145   return EPERM;
01146 
01147  win:
01148   /* Deallocate the REFPORT send right; we are done with it.  */
01149   __mach_port_deallocate (__mach_task_self (), refport);
01150 
01151   return 0;
01152 }
01153 
01154 /* Implement the sig_post RPC from <hurd/msg.defs>;
01155    sent when someone wants us to get a signal.  */
01156 kern_return_t
01157 _S_msg_sig_post (mach_port_t me,
01158                mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
01159                int signo, natural_t sigcode,
01160                mach_port_t refport)
01161 {
01162   error_t err;
01163   struct hurd_signal_detail d;
01164 
01165   if (err = signal_allowed (signo, refport))
01166     return err;
01167 
01168   d.code = sigcode;
01169   d.exc = 0;
01170 
01171   /* Post the signal to the designated signal-receiving thread.  This will
01172      reply when the signal can be considered delivered.  */
01173   _hurd_internal_post_signal (_hurd_thread_sigstate (_hurd_sigthread),
01174                            signo, &d, reply_port, reply_port_type,
01175                            0); /* Stop if traced.  */
01176 
01177   return MIG_NO_REPLY;             /* Already replied.  */
01178 }
01179 
01180 /* Implement the sig_post_untraced RPC from <hurd/msg.defs>;
01181    sent when the debugger wants us to really get a signal
01182    even if we are traced.  */
01183 kern_return_t
01184 _S_msg_sig_post_untraced (mach_port_t me,
01185                        mach_port_t reply_port,
01186                        mach_msg_type_name_t reply_port_type,
01187                        int signo, natural_t sigcode,
01188                        mach_port_t refport)
01189 {
01190   error_t err;
01191   struct hurd_signal_detail d;
01192 
01193   if (err = signal_allowed (signo, refport))
01194     return err;
01195 
01196   d.code = sigcode;
01197   d.exc = 0;
01198 
01199   /* Post the signal to the designated signal-receiving thread.  This will
01200      reply when the signal can be considered delivered.  */
01201   _hurd_internal_post_signal (_hurd_thread_sigstate (_hurd_sigthread),
01202                            signo, &d, reply_port, reply_port_type,
01203                            1); /* Untraced flag. */
01204 
01205   return MIG_NO_REPLY;             /* Already replied.  */
01206 }
01207 
01208 extern void __mig_init (void *);
01209 
01210 #include <mach/task_special_ports.h>
01211 
01212 /* Initialize the message port and _hurd_sigthread and start the signal
01213    thread.  */
01214 
01215 void
01216 _hurdsig_init (const int *intarray, size_t intarraysize)
01217 {
01218   error_t err;
01219   vm_size_t stacksize;
01220   struct hurd_sigstate *ss;
01221 
01222   __mutex_init (&_hurd_siglock);
01223 
01224   err = __mach_port_allocate (__mach_task_self (),
01225                            MACH_PORT_RIGHT_RECEIVE,
01226                            &_hurd_msgport);
01227   assert_perror (err);
01228 
01229   /* Make a send right to the signal port.  */
01230   err = __mach_port_insert_right (__mach_task_self (),
01231                               _hurd_msgport,
01232                               _hurd_msgport,
01233                               MACH_MSG_TYPE_MAKE_SEND);
01234   assert_perror (err);
01235 
01236   /* Initialize the main thread's signal state.  */
01237   ss = _hurd_self_sigstate ();
01238 
01239   /* Copy inherited values from our parent (or pre-exec process state)
01240      into the signal settings of the main thread.  */
01241   if (intarraysize > INIT_SIGMASK)
01242     ss->blocked = intarray[INIT_SIGMASK];
01243   if (intarraysize > INIT_SIGPENDING)
01244     ss->pending = intarray[INIT_SIGPENDING];
01245   if (intarraysize > INIT_SIGIGN && intarray[INIT_SIGIGN] != 0)
01246     {
01247       int signo;
01248       for (signo = 1; signo < NSIG; ++signo)
01249        if (intarray[INIT_SIGIGN] & __sigmask(signo))
01250          ss->actions[signo].sa_handler = SIG_IGN;
01251     }
01252 
01253   /* Set the default thread to receive task-global signals
01254      to this one, the main (first) user thread.  */
01255   _hurd_sigthread = ss->thread;
01256 
01257   /* Start the signal thread listening on the message port.  */
01258 
01259   if (__hurd_threadvar_stack_mask == 0)
01260     {
01261       err = __thread_create (__mach_task_self (), &_hurd_msgport_thread);
01262       assert_perror (err);
01263 
01264       stacksize = __vm_page_size * 8; /* Small stack for signal thread.  */
01265       err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread,
01266                              _hurd_msgport_receive,
01267                              (vm_address_t *) &__hurd_sigthread_stack_base,
01268                              &stacksize);
01269       assert_perror (err);
01270 
01271       __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize;
01272       __hurd_sigthread_variables =
01273        malloc (__hurd_threadvar_max * sizeof (unsigned long int));
01274       if (__hurd_sigthread_variables == NULL)
01275        __libc_fatal ("hurd: Can't allocate threadvars for signal thread\n");
01276       memset (__hurd_sigthread_variables, 0,
01277              __hurd_threadvar_max * sizeof (unsigned long int));
01278       __hurd_sigthread_variables[_HURD_THREADVAR_LOCALE]
01279        = (unsigned long int) &_nl_global_locale;
01280 
01281       /* Reinitialize the MiG support routines so they will use a per-thread
01282         variable for the cached reply port.  */
01283       __mig_init ((void *) __hurd_sigthread_stack_base);
01284 
01285       err = __thread_resume (_hurd_msgport_thread);
01286       assert_perror (err);
01287     }
01288   else
01289     {
01290       /* When cthreads is being used, we need to make the signal thread a
01291          proper cthread.  Otherwise it cannot use mutex_lock et al, which
01292          will be the cthreads versions.  Various of the message port RPC
01293          handlers need to take locks, so we need to be able to call into
01294          cthreads code and meet its assumptions about how our thread and
01295          its stack are arranged.  Since cthreads puts it there anyway,
01296          we'll let the signal thread's per-thread variables be found as for
01297          any normal cthread, and just leave the magic __hurd_sigthread_*
01298          values all zero so they'll be ignored.  */
01299 #pragma weak cthread_fork
01300 #pragma weak cthread_detach
01301       cthread_detach (cthread_fork ((cthread_fn_t) &_hurd_msgport_receive, 0));
01302 
01303       /* XXX We need the thread port for the signal thread further on
01304          in this thread (see hurdfault.c:_hurdsigfault_init).
01305          Therefore we block until _hurd_msgport_thread is initialized
01306          by the newly created thread.  This really shouldn't be
01307          necessary; we should be able to fetch the thread port for a
01308          cthread from here.  */
01309       while (_hurd_msgport_thread == 0)
01310        __swtch_pri (0);
01311     }
01312 
01313   /* Receive exceptions on the signal port.  */
01314 #ifdef TASK_EXCEPTION_PORT
01315   __task_set_special_port (__mach_task_self (),
01316                         TASK_EXCEPTION_PORT, _hurd_msgport);
01317 #elif defined (EXC_MASK_ALL)
01318   __task_set_exception_ports (__mach_task_self (),
01319                            EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
01320                                           | EXC_MASK_MACH_SYSCALL
01321                                           | EXC_MASK_RPC_ALERT),
01322                            _hurd_msgport,
01323                            EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
01324 #else
01325 # error task_set_exception_port?
01326 #endif
01327 
01328   /* Sanity check.  Any pending, unblocked signals should have been
01329      taken by our predecessor incarnation (i.e. parent or pre-exec state)
01330      before packing up our init ints.  This assert is last (not above)
01331      so that signal handling is all set up to handle the abort.  */
01332   assert ((ss->pending &~ ss->blocked) == 0);
01333 }
01334                            /* XXXX */
01335 /* Reauthenticate with the proc server.  */
01336 
01337 static void
01338 reauth_proc (mach_port_t new)
01339 {
01340   mach_port_t ref, ignore;
01341 
01342   ref = __mach_reply_port ();
01343   if (! HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
01344                      __proc_reauthenticate (port, ref,
01345                                          MACH_MSG_TYPE_MAKE_SEND) ||
01346                      __auth_user_authenticate (new, ref,
01347                                            MACH_MSG_TYPE_MAKE_SEND,
01348                                            &ignore))
01349       && ignore != MACH_PORT_NULL)
01350     __mach_port_deallocate (__mach_task_self (), ignore);
01351   __mach_port_destroy (__mach_task_self (), ref);
01352 
01353   /* Set the owner of the process here too. */
01354   mutex_lock (&_hurd_id.lock);
01355   if (!_hurd_check_ids ())
01356     HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC],
01357                  __proc_setowner (port,
01358                                 (_hurd_id.gen.nuids
01359                                  ? _hurd_id.gen.uids[0] : 0),
01360                                 !_hurd_id.gen.nuids));
01361   mutex_unlock (&_hurd_id.lock);
01362 
01363   (void) &reauth_proc;             /* Silence compiler warning.  */
01364 }
01365 text_set_element (_hurd_reauth_hook, reauth_proc);
01366 
01367 /* Like `getenv', but safe for the signal thread to run.
01368    If the environment is trashed, this will just return NULL.  */
01369 
01370 const char *
01371 _hurdsig_getenv (const char *variable)
01372 {
01373   if (__libc_enable_secure)
01374     return NULL;
01375 
01376   if (_hurdsig_catch_memory_fault (__environ))
01377     /* We bombed in getenv.  */
01378     return NULL;
01379   else
01380     {
01381       const size_t len = strlen (variable);
01382       char *value = NULL;
01383       char *volatile *ep = __environ;
01384       while (*ep)
01385        {
01386          const char *p = *ep;
01387          _hurdsig_fault_preemptor.first = (long int) p;
01388          _hurdsig_fault_preemptor.last = VM_MAX_ADDRESS;
01389          if (! strncmp (p, variable, len) && p[len] == '=')
01390            {
01391              size_t valuelen;
01392              p += len + 1;
01393              valuelen = strlen (p);
01394              _hurdsig_fault_preemptor.last = (long int) (p + valuelen);
01395              value = malloc (++valuelen);
01396              if (value)
01397               memcpy (value, p, valuelen);
01398              break;
01399            }
01400          _hurdsig_fault_preemptor.first = (long int) ++ep;
01401          _hurdsig_fault_preemptor.last = (long int) (ep + 1);
01402        }
01403       _hurdsig_end_catch_fault ();
01404       return value;
01405     }
01406 }