home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / glibc-1.06 / hurd / hurdsig.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-26  |  15.4 KB  |  571 lines

  1. /* Copyright (C) 1991, 1992, 1993 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 <hurd.h>
  20. #include <gnu-stabs.h>
  21.  
  22. struct mutex _hurd_siglock;
  23. int _hurd_stopped;
  24.  
  25. /* Port that receives signals and other miscellaneous messages.  */
  26. mach_port_t _hurd_msgport;
  27.  
  28. /* Thread listening on it.  */
  29. thread_t _hurd_msgport_thread;
  30.  
  31. /* Thread which receives task-global signals.  */
  32. thread_t _hurd_sigthread;
  33.  
  34. /* Linked-list of per-thread signal state.  */
  35. struct _hurd_sigstate *_hurd_sigstates;
  36.  
  37. struct _hurd_sigstate *
  38. _hurd_thread_sigstate (thread_t thread)
  39. {
  40.   struct _hurd_sigstate *ss;
  41.   __mutex_lock (&_hurd_siglock);
  42.   for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
  43.     if (ss->thread == thread)
  44.       break;
  45.   if (ss == NULL)
  46.     {
  47.       ss = calloc (1, sizeof (*ss)); /* Zero-initialized.  */
  48.       if (ss == NULL)
  49.     __libc_fatal ("hurd: Can't allocate thread sigstate\n");
  50.       ss->thread = thread;
  51.       __mutex_init (&ss->lock);
  52.       ss->next = _hurd_sigstates;
  53.       _hurd_sigstates = ss;
  54.     }
  55.   __mutex_lock (&ss->lock);
  56.   __mutex_unlock (&_hurd_siglock);
  57.   return ss;
  58. }
  59.  
  60. #include <hurd/core.h>
  61.  
  62. /* Limit on size of core files.  */
  63. int _hurd_core_limit;
  64.  
  65. /* Call the core server to mummify us before we die.
  66.    Returns nonzero if a core file was written.  */
  67. static int
  68. write_corefile (int signo, int sigcode)
  69. {
  70.   error_t err;
  71.   mach_port_t coreserver;
  72.   file_t file;
  73.   char *name;
  74.   char *target;
  75.  
  76.   if (_hurd_core_limit == 0)
  77.     /* User doesn't want a core.  */
  78.     return 0;
  79.  
  80.   coreserver = MACH_PORT_NULL;
  81.   if (!setjmp (_hurd_sigthread_fault_env))
  82.     {
  83.       name = getenv ("CORESERVER");
  84.       if (name != NULL)
  85.     coreserver = __path_lookup (name, 0, 0);
  86.     }
  87.  
  88.   if (coreserver == MACH_PORT_NULL)
  89.     coreserver = __path_lookup (_SERVERS_CORE, 0, 0);
  90.   if (coreserver == MACH_PORT_NULL)
  91.     return 0;
  92.  
  93.   file = MACH_PORT_NULL;
  94.   if (!setjmp (_hurd_sigthread_fault_env))
  95.     {
  96.       name = getenv ("COREFILE");
  97.       if (name != NULL)
  98.     file = __path_lookup (name, FS_LOOKUP_WRITE|FS_LOOKUP_CREATE,
  99.                   0666 & ~_hurd_umask);
  100.     }
  101.   if (name == NULL || file == MACH_PORT_NULL)
  102.     {
  103.       name = "core";
  104.       file = __path_lookup (name, FS_LOOKUP_WRITE|FS_LOOKUP_CREATE,
  105.                 0666 & ~_hurd_umask);
  106.     }
  107.  
  108.   if (file == MACH_PORT_NULL)
  109.     return 0;
  110.  
  111.   if (setjmp (_hurd_sigthread_fault_env))
  112.     /* We bombed in getenv.  */
  113.     target = NULL;
  114.   else
  115.     {
  116.       target = getenv ("GNUTARGET");
  117.       /* Fault now if TARGET is a bogus string.  */
  118.       (void) strlen (target)
  119.     }
  120.  
  121.   err = __core_dump_task (coreserver,
  122.               __mach_task_self (),
  123.               file,
  124.               signo, sigcode,
  125.               target);
  126.   __mach_port_deallocate (__mach_task_self (), coreserver);
  127.   if (!err && _hurd_core_limit != RLIM_INFINITY)
  128.     {
  129.       io_statbuf_t stb;
  130.       err = __io_stat (file, &stb);
  131.       if (!err && stb.stb_size > _hurd_core_limit)
  132.     err = EFBIG;
  133.     }
  134.   __mach_port_deallocate (__mach_task_self (), file);
  135.   if (err)
  136.     (void) remove (name);
  137.   return !err;
  138. }
  139.  
  140.  
  141. extern const size_t _hurd_thread_state_count;
  142.  
  143. /* How long to give servers to respond to
  144.    interrupt_operation before giving up on them.  */
  145. mach_msg_timeout_t _hurd_interrupt_timeout = 1000; /* One second.  */
  146.  
  147. /* SS->thread is suspended.  Fills STATE in with its registers.
  148.    SS->lock is held and kept.  */
  149. static inline void
  150. abort_rpcs (struct _hurd_sigstate *ss, int signo, void *state)
  151. {
  152.   if (ss->intr_port != MACH_PORT_NULL)
  153.     {
  154.       /* Abort whatever the thread is doing.
  155.      If it is in the mach_msg syscall doing the send,
  156.      the syscall will return MACH_SEND_INTERRUPTED.  */
  157.       __thread_abort (ss->thread);
  158.       _hurd_thread_state (ss->thread, state);
  159.  
  160.       if (_hurd_thread_msging_p (state))
  161.     {
  162.       /* The thread was waiting for the RPC to return.
  163.          Abort the operation.  The RPC will return EINTR.  */
  164.  
  165.       struct
  166.         {
  167.           mach_msg_header_t header;
  168.           mach_msg_type_t type;
  169.           kern_return_t retcode;
  170.         } msg;
  171.       kern_return_t err;
  172.  
  173.       msg.header.msgh_request_port = ss->intr_port;
  174.       msg.header.msgh_reply_port = __mach_reply_port ();
  175.       msg.header.msgh_seqno = 0;
  176.       msg.header.msgh_id = 33000; /* interrupt_operation XXX */
  177.       err = __mach_msg (&msg.header,
  178.                 MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_TIMEOUT,
  179.                 sizeof (msg.header), sizeof (msg),
  180.                 msg.header.msgh_reply_port,
  181.                 _hurd_interrupt_timeout,
  182.                 MACH_PORT_NULL);
  183.       if (err != MACH_MSG_SUCCESS)
  184.         /* The interrupt didn't work.
  185.            Destroy the receive right the thread is blocked on.  */
  186.         __mach_port_destroy (__mach_task_self (),
  187.                  /* XXX */
  188.                  _hurd_thread_reply_port (ss->thread));
  189.       else
  190.         /* In case the server returned something screwy.  */
  191.         __mach_msg_destroy (&msg.header);
  192.  
  193.       /* Tell the thread whether it should restart the
  194.          operation or return EINTR when it wakes up.  */
  195.       ss->intr_restart = ss->actions[signo].sa_flags & SA_RESTART;
  196.     }
  197.  
  198.       /* If the thread is anywhere before the system call trap,
  199.      it will start the operation after the signal is handled.
  200.      
  201.      If the thread is after the system call trap, but before it has
  202.      cleared SS->intr_port, the operation is already finished.  */
  203.     }
  204. }
  205.  
  206. /* Abort the RPCs being run by all threads but this one;
  207.    all other threads should be suspended.  */
  208. static inline void
  209. abort_all_rpcs (int signo, void *state)
  210. {
  211.   thread_t me = __mach_thread_self ();
  212.   thread_t *threads;
  213.   size_t nthreads, i;
  214.  
  215.   __task_threads (__mach_task_self (), &threads, &nthreads);
  216.   for (i = 0; i < nthreads; ++i)
  217.     {
  218.       if (threads[i] != me)
  219.     {
  220.       struct _hurd_sigstate *ss = _hurd_thread_sigstate (*nthreads);
  221.       abort_rpcs (ss, signo, state);
  222.       __mutex_unlock (&ss->lock);
  223.     }
  224.       __mach_port_deallocate (__mach_task_self (), threads[i]);
  225.     }
  226. }
  227.  
  228.  
  229. /* Deliver a signal.
  230.    SS->lock is held on entry and released before return.  */
  231. void
  232. _hurd_internal_post_signal (struct _hurd_sigstate *ss,
  233.                 int signo,
  234.                 int sigcode,
  235.                 sigset_t *restore_blocked)
  236. {
  237.   char thread_state[_hurd_thread_state_count];
  238.   enum { stop, ignore, core, term } act;
  239.  
  240.   if (ss->actions[signo].sa_handler == SIG_DFL)
  241.     switch (signo)
  242.       {
  243.       case 0:
  244.     /* A sig_post msg with SIGNO==0 is sent to
  245.        tell us to check for pending signals.  */
  246.     act = ignore;
  247.     break;
  248.  
  249.       case SIGTTIN:
  250.       case SIGTTOU:
  251.       case SIGSTOP:
  252.       case SIGTSTP:
  253.     ss->pending &= ~sigmask (SIGCONT);
  254.     act = stop;
  255.     break;
  256.  
  257.       case SIGCONT:
  258.     ss->pending &= ~(sigmask (SIGSTOP) | sigmask (SIGTSTP) |
  259.              sigmask (SIGTTIN) | sigmask (SIGTTOU));
  260.     /* Fall through.  */
  261.       case SIGIO:
  262.       case SIGURG:
  263.       case SIGCHLD:
  264.       case SIGWINCH:
  265.     act = ignore;
  266.     break;
  267.  
  268.       case SIGQUIT:
  269.       case SIGILL:
  270.       case SIGTRAP:
  271.       case SIGIOT:
  272.       case SIGEMT:
  273.       case SIGFPE:
  274.       case SIGBUS:
  275.       case SIGSEGV:
  276.       case SIGSYS:
  277.     act = core;
  278.     break;
  279.  
  280.       default:
  281.     act = term;
  282.     break;
  283.       }
  284.   else if (ss->actions[signo].sa_handler == SIG_IGN)
  285.     act = ignore;
  286.   else
  287.     act = handle;
  288.   if (_hurd_orphaned &&
  289.       (signo == SIGTTIN || signo == SIGTTOU || signo == SIGTSTP) &&
  290.       act == stop)
  291.     {
  292.       sigcode = signo;
  293.       signo = SIGKILL;
  294.       act = term;
  295.     }
  296.  
  297.   /* Handle receipt of a blocked signal.  */
  298.   if ((__sigismember (signo, &ss->blocked) && act != ignore) ||
  299.       (signo != SIGKILL && _hurd_stopped))
  300.     {
  301.       __sigaddmember (signo, &ss->pending);
  302.       /* Save the code to be given to the handler when SIGNO is unblocked.  */
  303.       ss->sigcodes[signo] = sigcode;
  304.       act = ignore;
  305.     }
  306.  
  307.   if (restore_blocked != NULL)
  308.     ss->blocked = *restore_blocked;
  309.  
  310.   switch (act)
  311.     {
  312.     case stop:
  313.       _HURD_PORT_USE
  314.     (&_hurd_proc,
  315.      ({
  316.        /* Hold the siglock while stopping other threads to be
  317.           sure it is not held by another thread afterwards.  */
  318.        __mutex_unlock (&ss->lock);
  319.        __mutex_lock (&_hurd_siglock);
  320.        __proc_dostop (port, __mach_thread_self ());
  321.        __mutex_unlock (&_hurd_siglock);
  322.        abort_all_rpcs (signo, thread_state);
  323.        __proc_markstop (port, signo);
  324.      }));
  325.       _hurd_stopped = 1;
  326.  
  327.       __mutex_lock (&ss->lock);
  328.       if (ss->suspended)
  329.     /* There is a sigsuspend waiting.  Tell it to wake up.  */
  330.     __condition_signal (&ss->arrived);
  331.       else
  332.     __mutex_unlock (&ss->lock);
  333.     
  334.       return;
  335.  
  336.     case ignore:
  337.       break;
  338.  
  339.     case core:
  340.     case term:
  341.       _HURD_PORT_USE
  342.     (&_hurd_proc,
  343.      ({
  344.        __proc_dostop (port, __mach_thread_self ());
  345.       abort_all_rpcs (signo, thread_state);
  346.       __proc_exit (port,
  347.                (W_EXITCODE (0, signo) |
  348.             (act == core && write_corefile (signo, sigcode) ?
  349.              WCOREDUMP : 0)))
  350.       }));
  351.  
  352.     case handle:
  353.       __thread_suspend (ss->thread);
  354.       abort_rpcs (ss, signo, thread_state);
  355.       {
  356.     const sigset_t blocked = ss->blocked;
  357.     ss->blocked |= __sigmask (signo) | ss->actions[signo].sa_mask;
  358.     _hurd_run_sighandler (ss, signo, sigcode, blocked, thread_state);
  359.       }
  360.       __thread_resume (ss->thread);
  361.     }
  362.  
  363.   /* We get here only if we are handling or ignoring the signal;
  364.      otherwise we are stopped or dead by now.  We still hold SS->lock.
  365.      Check for pending signals, and loop to post them.  */
  366.   for (signo = 1; signo < NSIG; ++signo)
  367.     if (__sigismember (signo, &ss->pending))
  368.       {
  369.     __sigdelmember (signo, &ss->pending);
  370.     _hurd_internal_post_signal (ss, signo, ss->sigcodes[signo], NULL);
  371.     return;
  372.       }
  373.  
  374.   if (ss->suspended)
  375.     /* There is a sigsuspend waiting.  Tell it to wake up.  */
  376.     __condition_signal (&ss->arrived);
  377.   else
  378.     __mutex_unlock (&ss->lock);
  379. }
  380.  
  381. /* Sent when someone wants us to get a signal.  */
  382. error_t
  383. __sig_post (sigthread_t me,
  384.         mig_reply_port_t reply,
  385.         int signo,
  386.         mach_port_t refport)
  387. {
  388.   struct _hurd_sigstate *ss;
  389.  
  390.   if (signo < 0 || signo >= NSIG)
  391.     return EINVAL;
  392.  
  393.   if (refport == __mach_task_self ())
  394.     /* Can send any signal.  */
  395.     goto win;
  396.   else if (refport == _hurd_cttyport)
  397.     switch (signo)
  398.       {
  399.       case SIGINT:
  400.       case SIGQUIT:
  401.       case SIGTSTP:
  402.       case SIGHUP:
  403.     goto win;
  404.       }
  405.   else
  406.     {
  407.       static mach_port_t sessport = MACH_PORT_NULL;
  408.       if (sessport == MACH_PORT_NULL)
  409.     _HURD_PORT_USE (&_hurd_proc,
  410.             __proc_getsidport (port, &sessport));
  411.       if (sessport != MACH_PORT_NULL && refport == sessport &&
  412.       signo == SIGCONT)
  413.     goto win;
  414.     }
  415.  
  416.   /* XXX async io? */
  417.   return EPERM;
  418.  
  419.  win:
  420.   ss = _hurd_thread_sigstate (_hurd_sigthread);
  421.   __sig_post_reply (reply, 0);
  422.   _hurd_internal_post_signal (ss, signo, 0, NULL);
  423.   return MIG_NO_REPLY;        /* Already replied.  */
  424. }
  425.  
  426. /* Called by the exception handler to take a signal.  */
  427. void
  428. _hurd_exc_post_signal (thread_t thread, int signo, int sigcode)
  429. {
  430.   _hurd_internal_post_signal (_hurd_thread_sigstate (thread),
  431.                   signo, sigcode, NULL);
  432. }
  433.  
  434. #include <sysdep.h>
  435.  
  436. /* Handle signal SIGNO in the calling thread.
  437.    If SS is not NULL it is the sigstate for the calling thread;
  438.    SS->lock is held on entry and released before return.  */
  439. void
  440. _hurd_raise_signal (struct _hurd_sigstate *ss, int signo, int sigcode)
  441. {
  442.   jmp_buf env;
  443.   struct sigcontext sc;
  444.  
  445.   if (ss == NULL)
  446.     ss = _hurd_thread_sigstate (__mach_thread_self ());
  447.  
  448.   if (! setjmp (env))
  449.     {
  450.       register volatile void (*handler) (int signo, int sigcode,
  451.                      struct sigcontext *scp);
  452.  
  453.       handler = (__typeof (handler)) ss->actions[signo].sa_handler;
  454.  
  455.       /* Set up SC to make setjmp return 1.  */
  456.       _hurd_jmp_buf_sigcontext (env, &sc, 1);
  457.  
  458.       sc.sc_mask = ss->blocked;    /* Restored by sigreturn.  */
  459.       sc.sc_onstack = ((ss->actions[signo].sa_flags & SA_ONSTACK) &&
  460.                !(ss->sigaltstack.ss_flags & SA_DISABLE));
  461.       if (sc.sc_onstack)
  462.     {
  463.       /* Switch to the signal stack.  */
  464.       ss->sigaltstack.ss_flags |= SA_ONSTACK;
  465.       SET_SP (ss->sigaltstack.ss_sp);
  466.     }
  467.  
  468.       __mutex_unlock (&ss->lock);
  469.  
  470.       /* Call the handler.  */
  471.       (*handler) (signo, sigcode, &sc);
  472.  
  473.       __sigreturn (&sc);    /* Does not return.   */
  474.       LOSE;            /* Firewall.  */
  475.     }
  476. }
  477.  
  478. void
  479. _hurdsig_init (void)
  480. {
  481.   thread_t sigthread;
  482.  
  483.   __mutex_init (&_hurd_siglock);
  484.  
  485.   if (_hurd_msgport == MACH_PORT_NULL)
  486.     if (err = __mach_port_allocate (__mach_task_self (),
  487.                     MACH_PORT_RIGHT_RECEIVE,
  488.                     &_hurd_msgport))
  489.       __libc_fatal ("hurd: Can't create signal port receive right\n");
  490.  
  491.   if (err = __thread_create (__mach_task_self (), &sigthread))
  492.     __libc_fatal ("hurd: Can't create signal thread\n");
  493.   if (err = _hurd_start_sigthread (sigthread, _hurd_msgport_receive))
  494.     __libc_fatal ("hurd: Can't start signal thread\n");
  495.   _hurd_msgport_thread = sigthread;
  496.  
  497.   /* Make a send right to the signal port.  */
  498.   if (err = __mach_port_insert_right (__mach_task_self (),
  499.                       _hurd_msgport,
  500.                       MACH_PORT_RIGHT_MAKE_SEND))
  501.     __libc_fatal ("hurd: Can't create send right to signal port\n");
  502.  
  503.   /* Receive exceptions on the signal port.  */
  504.   __task_set_special_port (__mach_task_self (),
  505.                TASK_EXCEPTION,
  506.                _hurd_msgport);
  507.  
  508.   {
  509.     /* Send exceptions for the signal thread to the proc server.
  510.        It will forward the message on to our message port,
  511.        and then restore the thread's state to code which
  512.        does `longjmp (_hurd_sigthread_fault_env, 1)'.  */
  513.  
  514.     mach_port_t sigexc;
  515.     int state[_hurd_thread_state_count];
  516.     if (err = __mach_port_allocate (__mach_task_self (),
  517.                     MACH_PORT_RIGHT_RECEIVE, &sigexc))
  518.       __libc_fatal ("hurd: Can't create receive right for sigthread exc\n");
  519.     _hurd_initialize_fault_recovery_state (state);
  520.     __thread_set_special_port (sigthread, THREAD_EXCEPTION, sigexc);
  521.     if (err = HURD_PORT_USE
  522.     (&_hurd_proc,
  523.      __proc_handle_exceptions (port,
  524.                    sigexc,
  525.                    _hurd_msgport, MACH_PORT_RIGHT_COPY_SEND,
  526.                    _hurd_thread_state_flavor,
  527.                    state, _hurd_thread_state_count)))
  528.       __libc_fatal ("hurd: proc won't handle sigthread exceptions\n");
  529.   }
  530. }
  531.                 /* XXXX */
  532. struct _hurd_port _hurd_proc;
  533.  
  534. /* Make PROCSERVER be our proc server port.
  535.    Tell the proc server that we exist.  */
  536.  
  537. void
  538. _hurd_proc_init (process_t procserver, char **argv)
  539. {
  540.   mach_port_t oldsig, oldtask;
  541.  
  542.   _hurd_port_init (&_hurd_proc, procserver);
  543.  
  544.   /* Tell the proc server where our args and environment are.  */
  545.   __proc_setprocargs (procserver, argv, __environ);
  546.  
  547.   /* Initialize the signal code; Mach exceptions will become signals.
  548.      This sets _hurd_msgport; it must be run before _hurd_proc_init.  */
  549.   _hurdsig_init ();
  550.  
  551.   /* Give the proc server our task and signal ports.  */
  552.   __proc_setports (procserver,
  553.            _hurd_msgportG, __mach_task_self (),
  554.            &oldsig, &oldtask);
  555.   if (oldsig != MACH_PORT_NULL)
  556.     __mach_port_deallocate (__mach_task_self (), oldsig);
  557.   if (oldtask != MACH_PORT_NULL)
  558.     __mach_port_deallocate (__mach_task_self (), oldtask);
  559. }
  560.  
  561. static void
  562. reauth_proc (mach_port_t new)
  563. {
  564.   /* Reauthenticate with the proc server.  */
  565.   if (! _HURD_PORT_USE (&_hurd_proc,
  566.             __proc_reauthenticate (port) ||
  567.             __auth_user_authenticate (new, port, &ignore))
  568.       && ignore != MACH_PORT_NULL)
  569.     __mach_port_deallocate (__mach_task_self (), ignore);
  570. }
  571.