+openbsd.ha (12784B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use errors; 5 use io; 6 use rt; 7 use unix; 8 9 // Requests that [[sig::ALRM]] is delivered to the calling process in (about) 10 // "sec" seconds. Returns the number of seconds until the previously scheduled 11 // alarm, or zero if none was scheduled. 12 export fn alarm(sec: uint) uint = { 13 return rt::alarm(sec); 14 }; 15 16 // Configures a new signal handler, returning the old details (which can be 17 // passed to [[restore]] to restore its behavior). 18 // 19 // The variadic parameters specify either [[flag]]s to enable or a signal mask 20 // to use via [[sigset]]; if the latter is provided no more than one may be 21 // used. 22 export fn handle( 23 signum: sig, 24 handler: *handler, 25 opt: (flag | sigset)... 26 ) sigaction = { 27 let sa_mask = newsigset(); 28 29 let sa_flags = rt::SA_SIGINFO: int, nmask = 0; 30 for (let i = 0z; i < len(opt); i += 1) { 31 match (opt[i]) { 32 case let flag: flag => 33 sa_flags |= flag: int; 34 case let mask: sigset => 35 assert(nmask == 0, "Multiple signal masks provided to signal::handle"); 36 nmask += 1; 37 sa_mask = mask; 38 }; 39 }; 40 41 let new = rt::sigact { 42 sa_sigaction = handler: *fn(int, *rt::siginfo, *opaque) void, 43 sa_mask = sa_mask, 44 sa_flags = sa_flags, 45 }; 46 let old = rt::sigact { 47 sa_sigaction = null: *fn(int, *rt::siginfo, *opaque) void, 48 ... 49 }; 50 match (rt::sigaction(signum, &new, &old)) { 51 case let err: rt::errno => 52 abort("sigaction failed (invalid signal?)"); 53 case void => void; 54 }; 55 return old; 56 57 }; 58 59 // Restores previous signal behavior following [[handle]]. 60 export fn restore(signum: sig, action: *sigaction) void = { 61 match (rt::sigaction(signum, action: *rt::sigact, null)) { 62 case rt::errno => 63 abort("sigaction failed (invalid signal?)"); 64 case void => void; 65 }; 66 67 }; 68 69 // Unregisters signal handlers for the specified signal. 70 export fn reset(signum: sig) void = { 71 handle(signum, rt::SIG_DFL: *handler); 72 }; 73 74 // Unregisters all signal handlers. 75 export fn resetall() void = { 76 // sig::KILL and sig::STOP deliberately omitted; see sigaction(2) 77 reset(sig::HUP); 78 reset(sig::INT); 79 reset(sig::QUIT); 80 reset(sig::ILL); 81 reset(sig::TRAP); 82 reset(sig::ABRT); 83 reset(sig::EMT); 84 reset(sig::FPE); 85 reset(sig::BUS); 86 reset(sig::SEGV); 87 reset(sig::SYS); 88 reset(sig::PIPE); 89 reset(sig::ALRM); 90 reset(sig::TERM); 91 reset(sig::URG); 92 reset(sig::TSTP); 93 reset(sig::CONT); 94 reset(sig::CHLD); 95 reset(sig::TTIN); 96 reset(sig::TTOU); 97 reset(sig::IO); 98 reset(sig::XCPU); 99 reset(sig::XFSZ); 100 reset(sig::VTALRM); 101 reset(sig::PROF); 102 reset(sig::WINCH); 103 reset(sig::INFO); 104 reset(sig::USR1); 105 reset(sig::USR2); 106 }; 107 108 // Prevents given signal from arriving to the current process. 109 // One common use case is to ignore SIGCHLD to avoid zombie child processes. 110 export fn ignore(signum: sig) void = { 111 handle(signum, rt::SIG_IGN: *handler); 112 }; 113 114 // Adds the given list of signals to the process's current signal mask, 115 // returning the old signal mask. This is a convenience function around 116 // [[setprocmask]]. 117 export fn block(signals: sig...) sigset = { 118 let new = newsigset(signals...); 119 return setprocmask(how::BLOCK, &new); 120 }; 121 122 // Removes the given list of signals from the process's current signal mask, 123 // returning the old signal mask. This is a convenience function around 124 // [[setprocmask]]. 125 export fn unblock(signals: sig...) sigset = { 126 let new = newsigset(signals...); 127 return setprocmask(how::UNBLOCK, &new); 128 }; 129 130 // Sets the process's signal mask, returning the previous mask. 131 export fn setprocmask(how: how, mask: *sigset) sigset = { 132 let old: sigset = 0; 133 rt::sigprocmask(how, mask: *rt::sigset, &old)!; 134 return old; 135 }; 136 137 // Gets the current process's signal mask. 138 export fn getprocmask() sigset = { 139 let old: sigset = 0; 140 rt::sigprocmask(how::SETMASK, null, &old)!; 141 return old; 142 }; 143 144 // Defines the modes of operation for [[setprocmask]]. 145 export type how = enum int { 146 // Adds the given set of signals to the current mask. 147 BLOCK = rt::SIG_BLOCK, 148 // Removes the given set of signals from the current mask. 149 UNBLOCK = rt::SIG_UNBLOCK, 150 // Sets the process mask to the given set. 151 SETMASK = rt::SIG_SETMASK, 152 }; 153 154 export type sigaction = rt::sigact; 155 export type sigset = rt::sigset; 156 157 // Creates a new signal set filled in with the provided signals (or empty if 158 // none are provided). 159 export fn newsigset(items: sig...) sigset = { 160 let set: sigset = 0; 161 rt::sigemptyset(&set); 162 sigset_add(&set, items...); 163 return set; 164 }; 165 166 // Sets a [[sigset]] to empty. 167 export fn sigset_empty(set: *sigset) void = { 168 rt::sigemptyset(set: *rt::sigset); 169 }; 170 171 // Adds signals to a [[sigset]]. 172 export fn sigset_add(set: *sigset, items: sig...) void = { 173 for (let i = 0z; i < len(items); i += 1) { 174 rt::sigaddset(set: *rt::sigset, items[i])!; 175 }; 176 }; 177 178 // Removes signals from a [[sigset]]. 179 export fn sigset_del(set: *sigset, items: sig...) void = { 180 for (let i = 0z; i < len(items); i += 1) { 181 rt::sigdelset(set: *rt::sigset, items[i])!; 182 }; 183 }; 184 185 // Adds all platform-defined signals to a [[sigset]]. 186 export fn sigset_fill(set: *sigset) void = { 187 rt::sigfillset(set: *rt::sigset)!; 188 }; 189 190 // Returns true if the given signal is a member of this [[sigset]]. 191 export fn sigset_member(set: *sigset, item: sig) bool = { 192 return rt::sigismember(set: *rt::sigset, item)!; 193 }; 194 195 // Waits for a signal among the given [[sigset]] to be delivered, then returns 196 // the signal number. 197 // 198 // If a signal is received while waiting, [[errors::interrupted]] is returned. 199 // Most consumers of this function will likely wish to block all signals and 200 // handle them exclusively through [[wait]] et al, in which case this error 201 // cannot occur. 202 export fn wait(set: *sigset) (sig | errors::interrupted) = { 203 let signal = 0i; 204 match (rt::sigwait(set: *rt::sigset, &signal)) { 205 case let err: rt::errno => 206 assert(err == rt::EINTR); 207 return errors::interrupted; 208 case void => 209 return signal: sig; 210 }; 211 }; 212 213 // Provides additional information about signal deliveries. Only the members 214 // defined by POSIX are available here; cast to [[rt::siginfo]] to access 215 // non-portable members. 216 export type siginfo = struct { 217 // The signal number being delivered. 218 signo: sig, 219 // The signal code, if any. 220 code: code, 221 // The errno, if any, associated with this signal. See 222 // [[errors::errno]] to convert to a Hare-native error. 223 errno: rt::errno, 224 union { 225 union { 226 struct { 227 // Process ID of the sender. 228 pid: unix::pid, 229 // Real user ID of the sending process. 230 uid: unix::uid, 231 }, 232 struct { 233 // Address of the faulting instruction. 234 addr: *opaque, 235 }, 236 }, 237 // Pads the structure out to the length used by the kernel; do not use. 238 _si_pad: [29]int, 239 }, 240 }; 241 242 export type code = enum int { 243 NOINFO = rt::SI_NOINFO, // no signal information 244 USER = rt::SI_USER, // user generated signal via kill() 245 LWP = rt::SI_LWP, // user generated signal via lwp_kill() 246 QUEUE = rt::SI_QUEUE, // user generated signal via sigqueue() 247 TIMER = rt::SI_TIMER, // from timer expiration 248 249 ILLOPC = rt::ILL_ILLOPC, // sig::ILL: illegal opcode 250 ILLOPN = rt::ILL_ILLOPN, // sig::ILL: illegal operand 251 ILLADR = rt::ILL_ILLADR, // sig::ILL: illegal addressing mode 252 ILLTRP = rt::ILL_ILLTRP, // sig::ILL: illegal trap 253 PRVOPC = rt::ILL_PRVOPC, // sig::ILL: privileged opcode 254 PRVREG = rt::ILL_PRVREG, // sig::ILL: privileged register 255 COPROC = rt::ILL_COPROC, // sig::ILL: co-processor 256 BADSTK = rt::ILL_BADSTK, // sig::ILL: bad stack 257 258 INTDIV = rt::FPE_INTDIV, // sig::FPE: integer divide by zero 259 INTOVF = rt::FPE_INTOVF, // sig::FPE: integer overflow 260 FLTDIV = rt::FPE_FLTDIV, // sig::FPE: floating point divide by zero 261 FLTOVF = rt::FPE_FLTOVF, // sig::FPE: floating point overflow 262 FLTUND = rt::FPE_FLTUND, // sig::FPE: floating point underflow 263 FLTRES = rt::FPE_FLTRES, // sig::FPE: floating point inexact result 264 FLTINV = rt::FPE_FLTINV, // sig::FPE: invalid floating point operation 265 FLTSUB = rt::FPE_FLTSUB, // sig::FPE: subscript out of range 266 267 MAPERR = rt::SEGV_MAPERR, // sig::SEGV: address not mapped to object 268 ACCERR = rt::SEGV_ACCERR, // sig::SEGV: invalid permissions 269 270 ADRALN = rt::BUS_ADRALN, // sig::BUS: invalid address alignment 271 ADRERR = rt::BUS_ADRERR, // sig::BUS: non-existent physical address 272 OBJERR = rt::BUS_OBJERR, // sig::BUS: object specific hardware error 273 274 BRKPT = rt::TRAP_BRKPT, // sig::TRAP: breakpoint trap 275 TRACE = rt::TRAP_TRACE, // sig::TRAP: trace trap 276 277 EXITED = rt::CLD_EXITED, // sig::CHLD: child has exited 278 KILLED = rt::CLD_KILLED, // sig::CHLD: child was killed 279 DUMPED = rt::CLD_DUMPED, // sig::CHLD: child has coredumped 280 TRAPPED = rt::CLD_TRAPPED, // sig::CHLD: traced child has stopped 281 STOPPED = rt::CLD_STOPPED, // sig::CHLD: child has stopped on signal 282 CONTINUED = rt::CLD_CONTINUED, // sig::CHLD: stopped child has continued 283 }; 284 285 export type flag = enum int { 286 // For use with sig::CHLD. Prevents notifications when child processes 287 // stop (e.g. via sig::STOP) or resume (i.e. sig::CONT). 288 NOCLDSTOP = rt::SA_NOCLDSTOP: int, 289 // For use with sig::CHLD. Do not transform children into zombies when 290 // they terminate. Note that POSIX leaves the delivery of sig::CHLD 291 // unspecified when this flag is present; some systems will still 292 // deliver a signal and others may not. 293 NOCLDWAIT = rt::SA_NOCLDWAIT: int, 294 // Uses an alternate stack when handling this signal. See 295 // [[setaltstack]] and [[getaltstack]] for details. 296 ONSTACK = rt::SA_ONSTACK: int, 297 // Do not add the signal to the signal mask while executing the signal 298 // handler. This can cause the same signal to be delivered again during 299 // the execution of the signal handler. 300 NODEFER = rt::SA_NODEFER: int, 301 // Restore the signal handler to the default behavior upon entering the 302 // signal handler. 303 RESETHAND = rt::SA_RESETHAND: int, 304 // Makes certain system calls restartable across signals. See signal(7) 305 // or similar documentation for your local system for details. 306 RESTART = rt::SA_RESTART: int, 307 }; 308 309 // All possible signals. 310 export type sig = enum int { 311 HUP = rt::SIGHUP, // Hangup. 312 INT = rt::SIGINT, // Terminal interrupt. 313 QUIT = rt::SIGQUIT, // Terminal quit. 314 ILL = rt::SIGILL, // Illegal instruction. 315 TRAP = rt::SIGTRAP, // Trace/breakpoint trap. 316 ABRT = rt::SIGABRT, // Process abort. 317 EMT = rt::SIGEMT, // Emulate instruction executed. 318 FPE = rt::SIGFPE, // Erroneous arithmetic operation. 319 KILL = rt::SIGKILL, // Kill (cannot be caught or ignored). 320 BUS = rt::SIGBUS, // Access to an undefined portion of a memory object. 321 SEGV = rt::SIGSEGV, // Invalid memory reference. 322 SYS = rt::SIGSYS, // Bad system call. 323 PIPE = rt::SIGPIPE, // Write on a pipe with no one to read it. 324 ALRM = rt::SIGALRM, // Alarm clock. 325 TERM = rt::SIGTERM, // Termination. 326 URG = rt::SIGURG, // High bandwidth data is available at a socket. 327 STOP = rt::SIGSTOP, // Stop executing (cannot be caught or ignored). 328 TSTP = rt::SIGTSTP, // Terminal stop. 329 CONT = rt::SIGCONT, // Continue executing, if stopped. 330 CHLD = rt::SIGCHLD, // Child process terminated, stopped, or continued. 331 TTIN = rt::SIGTTIN, // Background process attempting read. 332 TTOU = rt::SIGTTOU, // Background process attempting write. 333 IO = rt::SIGIO, // I/O now possible. 334 XCPU = rt::SIGXCPU, // CPU time limit exceeded. 335 XFSZ = rt::SIGXFSZ, // File size limit exceeded. 336 VTALRM = rt::SIGVTALRM, // Virtual timer expired. 337 PROF = rt::SIGPROF, // Profiling timer expired. 338 WINCH = rt::SIGWINCH, // Window resize. 339 INFO = rt::SIGINFO, // Status request from keyboard. 340 USR1 = rt::SIGUSR1, // User-defined signal 1. 341 USR2 = rt::SIGUSR2, // User-defined signal 2. 342 }; 343 344 // Returns the human friendly name of a given signal. 345 export fn signame(sig: sig) const str = { 346 switch (sig) { 347 case sig::HUP => 348 return "SIGHUP"; 349 case sig::INT => 350 return "SIGINT"; 351 case sig::QUIT => 352 return "SIGQUIT"; 353 case sig::ILL => 354 return "SIGILL"; 355 case sig::TRAP => 356 return "SIGTRAP"; 357 case sig::ABRT => 358 return "SIGABRT"; 359 case sig::EMT => 360 return "SIGEMT"; 361 case sig::FPE => 362 return "SIGFPE"; 363 case sig::KILL => 364 return "SIGKILL"; 365 case sig::BUS => 366 return "SIGBUS"; 367 case sig::SEGV => 368 return "SIGSEGV"; 369 case sig::SYS => 370 return "SIGSYS"; 371 case sig::PIPE => 372 return "SIGPIPE"; 373 case sig::ALRM => 374 return "SIGALRM"; 375 case sig::TERM => 376 return "SIGTERM"; 377 case sig::URG => 378 return "SIGURG"; 379 case sig::STOP => 380 return "SIGSTOP"; 381 case sig::TSTP => 382 return "SIGTSTP"; 383 case sig::CONT => 384 return "SIGCONT"; 385 case sig::CHLD => 386 return "SIGCHLD"; 387 case sig::TTIN => 388 return "SIGTTIN"; 389 case sig::TTOU => 390 return "SIGTTOU"; 391 case sig::IO => 392 return "SIGIO"; 393 case sig::XCPU => 394 return "SIGXCPU"; 395 case sig::XFSZ => 396 return "SIGXFSZ"; 397 case sig::VTALRM => 398 return "SIGVTALRM"; 399 case sig::PROF => 400 return "SIGPROF"; 401 case sig::WINCH => 402 return "SIGWINCH"; 403 case sig::INFO => 404 return "SIGINFO"; 405 case sig::USR1 => 406 return "SIGUSR1"; 407 case sig::USR2 => 408 return "SIGUSR2"; 409 }; 410 };