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