skalibs

Mirror/fork of https://skarnet.org/software/skalibs/
git clone https://ccx.te2000.cz/git/skalibs
Log | Files | Refs | README | LICENSE

selfpipe.c (3488B)


      1 /* ISC license. */
      2 
      3 /* MT-unsafe */
      4 
      5 #include <skalibs/sysdeps.h>
      6 
      7 #ifdef SKALIBS_HASSIGNALFD
      8 
      9 #include <errno.h>
     10 #include <signal.h>
     11 #include <sys/signalfd.h>
     12 
     13 #include <skalibs/allreadwrite.h>
     14 #include <skalibs/sig.h>
     15 #include <skalibs/djbunix.h>
     16 
     17 struct selfpipe_s
     18 {
     19   sigset_t caught ;
     20   int fd ;
     21 } ;
     22 
     23 static struct selfpipe_s sp = { .fd = -1 } ;
     24 
     25 int selfpipe_fd ()
     26 {
     27   return sp.fd ;
     28 }
     29 
     30 int selfpipe_read ()
     31 {
     32   struct signalfd_siginfo buf ;
     33   ssize_t r = sanitize_read(fd_read(sp.fd, (char *)&buf, sizeof(struct signalfd_siginfo))) ;
     34   return (r <= 0) ? r : buf.ssi_signo ;
     35 }
     36 
     37 int selfpipe_trap (int sig)
     38 {
     39   sigset_t set = sp.caught ;
     40   sigset_t old ;
     41   if (sp.fd == -1) return (errno = EBADF, 0) ;
     42   if (sigaddset(&set, sig) == -1 || sigprocmask(SIG_BLOCK, &set, &old) == -1) return 0 ;
     43   if (signalfd(sp.fd, &set, SFD_NONBLOCK | SFD_CLOEXEC) == -1)
     44   {
     45     int e = errno ;
     46     sigprocmask(SIG_SETMASK, &old, 0) ;
     47     errno = e ;
     48     return 0 ;
     49   }
     50   sp.caught = set ;
     51   return 1 ;
     52 }
     53 
     54 int selfpipe_trapset (sigset_t const *set)
     55 {
     56   sigset_t old ;
     57   if (sp.fd == -1) return (errno = EBADF, 0) ;
     58   if (sigprocmask(SIG_SETMASK, set, &old) == -1) return 0 ;
     59   if (signalfd(sp.fd, set, SFD_NONBLOCK | SFD_CLOEXEC) == -1)
     60   {
     61     int e = errno ;
     62     sigprocmask(SIG_SETMASK, &old, 0) ;
     63     errno = e ;
     64     return 0 ;
     65   }
     66   sp.caught = *set ;
     67   return 1 ;
     68 }
     69 
     70 void selfpipe_finish ()
     71 {
     72   int e = errno ;
     73   fd_close(sp.fd) ; sp.fd = -1 ;
     74   sigprocmask(SIG_UNBLOCK, &sp.caught, 0) ;
     75   sigemptyset(&sp.caught) ;
     76   errno = e ;
     77 }
     78 
     79 int selfpipe_init ()
     80 {
     81   sigemptyset(&sp.caught) ;
     82   sig_blocknone() ;
     83   sp.fd = signalfd(sp.fd, &sp.caught, SFD_NONBLOCK | SFD_CLOEXEC) ;
     84   return sp.fd ;
     85 }
     86 
     87 #else
     88 
     89 #include <skalibs/nonposix.h>
     90 
     91 #include <errno.h>
     92 #include <signal.h>
     93 #include <unistd.h>
     94 
     95 #include <skalibs/nsig.h>
     96 #include <skalibs/sig.h>
     97 #include <skalibs/allreadwrite.h>
     98 #include <skalibs/djbunix.h>
     99 
    100 struct selfpipe_s
    101 {
    102   sigset_t caught ;
    103   int fd[2] ;
    104 } ;
    105 
    106 static struct selfpipe_s sp = { .fd = { -1, -1 } } ;
    107 
    108 static void selfpipe_tophalf (int s)
    109 {
    110   int e = errno ;
    111   unsigned char c = (unsigned char)s ;
    112   write(sp.fd[1], (char *)&c, 1) ;
    113   errno = e ;
    114 }
    115 
    116 int selfpipe_fd ()
    117 {
    118   return sp.fd[0] ;
    119 }
    120 
    121 int selfpipe_read ()
    122 {
    123   char c ;
    124   ssize_t r = sanitize_read((fd_read(sp.fd[0], &c, 1))) ;
    125   return (r <= 0) ? r : c ;
    126 }
    127 
    128 int selfpipe_trap (int sig)
    129 {
    130   if (sp.fd[0] == -1) return (errno = EBADF, 0) ;
    131   if (!sig_catch(sig, &selfpipe_tophalf)) return 0 ;
    132   sigaddset(&sp.caught, sig) ;
    133   sig_unblock(sig) ;
    134   return 1 ;
    135 }
    136 
    137 int selfpipe_trapset (sigset_t const *set)
    138 {
    139   unsigned int i = 1 ;
    140   if (sp.fd[0] == -1) return (errno = EBADF, 0) ;
    141   for (; i < SKALIBS_NSIG ; i++)
    142   {
    143     int h = sigismember(set, i) ;
    144     if (h < 0) continue ;
    145     if (h)
    146     {
    147       if (!sig_catch(i, &selfpipe_tophalf)) goto err ;
    148     }
    149     else if (sigismember(&sp.caught, i))
    150     {
    151       if (!sig_restore(i)) goto err ;
    152     }
    153   }
    154   sig_blocknone() ;
    155   sp.caught = *set ;
    156   return 1 ;
    157 
    158  err:
    159   sig_restoreto(set, i) ;
    160   return 0 ;
    161 }
    162 
    163 void selfpipe_finish ()
    164 {
    165   int e = errno ;
    166   sigprocmask(SIG_BLOCK, &sp.caught, 0) ;
    167   sig_restoreto(&sp.caught, SKALIBS_NSIG) ;
    168   fd_close(sp.fd[1]) ;
    169   fd_close(sp.fd[0]) ;
    170   sigprocmask(SIG_UNBLOCK, &sp.caught, 0) ;
    171   sigemptyset(&sp.caught) ;
    172   sp.fd[0] = sp.fd[1] = -1 ;
    173   errno = e ;
    174 }
    175 
    176 int selfpipe_init ()
    177 {
    178   if (sp.fd[0] >= 0) selfpipe_finish() ;
    179   else sigemptyset(&sp.caught) ;
    180   sig_blocknone() ;
    181   return pipenbcoe(sp.fd) < 0 ? -1 : sp.fd[0] ;
    182 }
    183 
    184 #endif