home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / metamail / tahoe / sigretro.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-02-18  |  7.7 KB  |  345 lines

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