home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / ucbmail / sigretro.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-02-01  |  7.4 KB  |  339 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.  The Berkeley software License Agreement
  4.  * specifies the terms and conditions for redistribution.
  5.  */
  6.  
  7. #ifndef lint
  8. static char *sccsid = "@(#)sigretro.c    5.2 (Berkeley) 6/21/85";
  9. #endif not lint
  10.  
  11. #include <signal.h>
  12. #include <errno.h>
  13. #include <setjmp.h>
  14. #include "./sigretro.h"
  15.  
  16. /*
  17.  * Retrofit new signal interface to old signal primitives.
  18.  * Supported routines:
  19.  *    sigsys(sig, func)
  20.  *    sigset(sig, func)
  21.  *    sighold(sig)
  22.  *    sigrelse(sig)
  23.  *    sigignore(sig)
  24.  *    sigpause(sig)
  25.  * Also,
  26.  *    sigchild()
  27.  *        to set all held signals to ignored signals in the
  28.  *        child process after fork(2)
  29.  */
  30.  
  31. typedef    int    (*sigtype)();
  32.  
  33. sigtype    sigdisp(), sighold(), sigignore();
  34.  
  35. /*
  36.  * The following helps us keep the extended signal semantics together.
  37.  * We remember for each signal the address of the function we're
  38.  * supposed to call.  s_func is SIG_DFL / SIG_IGN if appropriate.
  39.  */
  40. struct sigtable {
  41.     sigtype    s_func;            /* What to call */
  42.     int    s_flag;            /* Signal flags; see below */
  43. } sigtable[NSIG + 1];
  44.  
  45. /*
  46.  * Signal flag values.
  47.  */
  48. #define    SHELD        1        /* Signal is being held */
  49. #define    SDEFER        2        /* Signal occured while held */
  50. #define    SSET        4        /* s_func is believable */
  51. #define    SPAUSE        8        /* are pausing, waiting for sig */
  52.  
  53. jmp_buf    _pause;                /* For doing sigpause() */
  54.  
  55. /*
  56.  * Approximate sigsys() system call
  57.  * This is almost useless since one only calls sigsys()
  58.  * in the child of a vfork().  If you have vfork(), you have new signals
  59.  * anyway.  The real sigsys() does all the stuff needed to support
  60.  * the real sigset() library.  We don't bother here, assuming that
  61.  * you are either ignoring or defaulting a signal in the child.
  62.  */
  63. sigtype
  64. sigsys(sig, func)
  65.     sigtype func;
  66. {
  67.     sigtype old;
  68.  
  69.     old = sigdisp(sig);
  70.     signal(sig, func);
  71.     return(old);
  72. }
  73.  
  74. /*
  75.  * Set the (permanent) disposition of a signal.
  76.  * If the signal is subsequently (or even now) held,
  77.  * the action you set here can be enabled using sigrelse().
  78.  */
  79. sigtype
  80. sigset(sig, func)
  81.     sigtype func;
  82. {
  83.     sigtype old;
  84.     int _sigtramp();
  85.     extern int errno;
  86.  
  87.     if (sig < 1 || sig > NSIG) {
  88.         errno = EINVAL;
  89.         return(BADSIG);
  90.     }
  91.     old = sigdisp(sig);
  92.     /*
  93.      * Does anyone actually call sigset with SIG_HOLD!?
  94.      */
  95.     if (func == SIG_HOLD) {
  96.         sighold(sig);
  97.         return(old);
  98.     }
  99.     sigtable[sig].s_flag |= SSET;
  100.     sigtable[sig].s_func = func;
  101.     if (func == SIG_DFL) {
  102.         /*
  103.          * If signal has been held, must retain
  104.          * the catch so that we can note occurrance
  105.          * of signal.
  106.          */
  107.         if ((sigtable[sig].s_flag & SHELD) == 0)
  108.             signal(sig, SIG_DFL);
  109.         else
  110.             signal(sig, _sigtramp);
  111.         return(old);
  112.     }
  113.     if (func == SIG_IGN) {
  114.         /*
  115.          * Clear pending signal
  116.          */
  117.         signal(sig, SIG_IGN);
  118.         sigtable[sig].s_flag &= ~SDEFER;
  119.         return(old);
  120.     }
  121.     signal(sig, _sigtramp);
  122.     return(old);
  123. }
  124.  
  125. /*
  126.  * Hold a signal.
  127.  * This CAN be tricky if the signal's disposition is SIG_DFL.
  128.  * In that case, we still catch the signal so we can note it
  129.  * happened and do something crazy later.
  130.  */
  131. sigtype
  132. sighold(sig)
  133. {
  134.     sigtype old;
  135.     extern int errno;
  136.  
  137.     if (sig < 1 || sig > NSIG) {
  138.         errno = EINVAL;
  139.         return(BADSIG);
  140.     }
  141.     old = sigdisp(sig);
  142.     if (sigtable[sig].s_flag & SHELD)
  143.         return(old);
  144.     /*
  145.      * When the default action is required, we have to
  146.      * set up to catch the signal to note signal's occurrance.
  147.      */
  148.     if (old == SIG_DFL) {
  149.         sigtable[sig].s_flag |= SSET;
  150.         signal(sig, _sigtramp);
  151.     }
  152.     sigtable[sig].s_flag |= SHELD;
  153.     return(old);
  154. }
  155.  
  156. /*
  157.  * Release a signal
  158.  * If the signal occurred while we had it held, cause the signal.
  159.  */
  160. sigtype
  161. sigrelse(sig)
  162. {
  163.     sigtype old;
  164.     extern int errno;
  165.     int _sigtramp();
  166.  
  167.     if (sig < 1 || sig > NSIG) {
  168.         errno = EINVAL;
  169.         return(BADSIG);
  170.     }
  171.     old = sigdisp(sig);
  172.     if ((sigtable[sig].s_flag & SHELD) == 0)
  173.         return(old);
  174.     sigtable[sig].s_flag &= ~SHELD;
  175.     if (sigtable[sig].s_flag & SDEFER)
  176.         _sigtramp(sig);
  177.     /*
  178.      * If disposition was the default, then we can unset the
  179.      * catch to _sigtramp() and let the system do the work.
  180.      */
  181.     if (sigtable[sig].s_func == SIG_DFL)
  182.         signal(sig, SIG_DFL);
  183.     return(old);
  184. }
  185.  
  186. /*
  187.  * Ignore a signal.
  188.  */
  189. sigtype
  190. sigignore(sig)
  191. {
  192.  
  193.     return(sigset(sig, SIG_IGN));
  194. }
  195.  
  196. /*
  197.  * Pause, waiting for sig to occur.
  198.  * We assume LUSER called us with the signal held.
  199.  * When we got the signal, mark the signal as having
  200.  * occurred.  It will actually cause something when
  201.  * the signal is released.
  202.  *
  203.  * This is probably useless without job control anyway.
  204.  */
  205. sigpause(sig)
  206. {
  207.     extern int errno;
  208.  
  209.     if (sig < 1 || sig > NSIG) {
  210.         errno = EINVAL;
  211.         return;
  212.     }
  213.     sigtable[sig].s_flag |= SHELD|SPAUSE;
  214.     if (setjmp(_pause) == 0)
  215.         pause();
  216.     sigtable[sig].s_flag &= ~SPAUSE;
  217.     sigtable[sig].s_flag |= SDEFER;
  218. }
  219.  
  220. /*
  221.  * In the child process after fork(2), set the disposition of all held
  222.  * signals to SIG_IGN.  This is a new procedure not in the real sigset()
  223.  * package, provided for retrofitting purposes.
  224.  */
  225. sigchild()
  226. {
  227.     register int i;
  228.  
  229.     for (i = 1; i <= NSIG; i++)
  230.         if (sigtable[i].s_flag & SHELD)
  231.             signal(i, SIG_IGN);
  232. }
  233.  
  234. /*
  235.  * Return the current disposition of a signal
  236.  * If we have not set this signal before, we have to
  237.  * ask the system
  238.  */
  239. sigtype
  240. sigdisp(sig)
  241. {
  242.     extern int errno;
  243.     sigtype old;
  244.  
  245.     if (sig < 1 || sig > NSIG) {
  246.         errno = EINVAL;
  247.         return(BADSIG);
  248.     }
  249.     /*
  250.      * If we have no knowledge of this signal,
  251.      * ask the system, then save the result for later.
  252.      */
  253.     if ((sigtable[sig].s_flag & SSET) == 0) {
  254.         old = signal(sig, SIG_IGN);
  255.         sigtable[sig].s_func = old;
  256.         sigtable[sig].s_flag |= SSET;
  257.         signal(sig, old);
  258.         return(old);
  259.     }
  260.     /*
  261.      * If we have set this signal before, then sigset()
  262.      * will have been careful to leave something meaningful
  263.      * in s_func.
  264.      */
  265.     return(sigtable[sig].s_func);
  266. }
  267.  
  268. /*
  269.  * The following routine gets called for any signal
  270.  * that is to be trapped to a user function.
  271.  */
  272. _sigtramp(sig)
  273. {
  274.     extern int errno;
  275.     sigtype old;
  276.  
  277.     if (sig < 1 || sig > NSIG) {
  278.         errno = EINVAL;
  279.         return;
  280.     }
  281.  
  282. top:
  283.     old = signal(sig, SIG_IGN);
  284.     /*
  285.      * If signal being paused on, wakeup sigpause()
  286.      */
  287.     if (sigtable[sig].s_flag & SPAUSE)
  288.         longjmp(_pause, 1);
  289.     /*
  290.      * If signal being held, mark its table entry
  291.      * so we can trigger it when signal released.
  292.      * Then just return.
  293.      */
  294.     if (sigtable[sig].s_flag & SHELD) {
  295.         sigtable[sig].s_flag |= SDEFER;
  296.         signal(sig, _sigtramp);
  297.         return;
  298.     }
  299.     /*
  300.      * If the signal is being ignored, just return.
  301.      * This would make SIGCONT more normal, but of course
  302.      * any system with SIGCONT also has the new signal pkg, so...
  303.      */
  304.     if (sigtable[sig].s_func == SIG_IGN)
  305.         return;
  306.     /*
  307.      * If the signal is SIG_DFL, then we probably got here
  308.      * by holding the signal, having it happen, then releasing
  309.      * the signal.  I wonder if a process is allowed to send
  310.      * a signal to itself?
  311.      */
  312.     if (sigtable[sig].s_func == SIG_DFL) {
  313.         signal(sig, SIG_DFL);
  314.         kill(getpid(), sig);
  315.         /* Will we get back here? */
  316.         return;
  317.     }
  318.     /*
  319.      * Looks like we should just cause the signal...
  320.      * We hold the signal for the duration of the user's
  321.      * code with the signal re-enabled.  If the signal
  322.      * happens again while in user code, we will recursively
  323.      * trap here and mark that we had another occurance
  324.      * and return to the user's trap code.  When we return
  325.      * from there, we can cause the signal again.
  326.      */
  327.     sigtable[sig].s_flag &= ~SDEFER;
  328.     sigtable[sig].s_flag |= SHELD;
  329.     signal(sig, _sigtramp);
  330.     (*sigtable[sig].s_func)(sig);
  331.     /*
  332.      * If the signal re-occurred while in the user's routine,
  333.      * just go try it again...
  334.      */
  335.     sigtable[sig].s_flag &= ~SHELD;
  336.     if (sigtable[sig].s_flag & SDEFER)
  337.         goto top;
  338. }
  339.