+freebsd.ha (15222B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use errors; 5 use rt; 6 use time; 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 export fn handle( 19 signum: sig, 20 handler: *handler, 21 flags: flag = flag::NONE, 22 mask: nullable *sigset = null, 23 ) sigaction = { 24 flags |= rt::SA_SIGINFO: flag; 25 let mask = match (mask) { 26 case null => 27 yield newsigset(); 28 case let set: *sigset => 29 yield *set; 30 }; 31 32 let new = rt::sigact { 33 sa_sigaction = handler: *fn(int, *rt::siginfo, *opaque) void, 34 sa_mask = mask, 35 sa_flags = flags, 36 }; 37 let old = rt::sigact { 38 sa_sigaction = null: *fn(int, *rt::siginfo, *opaque) void, 39 ... 40 }; 41 match (rt::sigaction(signum, &new, &old)) { 42 case rt::errno => 43 abort("sigaction failed (invalid signal?)"); 44 case int => void; 45 }; 46 return old; 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 int => void; 55 }; 56 }; 57 58 // Unregisters signal handlers for the specified signal. 59 export fn reset(signum: sig) void = { 60 handle(signum, rt::SIG_DFL: *handler); 61 }; 62 63 // Unregisters all signal handlers. 64 export fn resetall() void = { 65 // sig::KILL and sig::STOP deliberately omitted; see sigaction(2) 66 reset(sig::HUP); 67 reset(sig::INT); 68 reset(sig::QUIT); 69 reset(sig::ILL); 70 reset(sig::TRAP); 71 reset(sig::ABRT); 72 reset(sig::EMT); 73 reset(sig::FPE); 74 reset(sig::BUS); 75 reset(sig::SEGV); 76 reset(sig::SYS); 77 reset(sig::PIPE); 78 reset(sig::ALRM); 79 reset(sig::TERM); 80 reset(sig::URG); 81 reset(sig::TSTP); 82 reset(sig::CONT); 83 reset(sig::CHLD); 84 reset(sig::TTIN); 85 reset(sig::TTOU); 86 reset(sig::IO); 87 reset(sig::XCPU); 88 reset(sig::XFSZ); 89 reset(sig::VTALRM); 90 reset(sig::PROF); 91 reset(sig::WINCH); 92 reset(sig::INFO); 93 reset(sig::USR1); 94 reset(sig::USR2); 95 reset(sig::THR); 96 reset(sig::LIBRT); 97 }; 98 99 // Prevents given signal from arriving to the current process. 100 // One common use case is to ignore SIGCHLD to avoid zombie child processes. 101 export fn ignore(signum: sig) void = { 102 handle(signum, rt::SIG_IGN: *handler); 103 }; 104 105 // Adds the given list of signals to the process's current signal mask, 106 // returning the old signal mask. This is a convenience function around 107 // [[setprocmask]]. 108 export fn block(signals: sig...) sigset = { 109 let new = newsigset(signals...); 110 return setprocmask(how::BLOCK, &new); 111 }; 112 113 // Removes the given list of signals from the process's current signal mask, 114 // returning the old signal mask. This is a convenience function around 115 // [[setprocmask]]. 116 export fn unblock(signals: sig...) sigset = { 117 let new = newsigset(signals...); 118 return setprocmask(how::UNBLOCK, &new); 119 }; 120 121 // Sets the process's signal mask, returning the previous mask. 122 export fn setprocmask(how: how, mask: *sigset) sigset = { 123 let old = sigset { ... }; 124 rt::sigprocmask(how, mask: *rt::sigset, &old)!; 125 return old; 126 }; 127 128 // Gets the current process's signal mask. 129 export fn getprocmask() sigset = { 130 let old = sigset { ... }; 131 rt::sigprocmask(how::SETMASK, null, &old)!; 132 return old; 133 }; 134 135 // Defines the modes of operation for [[setprocmask]]. 136 export type how = enum int { 137 // Adds the given set of signals to the current mask. 138 BLOCK = rt::SIG_BLOCK, 139 // Removes the given set of signals from the current mask. 140 UNBLOCK = rt::SIG_UNBLOCK, 141 // Sets the process mask to the given set. 142 SETMASK = rt::SIG_SETMASK, 143 }; 144 145 export type sigaction = rt::sigact; 146 147 export type sigset = rt::sigset; 148 149 // Creates a new signal set filled in with the provided signals (or empty if 150 // none are provided). 151 export fn newsigset(items: sig...) sigset = { 152 let set = sigset { ... }; 153 rt::sigemptyset(&set); 154 sigset_add(&set, items...); 155 return set; 156 }; 157 158 // Sets a [[sigset]] to empty. 159 export fn sigset_empty(set: *sigset) void = { 160 rt::sigemptyset(set: *rt::sigset); 161 }; 162 163 // Adds signals to a [[sigset]]. 164 export fn sigset_add(set: *sigset, items: sig...) void = { 165 for (let i = 0z; i < len(items); i += 1) { 166 rt::sigaddset(set: *rt::sigset, items[i])!; 167 }; 168 }; 169 170 // Removes signals from a [[sigset]]. 171 export fn sigset_del(set: *sigset, items: sig...) void = { 172 for (let i = 0z; i < len(items); i += 1) { 173 rt::sigdelset(set: *rt::sigset, items[i])!; 174 }; 175 }; 176 177 // Adds all platform-defined signals to a [[sigset]]. 178 export fn sigset_fill(set: *sigset) void = { 179 rt::sigfillset(set: *rt::sigset)!; 180 }; 181 182 // Returns true if the given signal is a member of this [[sigset]]. 183 export fn sigset_member(set: *sigset, item: sig) bool = { 184 return rt::sigismember(set: *rt::sigset, item)!; 185 }; 186 187 // Waits for a signal among the given [[sigset]] to be delivered, then returns 188 // the signal number. 189 // 190 // If a signal is received while waiting, [[errors::interrupted]] is returned. 191 // Most consumers of this function will likely wish to block all signals and 192 // handle them exclusively through [[wait]] et al, in which case this error 193 // cannot occur. 194 // 195 // See also [[waitinfo]] and [[timedwait]]. 196 export fn wait(set: *sigset) (sig | errors::interrupted) = { 197 let signal = 0i; 198 match (rt::sigwait(set: *rt::sigset, &signal)) { 199 case let err: rt::errno => 200 assert(err == rt::EINTR); 201 return errors::interrupted; 202 case void => 203 return signal: sig; 204 }; 205 }; 206 207 // Waits for a signal among the given [[sigset]] to be delivered, then returns 208 // the corresponding [[siginfo]] data. 209 // 210 // See notes on [[wait]] regarding the [[errors::interrupted]] case. 211 // 212 // This function is designed to provide the portable subset of the semantics of 213 // sigwaitinfo(3) as defined by POSIX.1-2008. To access the complete siginfo_t 214 // structure provided by the underlying platform, use [[rt::sigwaitinfo]] and 215 // [[rt::siginfo_t]] directly. 216 // 217 // Note that this function is not supported on OpenBSD. 218 export fn waitinfo(set: *sigset) (siginfo | errors::interrupted) = { 219 let info = rt::siginfo { 220 si_addr = null: *opaque, 221 si_value = rt::sigval { ... }, 222 ... 223 }; 224 match (rt::sigwaitinfo(set: *rt::sigset, &info)) { 225 case let err: rt::errno => 226 assert(err == rt::EINTR); 227 return errors::interrupted; 228 case int => 229 return *(&info: *siginfo); 230 }; 231 }; 232 233 // Waits for a signal among the given [[sigset]] to be delivered, then returns 234 // the corresponding [[siginfo]] data. 235 // 236 // Returns a [[siginfo]] if a signal is successfully processed through this 237 // function, or [[errors::again]] if the timeout expired. See notes on [[wait]] 238 // regarding the [[errors::interrupted]] case. 239 // 240 // This function is designed to provide the portable subset of the semantics of 241 // sigtimedwait(3) as defined by POSIX.1-2008. To access the complete siginfo_t 242 // structure provided by the underlying platform, use [[rt::sigtimedwait]] and 243 // [[rt::siginfo_t]] directly. 244 // 245 // Note that this function is not supported on OpenBSD. 246 export fn timedwait( 247 set: *sigset, 248 timeout: time::duration, 249 ) (siginfo | errors::interrupted | errors::again) = { 250 let info = rt::siginfo { 251 si_addr = null: *opaque, 252 si_value = rt::sigval { ... }, 253 ... 254 }; 255 let to = time::duration_to_timeval(timeout); 256 match (rt::sigwaitinfo(set: *rt::sigset, &info)) { 257 case let err: rt::errno => 258 switch (err) { 259 case rt::EINTR => 260 return errors::interrupted; 261 case rt::EAGAIN => 262 return errors::again; 263 case => abort(); 264 }; 265 case int => 266 return *(&info: *siginfo); 267 }; 268 }; 269 270 // Provides additional information about signal deliveries. Only the members 271 // defined by POSIX are available here; cast to [[rt::siginfo]] to access 272 // non-portable members. 273 export type siginfo = union { 274 struct { 275 // The signal number being delivered. 276 signo: sig, 277 // The errno, if any, associated with this signal. See 278 // [[errors::errno]] to convert to a Hare-native error. 279 errno: rt::errno, 280 // The signal code, if any. 281 code: code, 282 // Process ID of the sender. 283 pid: unix::pid, 284 // Real user ID of the sending process. 285 uid: unix::uid, 286 // Exit value or signal. 287 status: int, 288 // Address of the faulting instruction. 289 addr: *opaque, 290 }, 291 // Pads the structure out to the length used by the kernel; do not use. 292 _si_pad: [128 - 3 * size(int)]u8, 293 }; 294 295 // A code indicating why a signal was sent. 296 export type code = enum int { 297 USER = 0, // sent by userspace program (kill) 298 KERNEL = 128, // sent by kernel 299 QUEUE = -1, // sent by sigqueue 300 TIMER = -2, // generated by expiration of a timer 301 MESQ = -3, // generated by arrival of a message on an empty queue 302 ASYNCIO = -4, // generated by completion of an asynchronous I/O request 303 SIGIO = -5, 304 TKILL = -6, // sent by userspace program (tkill, tgkill) 305 ASYNCNL = -60, 306 307 ILLOPC = 1, // sig::ILL: illegal opcode 308 ILLOPN = 2, // sig::ILL: illegal operand 309 ILLADR = 3, // sig::ILL: illegal addressing mode 310 ILLTRP = 4, // sig::ILL: illegal trap 311 PRVOPC = 5, // sig::ILL: privileged opcode 312 PRVREG = 6, // sig::ILL: privileged register 313 COPROC = 7, // sig::ILL: coprocessor error 314 BADSTK = 8, // sig::ILL: internal stack error 315 316 INTOVF = 1, // sig::FPE: integer overflow 317 INTDIV = 2, // sig::FPE: integer divide by zero 318 FLTDIV = 3, // sig::FPE: floating-point divide by zero 319 FLTOVF = 4, // sig::FPE: floating-point overflow 320 FLTUND = 5, // sig::FPE: floating-point underflow 321 FLTRES = 6, // sig::FPE: floating-point inexact result 322 FLTINV = 7, // sig::FPE: invalid floating-point operation 323 FLTSUB = 8, // sig::FPE: subscript out of range 324 325 MAPERR = 1, // sig::SEGV: address not mapped to object 326 ACCERR = 2, // sig::SEGV: invalid permissions for mapped object 327 PKUERR = 100, // sig::SEGV: access was denied by memory protection keys (x86_64) 328 329 ADRALN = 1, // sig::BUS: invalid address alignment 330 ADRERR = 2, // sig::BUS: nonexistent physical address 331 OBJERR = 3, // sig::BUS: object-specific hardware error 332 OOMERR = 100, // sig::BUS: out of memory 333 334 BRKPT = 1, // sig::TRAP: process breakpoint 335 TRACE = 2, // sig::TRAP: process trace trap 336 DTRACE = 3, // sig::TRAP: DTrace induced trap 337 CAP = 4, // sig::TRAP: capabilities protection trap 338 339 EXITED = 1, // sig::CHLD: child exited 340 KILLED = 2, // sig::CHLD: child terminated abnormally without a core file 341 DUMPED = 3, // sig::CHLD: child terminated abnormally with a core file 342 TRAPPED = 4, // sig::CHLD: traced child has trapped 343 STOPPED = 5, // sig::CHLD: child has stopped 344 CONTINUED = 6, // sig::CHLD: stopped child has continued 345 346 IN = 1, // sig::IO: data input available 347 OUT = 2, // sig::IO: output buffers available 348 MSG = 3, // sig::IO: input message available 349 ERR = 4, // sig::IO: I/O error 350 PRI = 5, // sig::IO: high priority input available 351 HUP = 6, // sig::IO: device disconnected 352 }; 353 354 // Flags used to configure the behavior of a signal handler. 355 export type flag = enum int { 356 NONE = 0, 357 // For use with sig::CHLD. Prevents notifications when child processes 358 // stop (e.g. via sig::STOP) or resume (i.e. sig::CONT). 359 NOCLDSTOP = rt::SA_NOCLDSTOP, 360 // For use with sig::CHLD. Do not transform children into zombies when 361 // they terminate. Note that POSIX leaves the delivery of sig::CHLD 362 // unspecified when this flag is present; some systems will still 363 // deliver a signal and others may not. 364 NOCLDWAIT = rt::SA_NOCLDWAIT, 365 // Uses an alternate stack when handling this signal. See 366 // [[setaltstack]] and [[getaltstack]] for details. 367 ONSTACK = rt::SA_ONSTACK, 368 // Do not add the signal to the signal mask while executing the signal 369 // handler. This can cause the same signal to be delivered again during 370 // the execution of the signal handler. 371 NODEFER = rt::SA_NODEFER, 372 // Restore the signal handler to the default behavior upon entering the 373 // signal handler. 374 RESETHAND = rt::SA_RESETHAND, 375 // Makes certain system calls restartable across signals. See signal(7) 376 // or similar documentation for your local system for details. 377 RESTART = rt::SA_RESTART, 378 }; 379 380 // All possible signals. 381 export type sig = enum int { 382 HUP = rt::SIGHUP, // Hangup. 383 INT = rt::SIGINT, // Terminal interrupt. 384 QUIT = rt::SIGQUIT, // Terminal quit. 385 ILL = rt::SIGILL, // Illegal instruction. 386 TRAP = rt::SIGTRAP, // Trace/breakpoint trap. 387 ABRT = rt::SIGABRT, // Process abort. 388 IOT = rt::SIGIOT, // Synonym for ABRT, provided for compatibility. 389 EMT = rt::SIGEMT, // Emulate instruction executed. 390 FPE = rt::SIGFPE, // Erroneous arithmetic operation. 391 KILL = rt::SIGKILL, // Kill (cannot be caught or ignored). 392 BUS = rt::SIGBUS, // Access to an undefined portion of a memory object. 393 SEGV = rt::SIGSEGV, // Invalid memory reference. 394 SYS = rt::SIGSYS, // Bad system call. 395 PIPE = rt::SIGPIPE, // Write on a pipe with no one to read it. 396 ALRM = rt::SIGALRM, // Alarm clock. 397 TERM = rt::SIGTERM, // Termination. 398 URG = rt::SIGURG, // High bandwidth data is available at a socket. 399 STOP = rt::SIGSTOP, // Stop executing (cannot be caught or ignored). 400 TSTP = rt::SIGTSTP, // Terminal stop. 401 CONT = rt::SIGCONT, // Continue executing, if stopped. 402 CHLD = rt::SIGCHLD, // Child process terminated, stopped, or continued. 403 TTIN = rt::SIGTTIN, // Background process attempting read. 404 TTOU = rt::SIGTTOU, // Background process attempting write. 405 IO = rt::SIGIO, // I/O now possible. 406 XCPU = rt::SIGXCPU, // CPU time limit exceeded. 407 XFSZ = rt::SIGXFSZ, // File size limit exceeded. 408 VTALRM = rt::SIGVTALRM, // Virtual timer expired. 409 PROF = rt::SIGPROF, // Profiling timer expired. 410 WINCH = rt::SIGWINCH, // Window resize. 411 INFO = rt::SIGINFO, // Status request from keyboard. 412 USR1 = rt::SIGUSR1, // User-defined signal 1. 413 USR2 = rt::SIGUSR2, // User-defined signal 2. 414 THR = rt::SIGTHR, // Thread interrupt. 415 LIBRT = rt::SIGLIBRT, // Real-time library interrupt. 416 }; 417 418 // Returns the human friendly name of a given signal. 419 export fn signame(sig: sig) const str = { 420 switch (sig) { 421 case sig::HUP => 422 return "SIGHUP"; 423 case sig::INT => 424 return "SIGINT"; 425 case sig::QUIT => 426 return "SIGQUIT"; 427 case sig::ILL => 428 return "SIGILL"; 429 case sig::TRAP => 430 return "SIGTRAP"; 431 case sig::ABRT => 432 return "SIGABRT"; 433 case sig::EMT => 434 return "SIGEMT"; 435 case sig::FPE => 436 return "SIGFPE"; 437 case sig::KILL => 438 return "SIGKILL"; 439 case sig::BUS => 440 return "SIGBUS"; 441 case sig::SEGV => 442 return "SIGSEGV"; 443 case sig::SYS => 444 return "SIGSYS"; 445 case sig::PIPE => 446 return "SIGPIPE"; 447 case sig::ALRM => 448 return "SIGALRM"; 449 case sig::TERM => 450 return "SIGTERM"; 451 case sig::URG => 452 return "SIGURG"; 453 case sig::STOP => 454 return "SIGSTOP"; 455 case sig::TSTP => 456 return "SIGTSTP"; 457 case sig::CONT => 458 return "SIGCONT"; 459 case sig::CHLD => 460 return "SIGCHLD"; 461 case sig::TTIN => 462 return "SIGTTIN"; 463 case sig::TTOU => 464 return "SIGTTOU"; 465 case sig::IO => 466 return "SIGIO"; 467 case sig::XCPU => 468 return "SIGXCPU"; 469 case sig::XFSZ => 470 return "SIGXFSZ"; 471 case sig::VTALRM => 472 return "SIGVTALRM"; 473 case sig::PROF => 474 return "SIGPROF"; 475 case sig::WINCH => 476 return "SIGWINCH"; 477 case sig::INFO => 478 return "SIGINFO"; 479 case sig::USR1 => 480 return "SIGUSR1"; 481 case sig::USR2 => 482 return "SIGUSR2"; 483 case sig::THR => 484 return "SIGTHR"; 485 case sig::LIBRT => 486 return "SIGLIBRT"; 487 }; 488 };