home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 036 / emxfix02.zip / emx / src / os2 / signal.c < prev    next >
C/C++ Source or Header  |  1994-12-21  |  30KB  |  1,142 lines

  1. /* signal.c -- Manage signals and exceptions
  2.    Copyright (c) 1994 by Eberhard Mattes
  3.  
  4. This file is part of emx.
  5.  
  6. emx is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. emx is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with emx; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20. As special exception, emx.dll can be distributed without source code
  21. unless it has been changed.  If you modify emx.dll, this exception
  22. no longer applies and you must remove this paragraph from all source
  23. files for emx.dll.  */
  24.  
  25.  
  26. #define INCL_DOSEXCEPTIONS
  27. #define INCL_DOSPROCESS
  28. #define INCL_DOSSEMAPHORES
  29. #define INCL_DOSDATETIME
  30. #define INCL_DOSMISC
  31. #define INCL_DOSERRORS
  32. #include <os2emx.h>
  33. #include "wrapper.h"
  34. #include <sys/emx.h>
  35. #include <sys/signal.h>
  36. #include <sys/errno.h>
  37. #include "emxdll.h"
  38.  
  39. #define SIGF_CORE               0x01
  40.  
  41. /* TODO: SIGSTOP */
  42. #define SET_BLOCKED(td,set) ((td)->sig_blocked = (set) & ~_SIGMASK (SIGKILL))
  43.  
  44.  
  45. /* This structure describes a signal. */
  46.  
  47. struct signal_descr
  48. {
  49.   const char *name;             /* Name of the signal */
  50.   BYTE dfl_action;              /* Action for SIG_DFL */
  51.   BYTE fun_action;              /* Action taken after function */
  52.   BYTE flags;                   /* Flags (SIGF_CORE) */
  53. };
  54.  
  55.  
  56. /* Inhibit core dumps. */
  57.  
  58. BYTE nocore_flag;
  59.  
  60. /* Don't display harderror popups.  This is done by terminating the
  61.    process instead of returning XCPT_CONTINUE_SEARCH from the
  62.    exception handler. */
  63.  
  64. BYTE no_popup;
  65.  
  66. /* Event semaphore for temporarily blocked signal. */
  67.  
  68. HEV signal_sem;
  69.  
  70. /* This flag is set when a temporarily blocked signal is generated. */
  71.  
  72. char sig_flag;
  73.  
  74. /* When exec() is called in a forked process, we pass on signals to
  75.    the child process until it terminates.  This variable holds the
  76.    process ID of the child process.  If the value is zero, there is no
  77.    such child process. */
  78.  
  79. ULONG fork_exec_pid;
  80.  
  81. /* Critical sections for signal processing are protected by this Mutex
  82.    semaphore. */
  83.  
  84. static HMTX sig_access;
  85.  
  86.  
  87. /* 16-bit signal handler. */
  88.  
  89. extern _far16ptr old_sig16_handler;
  90. extern void (*sig16_handler)(void);
  91.  
  92. #define ST_TERM   0             /* Terminate process (SIGINT for instance) */
  93. #define ST_NEXT   1             /* Pass on to next exception handler */
  94. #define ST_IGNORE 2             /* Ignore exception and continue thread */
  95.  
  96.  
  97. /* This array contains TRUE for all valid signal numbers. */
  98.  
  99. char const signal_valid[NSIG] =
  100. {
  101.   FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,  /* 0..9 */
  102.   TRUE,  TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, /* 10..19 */
  103.   FALSE, TRUE                                                   /* 20..21 */
  104. };
  105.  
  106. /* This array contains constant information about the signals: The
  107.    name of the signal, what to do for SIG_DFL and SIG_IGN and whether
  108.    to dump core or not. */
  109.  
  110. static struct signal_descr const signal_info[NSIG] =
  111. {
  112.   {"SIG0",     ST_TERM,   ST_TERM,   0},
  113.   {"SIGHUP",   ST_TERM,   ST_IGNORE, 0},
  114.   {"SIGINT",   ST_TERM,   ST_IGNORE, 0},
  115.   {"SIGQUIT",  ST_TERM,   ST_IGNORE, SIGF_CORE},
  116.   {"SIGILL",   ST_NEXT,   ST_NEXT,   SIGF_CORE},
  117.   {"SIGTRAP",  ST_NEXT,   ST_NEXT,   SIGF_CORE},
  118.   {"SIGABRT",  ST_TERM,   ST_TERM,   SIGF_CORE},
  119.   {"SIGEMT",   ST_TERM,   ST_TERM,   SIGF_CORE},
  120.   {"SIGFPE",   ST_NEXT,   ST_NEXT,   SIGF_CORE},
  121.   {"SIGKILL",  ST_TERM,   ST_TERM,   0},
  122.   {"SIGBUS",   ST_TERM,   ST_TERM,   SIGF_CORE},
  123.   {"SIGSEGV",  ST_NEXT,   ST_NEXT,   SIGF_CORE},
  124.   {"SIGSYS",   ST_TERM,   ST_TERM,   SIGF_CORE},
  125.   {"SIGPIPE",  ST_TERM,   ST_IGNORE, 0},
  126.   {"SIGALRM",  ST_TERM,   ST_IGNORE, 0},
  127.   {"SIGTERM",  ST_NEXT,   ST_NEXT,   0},
  128.   {"SIGUSR1",  ST_IGNORE, ST_IGNORE, 0},
  129.   {"SIGUSR2",  ST_IGNORE, ST_IGNORE, 0},
  130.   {"SIGCLD",   ST_IGNORE, ST_IGNORE, 0},
  131.   {"SIG19",    ST_TERM,   ST_TERM,   0},
  132.   {"SIG20",    ST_TERM,   ST_TERM,   0},
  133.   {"SIGBREAK", ST_TERM,   ST_IGNORE, 0}
  134. };
  135.  
  136.  
  137. /* Prototypes. */
  138.  
  139. static ULONG kill_emx (int pid, int signo, int tree);
  140.  
  141.  
  142. /* Display a message when terminating a process due to signal
  143.    SIGNO. */
  144.  
  145. static void signal_message (int signo)
  146. {
  147.   if (signo == SIGABRT)
  148.     otext ("\r\nAbnormal program termination\r\n");
  149.   else
  150.     oprintf ("\r\nProcess terminated by %s\r\n", signal_info[signo].name);
  151. }
  152.  
  153.  
  154. static void sig_lock (void)
  155. {
  156.   ULONG count;
  157.  
  158.   DosEnterMustComplete (&count);
  159.   request_mutex (sig_access);
  160. }
  161.  
  162.  
  163. static void sig_unlock (void)
  164. {
  165.   ULONG count;
  166.  
  167.   DosReleaseMutexSem (sig_access);
  168.   DosExitMustComplete (&count);
  169. }
  170.  
  171.  
  172. /* Acknowledge the signal to OS/2. */
  173.  
  174. static void acknowledge (int signo)
  175. {
  176.   switch (signo)
  177.     {
  178.     case SIGINT:
  179.       DosAcknowledgeSignalException (XCPT_SIGNAL_INTR);
  180.       break;
  181.     case SIGTERM:
  182.       DosAcknowledgeSignalException (XCPT_SIGNAL_KILLPROC);
  183.       break;
  184.     case SIGBREAK:
  185.       DosAcknowledgeSignalException (XCPT_SIGNAL_BREAK);
  186.       break;
  187.     }
  188. }
  189.  
  190.  
  191. static void acknowledge_mult (ULONG set)
  192. {
  193.   if (set & _SIGMASK (SIGINT))
  194.     acknowledge (SIGINT);
  195.   if (set & _SIGMASK (SIGBREAK))
  196.     acknowledge (SIGBREAK);
  197.   if (set & _SIGMASK (SIGKILL))
  198.     acknowledge (SIGKILL);
  199. }
  200.  
  201.  
  202. /* Generate a signal. */
  203.  
  204. void generate_signal (thread_data *td, int signo)
  205. {
  206.   struct signal_entry *p;
  207.  
  208.   sig_lock ();
  209.   p = td->sig_table + signo;
  210.   if (p->handler != SIG_IGN)
  211.     {
  212.       td->sig_pending |= _SIGMASK (signo);
  213.       if ((td->sig_blocked & ~td->sig_prev_blocked & _SIGMASK (signo))
  214.           && p->handler != SIG_DFL)
  215.         {
  216.           /* Wake up __select() */
  217.  
  218.           sig_flag = TRUE;
  219.           DosPostEventSem (signal_sem);
  220.         }
  221.       if (td == threads[1] && get_tid () != 1)
  222.         {
  223.           /* Interrupt thread 1 and let it examine its set of pending
  224.              signals. */
  225.  
  226.           DosFlagProcess (my_pid, FLGP_PID, PFLG_A, 0);
  227.         }
  228.     }
  229.   sig_unlock ();
  230. }
  231.  
  232.  
  233. static void regen_sigcld (int lock)
  234. {
  235.   if (lock) sig_lock ();
  236.   if (zombie_count > 0)
  237.     threads[1]->sig_pending |= _SIGMASK (SIGCLD);
  238.   if (lock) sig_unlock ();
  239. }
  240.  
  241.  
  242. /* Terminate the process.  Optionally do a core dump, taking the
  243.    registers from the syscall stack frame or the exception context
  244.    record.  Actually, the process is not terminated by this function
  245.    if CONTEXT_RECORD is non-NULL and no_popup is false. */
  246.  
  247. static void sig_terminate (int signo, syscall_frame *frame,
  248.                            CONTEXTRECORD *context_record)
  249. {
  250.   signal_message (signo);
  251.  
  252.   if (signo == SIGKILL
  253.       || (!nocore_flag && (signal_info[signo].flags & SIGF_CORE)))
  254.     {
  255.       if (frame != NULL)
  256.         {
  257.           core_regs_i (frame);
  258.           core_dump ();
  259.         }
  260.       else if (context_record != NULL)
  261.         {
  262.           core_regs_e (context_record);
  263.           core_dump ();
  264.         }
  265.     }
  266.   if (context_record == NULL || no_popup)
  267.     quit (3);
  268. }
  269.  
  270.  
  271. /* Deliver a signal.  FRAME points to the system call stack frame,
  272.    CONTEXT_RECORD points to the exception context record.  This
  273.    function must be called with sig_lock() in effect; sig_unlock() is
  274.    called by this function.
  275.  
  276.    Return ST_TERM, ST_IGNORE, or ST_NEXT. */
  277.  
  278. static int deliver_signal (thread_data *td, int signo,
  279.                            syscall_frame *frame,
  280.                            CONTEXTRECORD *context_record)
  281. {
  282.   struct signal_entry *p;
  283.   void (*handler)(int signo);
  284.   ULONG mask, old_blocked;
  285.  
  286.   mask = _SIGMASK (signo);
  287.   p = td->sig_table + signo;
  288.  
  289.   td->sig_pending &= ~mask;
  290.   handler = p->handler;
  291.  
  292.   if (handler == SIG_IGN)
  293.     {
  294.       /* Ignore the signal. */
  295.  
  296.       sig_unlock ();
  297.     }
  298.   else if (handler == SIG_DFL)
  299.     {
  300.       /* If the default handler SIG_DFL is installed, check the signal
  301.          information table to learn whether to ignore the signal or to
  302.          terminate the process. */
  303.  
  304.       sig_unlock ();
  305.       if (signal_info[signo].dfl_action != ST_IGNORE)
  306.         {
  307.           sig_terminate (signo, frame, context_record);
  308.           return (signal_info[signo].dfl_action);
  309.         }
  310.     }
  311.   else
  312.     {
  313.       /* Call the user-defined signal handler. */
  314.  
  315.       if (p->sa_flags & SA_SYSV)
  316.         {
  317.           p->handler = SIG_DFL;
  318.           sig_unlock ();
  319.           handler (signo);
  320.         }
  321.       else if (p->sa_flags & SA_ACK)
  322.         {
  323.           td->sig_blocked |= mask;
  324.           sig_unlock ();
  325.           handler (signo);
  326.         }
  327.       else
  328.         {
  329.           old_blocked = td->sig_blocked;
  330.           SET_BLOCKED (td, td->sig_blocked | mask | p->sa_mask);
  331.           sig_unlock ();
  332.           handler (signo);
  333.           td->sig_blocked = old_blocked;
  334.         }
  335.       if (signo == SIGCLD && td == threads[1])
  336.         regen_sigcld (TRUE);
  337.  
  338.       /* Check the signal information table to learn whether to
  339.          continue the program or to terminate the process.  This is
  340.          only done when called from an exception handler. */
  341.  
  342.       if (context_record != NULL && signal_info[signo].fun_action != ST_IGNORE)
  343.         {
  344.           sig_terminate (signo, frame, context_record);
  345.           return (signal_info[signo].fun_action);
  346.         }
  347.     }
  348.   return (ST_IGNORE);
  349. }
  350.  
  351.  
  352. /* Deliver all pending signals. */
  353.  
  354. int deliver_pending_signals (thread_data *td, syscall_frame *frame,
  355.                               CONTEXTRECORD *context_record)
  356. {
  357.   int signo, action;
  358.  
  359.   sig_lock ();
  360.   while ((td->sig_pending & ~td->sig_blocked) != 0)
  361.     {
  362.       for (signo = 1; signo < NSIG; ++signo)
  363.         if (td->sig_pending & ~td->sig_blocked & _SIGMASK (signo))
  364.           {
  365.             action = deliver_signal (td, signo, frame, context_record);
  366.             if (action != ST_IGNORE)
  367.               return (action);
  368.             sig_lock ();
  369.           }
  370.     }
  371.   sig_unlock ();
  372.   return (ST_IGNORE);
  373. }
  374.  
  375.  
  376. /* This function is called from the 16-bit signal handler to generate
  377.    signal SIGNO (if SIGNO is non-zero) and to deliver pending
  378.    signals. */
  379.  
  380. void raise_from_16 (int signo)
  381. {
  382.   if (fork_exec_pid != 0)
  383.     kill_emx (fork_exec_pid, signo, FALSE);
  384.   else
  385.     {
  386.       if (signo != 0)
  387.         generate_signal (threads[1], signo);
  388.       deliver_pending_signals (threads[1], NULL, NULL);
  389.     }
  390. }
  391.  
  392.  
  393. /* Unblock temporarily blocked signals, raise pending signals. */
  394.  
  395. void sig_block_end (void)
  396. {
  397.   thread_data *td;
  398.  
  399.   td = get_thread ();
  400.   sig_lock ();
  401.   td->sig_blocked = td->sig_prev_blocked;
  402.   td->sig_prev_blocked = 0;
  403.   sig_unlock ();
  404.   deliver_pending_signals (td, NULL, NULL);
  405. }
  406.  
  407.  
  408. /* Temporarily block signals (for the duration of a system call).
  409.    From now on, no signals will be raised.  Instead, generated signals
  410.    will be made pending. */
  411.  
  412. void sig_block_start (void)
  413. {
  414.   thread_data *td;
  415.  
  416.   td = get_thread ();
  417.   sig_lock ();
  418.   sig_flag = FALSE;
  419.   reset_event_sem (signal_sem); /* select() waits for this semaphore */
  420.   td->sig_prev_blocked = td->sig_blocked;
  421.   SET_BLOCKED (td, ~0);
  422.   sig_unlock ();
  423. }
  424.  
  425.  
  426. /* Send a signal to another process (or process tree).  PID is the
  427.    process ID of the target process and SIGNO is the signal number.
  428.    Send signal to the process tree starting at PID if tree is true. */
  429.  
  430. static ULONG kill_emx (int pid, int signo, int tree)
  431. {
  432.   return (DosFlagProcess (pid, (tree ? FLGP_SUBTREE : FLGP_PID),
  433.                           PFLG_A, signo));
  434. }
  435.  
  436.  
  437. void do_raise (int signo, syscall_frame *frame)
  438. {
  439.   thread_data *td;
  440.  
  441.   td = get_thread ();
  442.   generate_signal (td, signo);
  443.   deliver_pending_signals (td, frame, NULL);
  444. }
  445.  
  446.  
  447. /* This function implements the __kill() system call.  SIGNO is the
  448.    signal number (or 0 to check whether the target process is alive).
  449.    PID is the process ID of the target process.  Store the error
  450.    number (errno) to *ERRNOP.  Return 0 on success, -1 on failure. */
  451.  
  452. int do_kill (int signo, int pid, syscall_frame *frame, int *errnop)
  453. {
  454.   ULONG rc;
  455.   int org_pid;
  456.  
  457.   /* Check whether process PID is alive if SIGNO is 0. */
  458.  
  459.   if (signo == 0)
  460.     {
  461.       if (proc_check (pid))
  462.         {
  463.           /* The process is alive. */
  464.  
  465.           *errnop = 0;
  466.           return (0);
  467.         }
  468.  
  469.       /* The process does not exist. */
  470.  
  471.       *errnop = ESRCH;
  472.       return (-1);
  473.     }
  474.  
  475.   /* Fail if SIGNO is not a valid signal number. */
  476.  
  477.   if (signo < 0 || signo >= NSIG || !signal_valid[signo])
  478.     {
  479.       *errnop = EINVAL;
  480.       return (-1);
  481.     }
  482.  
  483.   /* Map `kill(getpid(),signo)' to `raise(signo)' to enable core
  484.      dumps.  Do this only for the main thread as kill() is defined
  485.      (for emx) to send the signal to the main thread. */
  486.  
  487.   if (pid == my_pid && get_tid () == 1)
  488.     {
  489.       do_raise (signo, frame);
  490.       *errnop = 0;
  491.       return (0);
  492.     }
  493.  
  494.   /* Save the original process or group ID and turn a group ID (PID is
  495.      negative) into a process ID. */
  496.  
  497.   org_pid = pid;
  498.   if (pid < -1)                 /* Process group? */
  499.     pid = -pid;                 /* Yes: compute PID from group ID */
  500.  
  501.   /* SIGKILL is treated specially: Call DosKillProcess. */
  502.  
  503.   if (signo == SIGKILL)
  504.     {
  505.       /* When sending SIGKILL to a process group, first try to kill
  506.          the process tree.  If this fails, kill only one process.
  507.          When sending SIGKILL to a single process, kill only that
  508.          process. */
  509.  
  510.       if (org_pid < -1)
  511.         {
  512.           rc = DosKillProcess (DKP_PROCESSTREE, pid);
  513.           if (rc != 0)
  514.             rc = DosKillProcess (DKP_PROCESS, pid);
  515.         }
  516.       else
  517.         rc = DosKillProcess (DKP_PROCESS, pid);
  518.  
  519.       /* If the process has already been killed but has not yet
  520.          reacted to the signal, the return code will be
  521.          ERROR_SIGNAL_PENDING.  Ignore this error. */
  522.  
  523.       if (rc == 0 || rc == ERROR_SIGNAL_PENDING)
  524.         {
  525.           *errnop = 0;
  526.           return (0);
  527.         }
  528.       *errnop = set_error (rc);
  529.       return (-1);
  530.     }
  531.  
  532.   /* We can send SIGINT and SIGBREAK to child processes. */
  533.  
  534.   if ((signo == SIGINT || signo == SIGBREAK) && pid != my_pid)
  535.     {
  536.       rc = DosSendSignalException (pid, ((signo == SIGINT)
  537.                                          ? XCPT_SIGNAL_INTR
  538.                                          : XCPT_SIGNAL_BREAK));
  539.       if (rc == 0)
  540.         {
  541.           *errnop = 0;
  542.           return (0);
  543.         }
  544.       /* Seems not to be a child process.  Use DosFlagProcess. */
  545.     }
  546.  
  547.   /* Send the signal via a 16-bit signal (DosFlagProcess).  This works
  548.      only for emx programs. */
  549.  
  550.   if (org_pid < -1)
  551.     {
  552.       rc = kill_emx (pid, signo, TRUE);
  553.       if (rc != 0)
  554.         rc = kill_emx (pid, signo, FALSE);
  555.     }
  556.   else
  557.     rc = kill_emx (pid, signo, FALSE);
  558.   if (rc == 0)
  559.     {
  560.       *errnop = 0;
  561.       return (0);
  562.     }
  563.   *errnop = set_error (rc);
  564.   return (-1);
  565. }
  566.  
  567.  
  568. /* Set a signal handler or acknowledge a signal.  This is the main
  569.    code for the __signal() system call.  SIGNO is the signal number.
  570.    HANDLER is SIG_DFL, SIG_IGN, SIG_ACK or the address of the signal
  571.    handler to be used.  FRAME points to the syscall stack frame in
  572.    case we have to dump core.  Return the previous (or current for
  573.    SIG_ACK) signal handler or SIG_ERR on error. */
  574.  
  575. sigfun *do_signal (ULONG signo, sigfun *handler, syscall_frame *frame)
  576. {
  577.   if (handler == SIG_ACK)
  578.     {
  579.       thread_data *td;
  580.       struct signal_entry *p;
  581.       void (*result)(int signo);
  582.  
  583.       /* Acknowledge (unblock) the signal. */
  584.  
  585.       if (signo < 1 || signo >= NSIG || !signal_valid[signo])
  586.         return (SIG_ERR);
  587.  
  588.       td = get_thread ();
  589.       p = td->sig_table + signo;
  590.  
  591.       sig_lock ();
  592.       if (!(p->sa_flags & SA_ACK))
  593.         {
  594.           sig_unlock ();
  595.           return (SIG_ERR);
  596.         }
  597.       acknowledge (signo);
  598.       td->sig_blocked &= ~_SIGMASK (signo);
  599.       result = p->handler;
  600.       sig_unlock ();
  601.       deliver_pending_signals (td, frame, NULL);
  602.       return (handler);
  603.     }
  604.   else
  605.     {
  606.       struct sigaction isa, osa;
  607.  
  608.       isa.sa_handler = handler;
  609.       isa.sa_mask = 0;
  610.       switch (uflags & _UF_SIG_MODEL)
  611.         {
  612.         case _UF_SIG_SYSV:
  613.           isa.sa_flags = SA_SYSV;
  614.           break;
  615.         case _UF_SIG_EMX:
  616.           isa.sa_flags = SA_ACK;
  617.           break;
  618.         default:
  619.           isa.sa_flags = 0;
  620.           break;
  621.         }
  622.       if (do_sigaction (signo, &isa, &osa) != 0)
  623.         return (SIG_ERR);
  624.       else
  625.         return (osa.sa_handler);
  626.     }
  627. }
  628.  
  629.  
  630. /* This function implements the __sigaction() system call. */
  631.  
  632. int do_sigaction (int signo, const struct sigaction *iact,
  633.                   struct sigaction *oact)
  634. {
  635.   thread_data *td;
  636.   struct signal_entry *p;
  637.   struct sigaction output;
  638.  
  639.   /* Check the signal number. */
  640.  
  641.   if (signo < 1 || signo >= NSIG || !signal_valid[signo])
  642.     return (EINVAL);
  643.  
  644.   /* Fail if the process tries to set the action for SIGKILL.
  645.  
  646.      POSIX.1, 3.3.1.3: "The system shall not allow the action for the
  647.      signals SIGKILL or SIGSTOP to be set to SIG_IGN."
  648.  
  649.      POSIX.1, 3.3.1.3: "The system shall not allow a process to catch
  650.      the signals SIGKILL and SIGSTOP."
  651.  
  652.      POSIX.1, 3.3.4.2: "It is unspecified whether an attempt to set
  653.      the action for a signal that cannot be caught or ignored to
  654.      SIG_DFL is ignored or causes an error to be returned with errno
  655.      set to [EINVAL]." */
  656.  
  657.   if (signo == SIGKILL && iact != NULL)
  658.     return (EINVAL);
  659.  
  660.   /* Get a pointer to the thread data block and a pointer to the
  661.      signal table entry for SIGNO of the current thread. */
  662.  
  663.   td = get_thread ();
  664.   p = td->sig_table + signo;
  665.  
  666.   /* Save the previous action. */
  667.  
  668.   sig_lock ();
  669.   output.sa_handler = p->handler;
  670.   output.sa_mask = p->sa_mask;
  671.   output.sa_flags = p->sa_flags;
  672.  
  673.   /* Install new action if IACT is not NULL. */
  674.  
  675.   if (iact != NULL)
  676.     {
  677.       p->handler = iact->sa_handler;
  678.       p->sa_mask = iact->sa_mask;
  679.       p->sa_flags = iact->sa_flags;
  680.  
  681.       if ((p->handler == SIG_DFL && signal_info[signo].dfl_action != ST_IGNORE)
  682.           || p->handler == SIG_IGN)
  683.         {
  684.           /* POSIX.1, 3.3.1.3: "Setting a signal action to SIG_DFL for
  685.              a signal that is pending, and whose default action is to
  686.              ignore the signal (for example, SIGCHLD), shall cause the
  687.              pending signal to be discarded, whether or not it is
  688.              blocked."
  689.  
  690.              POSIX.1, 3.3.1.3: "Setting a signal action to SIG_IGN for
  691.              a signal that is pending shall cause the pending signal
  692.              to be discarded, whether or not it is blocked." */
  693.  
  694.           td->sig_pending &= ~_SIGMASK (signo);
  695.         }
  696.  
  697.       if ((p->sa_flags & SA_SYSV) && signo == SIGCLD)
  698.         regen_sigcld (FALSE);
  699.     }
  700.  
  701.   /* Store previous action to *OACT if OACT is not NULL.  Do this
  702.      after reading *IACT because IACT may point to the same set as
  703.      OACT. */
  704.  
  705.   if (oact != NULL)
  706.     *oact = output;
  707.  
  708.   sig_unlock ();
  709.   return (0);
  710. }
  711.  
  712.  
  713. int do_sigpending (sigset_t *set)
  714. {
  715.   thread_data *td;
  716.  
  717.   td = get_thread ();
  718.   sig_lock ();
  719.   *set = td->sig_blocked & td->sig_pending;
  720.   sig_unlock ();
  721.   return (0);
  722. }
  723.  
  724.  
  725. int do_sigprocmask (int how, const sigset_t *iset, sigset_t *oset,
  726.                     syscall_frame *frame)
  727. {
  728.   thread_data *td;
  729.   ULONG temp, output;
  730.  
  731.   td = get_thread ();
  732.   sig_lock ();
  733.   output = td->sig_blocked;
  734.   if (iset != NULL)
  735.     {
  736.       switch (how)
  737.         {
  738.         case SIG_BLOCK:
  739.           temp = td->sig_blocked | *iset;
  740.           break;
  741.         case SIG_UNBLOCK:
  742.           temp = td->sig_blocked & ~*iset;
  743.           break;
  744.         case SIG_SETMASK:
  745.           temp = *iset;
  746.           break;
  747.         default:
  748.           sig_unlock ();
  749.           return (EINVAL);
  750.         }
  751.       acknowledge_mult (td->sig_blocked & ~temp);
  752.       SET_BLOCKED (td, temp);
  753.  
  754.     }
  755.  
  756.   /* Set *OSET after reading *ISET, because ISET may point to the same
  757.      set as OSET. */
  758.  
  759.   if (oset != NULL)
  760.     *oset = output;
  761.  
  762.   /* POSIX.1, 3.3.5.2: "If there are any pending unblocked signals
  763.      after the call to the sigprocmask() function, at least one of
  764.      those signals shall be delivered before the sigprocmask()
  765.      function returns." */
  766.  
  767.   sig_unlock ();
  768.   deliver_pending_signals (td, frame, NULL);
  769.   return (0);
  770. }
  771.  
  772.  
  773. /* This function implements the __pause() system call.  Wait for the
  774.    occurance of a signal.  Signals set to SIG_IGN should not make this
  775.    function return, but they do (for now). */
  776.  
  777. void do_pause (void)
  778. {
  779.   ULONG rc;
  780.  
  781.   do
  782.     {
  783.       rc = DosSleep ((ULONG)(-1));
  784.     } while (rc == 0);
  785. }
  786.  
  787.  
  788. int do_sigsuspend (const sigset_t *mask)
  789. {
  790.   ULONG old_blocked;
  791.   thread_data *td;
  792.  
  793.   td = get_thread ();
  794.   sig_lock ();
  795.   old_blocked = td->sig_blocked;
  796.   acknowledge_mult (~*mask & td->sig_blocked);
  797.   SET_BLOCKED (td, *mask);
  798.   sig_unlock ();
  799.   do_pause ();
  800.   td->sig_blocked = old_blocked;
  801.   return (EINTR);
  802. }
  803.  
  804.  
  805. /* Raise signal SIGNO from the exception handler. */
  806.  
  807. ULONG signal_exception (int signo, CONTEXTRECORD *context)
  808. {
  809.   thread_data *td;
  810.   struct signal_entry *p;
  811.   int action;
  812.  
  813.   if (fork_exec_pid != 0)
  814.     {
  815.       kill_emx (fork_exec_pid, signo, FALSE);
  816.       acknowledge (signo);
  817.       return (XCPT_CONTINUE_EXECUTION);
  818.     }
  819.  
  820.   /* Get a pointer to the thread data block and a pointer to the
  821.      signal table entry for SIGNO of the current thread. */
  822.  
  823.   td = get_thread ();
  824.   p = td->sig_table + signo;
  825.  
  826.   if (p->handler != SIG_IGN)
  827.     {
  828.       generate_signal (td, signo);
  829.       action = deliver_pending_signals (td, NULL, context);
  830.       switch (action)
  831.         {
  832.         case ST_TERM:
  833.           quit (3);
  834.         case ST_NEXT:
  835.           acknowledge (signo);
  836.           return (XCPT_CONTINUE_SEARCH);
  837.         default:
  838.           break;
  839.         }
  840.     }
  841.   acknowledge (signo);
  842.   return (XCPT_CONTINUE_EXECUTION);
  843. }
  844.  
  845.  
  846. static ULONG trap (EXCEPTIONREPORTRECORD *report,
  847.                    CONTEXTRECORD *context,
  848.                    int signo)
  849. {
  850.   struct signal_entry *p;
  851.   thread_data *td;
  852.  
  853.   /* Don't try to do anything if the stack is invalid or in a nested
  854.      exception. */
  855.  
  856.   if (report->fHandlerFlags & (EH_STACK_INVALID|EH_NESTED_CALL))
  857.     return (XCPT_CONTINUE_SEARCH);
  858.  
  859.   /* Get a pointer to the thread data block and a pointer to the
  860.      signal table entry for SIGNO of the current thread. */
  861.  
  862.   td = get_thread ();
  863.   p = get_thread ()->sig_table + signo;
  864.  
  865.   if (p->handler != SIG_IGN)
  866.     {
  867.       generate_signal (td, signo);
  868.  
  869.       /* Deliver the signal even if its blocked. */
  870.  
  871.       sig_lock ();
  872.       deliver_signal (td, signo, NULL, context);
  873.  
  874.       /* Deliver any other pending signals. */
  875.  
  876.       deliver_pending_signals (td, NULL, context);
  877.     }
  878.  
  879.   /* Invoke the next exception handler. */
  880.  
  881.   return (XCPT_CONTINUE_SEARCH);
  882. }
  883.  
  884.  
  885. /* Load a heap page from a dumped executable. */
  886.  
  887. static void load_heap (ULONG addr)
  888. {
  889.   ULONG rc, cbread, newpos;
  890.  
  891.   addr &= ~0xfff;
  892.   rc = DosSetFilePtr (exe_fhandle, addr - heap_base + heap_off,
  893.                       FILE_BEGIN, &newpos);
  894.   if (rc == 0)
  895.     rc = DosRead (exe_fhandle, (void *)addr, 0x1000, &cbread);
  896.   if (rc != 0)
  897.     {
  898.       otext ("\r\nCannot read EXE file\r\n");
  899.       quit (255);
  900.     }
  901. }
  902.  
  903.  
  904. /* This is the exception handler. */
  905.  
  906. ULONG exception (EXCEPTIONREPORTRECORD *report,
  907.                  EXCEPTIONREGISTRATIONRECORD *registration,
  908.                  CONTEXTRECORD *context, void *dummy)
  909. {
  910.   ULONG addr;
  911.  
  912.   /* Don't trust -- clear the decrement flag. */
  913.  
  914.   __asm__ ("cld");
  915.  
  916.   /* Don't do anything when unwinding exception handlers. */
  917.  
  918.   if (report->fHandlerFlags & (EH_EXIT_UNWIND|EH_UNWINDING))
  919.     return (XCPT_CONTINUE_SEARCH);
  920.  
  921.   /* The rest of this function depends on the exception number. */
  922.  
  923.   switch (report->ExceptionNum)
  924.     {
  925.     case XCPT_GUARD_PAGE_VIOLATION:
  926.  
  927.       /* Guard page violation.  This exception is used for loading
  928.          heap pages from a dumped executable.  Moreover, this is used
  929.          by old emx programs for expanding the stack.  First, get the
  930.          address of the page. */
  931.  
  932.       addr = report->ExceptionInfo[1];
  933.  
  934.       /* Load a page from the executable if the page is in the heap
  935.          and we have a dumped executable. */
  936.  
  937.       if (exe_heap && addr >= heap_base && addr < brk_ptr)
  938.         {
  939.           load_heap (addr);
  940.           return (XCPT_CONTINUE_EXECUTION);
  941.         }
  942.  
  943.       /* Looks like a guard page created by the application program.
  944.          Pass the exception to the next exception handler. */
  945.  
  946.       return (XCPT_CONTINUE_SEARCH);
  947.  
  948.     case XCPT_ACCESS_VIOLATION:
  949.     case XCPT_DATATYPE_MISALIGNMENT:
  950.  
  951.       /* Map access violations to SIGSEGV. */
  952.  
  953.       return (trap (report, context, SIGSEGV));
  954.  
  955.     case XCPT_INTEGER_DIVIDE_BY_ZERO:
  956.     case XCPT_INTEGER_OVERFLOW:
  957.     case XCPT_ARRAY_BOUNDS_EXCEEDED:
  958.     case XCPT_FLOAT_DENORMAL_OPERAND:
  959.     case XCPT_FLOAT_DIVIDE_BY_ZERO:
  960.     case XCPT_FLOAT_INEXACT_RESULT:
  961.     case XCPT_FLOAT_INVALID_OPERATION:
  962.     case XCPT_FLOAT_OVERFLOW:
  963.     case XCPT_FLOAT_STACK_CHECK:
  964.     case XCPT_FLOAT_UNDERFLOW:
  965.  
  966.       /* Map integer division by zero and floating point exceptions to
  967.          SIGFPE. */
  968.  
  969.       return (trap (report, context, SIGFPE));
  970.  
  971.     case XCPT_ILLEGAL_INSTRUCTION:
  972.     case XCPT_INVALID_LOCK_SEQUENCE:
  973.     case XCPT_PRIVILEGED_INSTRUCTION:
  974.  
  975.       /* Map the various exceptions for illegal instructions to
  976.          SIGILL. */
  977.  
  978.       return (trap (report, context, SIGILL));
  979.  
  980.     case XCPT_SIGNAL:
  981.  
  982.       /* Map signal exceptions to SIGINT, SIGTERM or SIGBREAK. */
  983.  
  984.       if (report->cParameters >= 1)
  985.         switch (report->ExceptionInfo[0])
  986.           {
  987.           case XCPT_SIGNAL_INTR:
  988.             return (signal_exception (SIGINT, context));
  989.           case XCPT_SIGNAL_KILLPROC:
  990.             return (signal_exception (SIGTERM, context));
  991.           case XCPT_SIGNAL_BREAK:
  992.             return (signal_exception (SIGBREAK, context));
  993.           }
  994.       return (XCPT_CONTINUE_SEARCH);
  995.     }
  996.  
  997.   /* The exception is not handled by emx.  Pass it to the next
  998.      exception handler. */
  999.  
  1000.   return (XCPT_CONTINUE_SEARCH);
  1001. }
  1002.  
  1003.  
  1004. /* Install the exception handler for the main thread.  REGISTRATION
  1005.    points to the exception registration record, which must be in the
  1006.    stack (at the `bottom' of the stack). */
  1007.  
  1008. void install_except (EXCEPTIONREGISTRATIONRECORD *registration)
  1009. {
  1010.   ULONG rc;
  1011.  
  1012.   registration->prev_structure = NULL;
  1013.   registration->ExceptionHandler = exception;
  1014.   rc = DosSetExceptionHandler (registration);
  1015.   if (rc != 0)
  1016.     error (rc, "DosSetExceptionHandler");
  1017. }
  1018.  
  1019.  
  1020. /* Install the exception handler for another thread.  REGISTRATION
  1021.    points to the exception registration record, which must be in the
  1022.    stack (at the `bottom' of the stack). */
  1023.  
  1024. int initthread (EXCEPTIONREGISTRATIONRECORD *registration)
  1025. {
  1026.   ULONG rc;
  1027.  
  1028.   registration->prev_structure = NULL;
  1029.   registration->ExceptionHandler = exception;
  1030.   rc = DosSetExceptionHandler (registration);
  1031.   return (0);
  1032. }
  1033.  
  1034.  
  1035. /* We want to receive signals. */
  1036.  
  1037. void receive_signals (void)
  1038. {
  1039.   ULONG times;
  1040.  
  1041.   DosSetSignalExceptionFocus (SIG_SETFOCUS, ×);
  1042. }
  1043.  
  1044.  
  1045. void init_exceptions (void)
  1046. {
  1047.   USHORT old_sig16_action;      /* Dummy (output) */
  1048.  
  1049.   sig_flag = FALSE;
  1050.   create_event_sem (&signal_sem, DC_SEM_SHARED);
  1051.   create_mutex_sem (&sig_access);
  1052.   install_except (exc_reg_ptr);
  1053.   init_signal16 ();
  1054.   DosSetSigHandler (_emx_32to16 (&sig16_handler), &old_sig16_handler,
  1055.                     &old_sig16_action, SIGA_ACCEPT, SIG_PFLG_A);
  1056. }
  1057.  
  1058.  
  1059. /* alarm() */
  1060.  
  1061. static BYTE alarm_started;
  1062. static BYTE alarm_set;
  1063. static ULONG alarm_interval;
  1064. static ULONG alarm_time;
  1065. static HTIMER alarm_timer;
  1066. static HEV alarm_sem_timer;
  1067.  
  1068. static void alarm_thread (ULONG arg)
  1069. {
  1070.   ULONG rc;
  1071.  
  1072.   for (;;)
  1073.     {
  1074.       rc = DosWaitEventSem (alarm_sem_timer, -1);
  1075.       if (rc == 0)
  1076.         {
  1077.           reset_event_sem (alarm_sem_timer);
  1078.           generate_signal (threads[1], SIGALRM);
  1079.         }
  1080.       else if (rc != ERROR_INTERRUPT)
  1081.         error (rc, "DosWaitEventSem");
  1082.     }
  1083. }
  1084.  
  1085.  
  1086. void start_alarm (void)
  1087. {
  1088.   ULONG rc, tid;
  1089.  
  1090.   if (create_event_sem (&alarm_sem_timer, DC_SEM_SHARED) == 0)
  1091.     {
  1092.       rc = DosCreateThread (&tid, alarm_thread, 0,
  1093.                             CREATE_READY | STACK_COMMITTED, 0x4000);
  1094.       if (rc != 0)
  1095.         error (rc, "DosCreateThread");
  1096.       else
  1097.         alarm_started = TRUE;
  1098.     }
  1099. }
  1100.  
  1101.  
  1102. ULONG set_alarm (ULONG value)
  1103. {
  1104.   ULONG rc, rest, result;
  1105.  
  1106.   if (!alarm_started)
  1107.     {
  1108.       start_alarm ();
  1109.       if (!alarm_started)
  1110.         return (-1);
  1111.     }
  1112.   result = 0;
  1113.   if (alarm_set)
  1114.     {
  1115.       rest = querysysinfo (QSV_TIME_LOW) - alarm_time;
  1116.       if (alarm_interval >= rest)
  1117.         result = alarm_interval - rest;
  1118.       DosStopTimer (alarm_timer);
  1119.       alarm_set = FALSE;
  1120.       reset_event_sem (alarm_sem_timer);
  1121.     }
  1122.   if (value == 0)
  1123.     alarm_interval = 0;
  1124.   else
  1125.     {
  1126.       alarm_set = TRUE;
  1127.       alarm_interval = value;
  1128.       rc = DosAsyncTimer (1000 * value, (HSEM)alarm_sem_timer, &alarm_timer);
  1129.       if (rc != 0)
  1130.         error (rc, "DosAsyncTimer");
  1131.       alarm_time = querysysinfo (QSV_TIME_LOW);
  1132.     }
  1133.   return (result);
  1134. }
  1135.  
  1136.  
  1137. void stop_alarm (void)
  1138. {
  1139.   if (!alarm_started)
  1140.     set_alarm (0);
  1141. }
  1142.