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