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