home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume1 / bourne / part1 / signal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  3.8 KB  |  145 lines

  1. /*
  2.     signal -- old system call emulation for 4.2BSD (VAX version)
  3.         (adapted from BRL UNIX System V emulation for 4.2BSD)
  4.  
  5.     last edit:    25-Aug-1984    D A Gwyn
  6.  
  7.     NOTE:  Although this module is VAX-specific, it should be
  8.     possible to adapt it to other fairly clean implementations of
  9.     4.2BSD.  The difficulty lies in avoiding the automatic restart
  10.     of certain system calls when the signal handler returns.  I use
  11.     here a trick first described by Donn Seeley of UCSD Chem. Dept.
  12. */
  13.  
  14. #include    <errno.h>
  15. #include    <signal.h>
  16. #include    <syscall.h>
  17.  
  18. extern int    sigvec();
  19. extern int    sigsetmask();
  20.  
  21. extern        etext;
  22. extern int    errno;
  23.  
  24. static int    (*handler[NSIG])() =    /* "current handler" memory */
  25.     {
  26.     BADSIG                /* initially, unknown state */
  27.     };
  28. static int    inited = 0;        /* for initializing above */
  29.  
  30. static int    catchsig();
  31. static int    ret_eintr();
  32.  
  33. int    (*
  34. signal( sig, func )            /* returns previous handler */
  35.     )()
  36.     register int    sig;        /* signal affected */
  37.     register int    (*func)();    /* new handler */
  38.     {
  39.     register int    (*retval)();    /* previous handler value */
  40.     struct sigvec    oldsv;        /* previous state */
  41.     struct sigvec    newsv;        /* state being set */
  42.  
  43.     if ( func >= (int (*)())&etext )    /* "lint" hates this */
  44.         {
  45.         errno = EFAULT;
  46.         return BADSIG;        /* error */
  47.         }
  48.  
  49.     /* cancel pending signals */
  50.     newsv.sv_handler = SIG_IGN;
  51.     newsv.sv_mask = newsv.sv_onstack = 0;
  52.     if ( sigvec( sig, &newsv, &oldsv ) != 0 )
  53.         return BADSIG;        /* error */
  54.  
  55.     /* C language provides no good way to initialize handler[] */
  56.     if ( !inited )            /* once only */
  57.         {
  58.         register int    i;
  59.  
  60.         for ( i = 1; i < NSIG; ++i )
  61.             handler[i] = BADSIG;    /* initialize */
  62.  
  63.         ++inited;
  64.         }
  65.  
  66.     /* the first time for this sig, get state from the system */
  67.     if ( (retval = handler[sig-1]) == BADSIG )
  68.         retval = oldsv.sv_handler;
  69.  
  70.     handler[sig-1] = func;    /* keep track of state */
  71.  
  72.     if ( func == SIG_DFL )
  73.         newsv.sv_handler = SIG_DFL;
  74.     else if ( func != SIG_IGN )
  75.         newsv.sv_handler = catchsig;    /* actual sig catcher */
  76.  
  77.     if ( func != SIG_IGN        /* sig already being ignored */
  78.       && sigvec( sig, &newsv, (struct sigvec *)0 ) != 0
  79.        )
  80.         return BADSIG;        /* error */
  81.  
  82.     return retval;            /* previous handler */
  83.     }
  84.  
  85.  
  86. /* # bytes to skip at the beginning of C ret_eintr() function code: */
  87. #define    OFFSET    2            /* for VAX .word reg_mask */
  88.  
  89. /* PC will be pointing at a syscall if it is to be restarted: */
  90. typedef unsigned char    opcode;        /* one byte long */
  91. #define    SYSCALL        ((opcode)0xBC)    /* VAX CHMK instruction */
  92. #define    IMMEDIATE    ((opcode)0x8F)    /* VAX immediate addressing */
  93.  
  94.  
  95. /*ARGSUSED*/
  96. static int
  97. catchsig( sig, code, scp )        /* signal interceptor */
  98.     register int        sig;    /* signal number */
  99.     int            code;    /* code for SIGILL, SIGFPE */
  100.     register struct sigcontext    *scp;    /* -> interrupted context */
  101.     {
  102.     register int        (*uhandler)();    /* user handler */
  103.     register opcode        *pc;    /* for snooping instructions */
  104.     struct sigvec        newsv;    /* state being set */
  105.  
  106.     /* at this point, sig is blocked */
  107.  
  108.     uhandler = handler[sig - 1];
  109.  
  110.     /* most UNIXes usually want the state reset to SIG_DFL */
  111.     if ( sig != SIGILL && sig != SIGTRAP )
  112.         {
  113.         handler[sig-1] = newsv.sv_handler = SIG_DFL;
  114.         newsv.sv_mask = newsv.sv_onstack = 0;
  115.         (void)sigvec( sig, &newsv, (struct sigvec *)0 );
  116.         }
  117.  
  118.     (void)sigsetmask( scp->sc_mask );    /* restore old mask */
  119.  
  120.     /* at this point, sig is not blocked, usually have SIG_DFL;
  121.        a longjmp may safely be taken by the user signal handler */
  122.  
  123.     (void)(*uhandler)( sig );    /* user signal handler */
  124.  
  125.     /* must now avoid restarting certain system calls */
  126.     pc = (opcode *)scp->sc_pc;
  127.     if ( *pc++ == SYSCALL
  128.       && (*pc == SYS_read || *pc == SYS_write || *pc == SYS_ioctl
  129.        || *pc++ == IMMEDIATE
  130.        && (*pc == SYS_wait || *pc == SYS_readv || *pc == SYS_writev)
  131.          )
  132.        )
  133.         scp->sc_pc = (int)ret_eintr + OFFSET;
  134.  
  135.     /* return here restores interrupted context */
  136.     }
  137.  
  138.  
  139. static int
  140. ret_eintr()                /* substitute for system call */
  141. {
  142.     errno = EINTR;
  143.     return -1;
  144. }
  145.