hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

signal.ha (3866B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 // XXX: sigwaitinfo and sigtimedwait are not yet available in OpenBSD. Quoting
      5 // from OpenBSD's lib/libc/gen/sigwait.c: "need kernel to fill in more siginfo_t
      6 // bits first"
      7 
      8 // sigwait
      9 
     10 @symbol("sigwait") fn libc_sigwait(set: *sigset, sig: *int) int;
     11 
     12 export fn sigwait(set: *sigset, sig: *int) (void | errno) = {
     13 	let res = libc_sigwait(set, sig);
     14 	if (res != -1) {
     15 		return *__errno(): errno;
     16 	};
     17 };
     18 
     19 export fn alarm(sec: uint) uint = {
     20 	let nval = itimerval { ... };
     21 	let oval = itimerval { ... };
     22 	nval.it_value.tv_sec = sec: time_t;
     23 	setitimer(ITIMER_REAL, &nval, &oval)!;
     24 	if (oval.it_value.tv_usec != 0) {
     25 		oval.it_value.tv_sec += 1;
     26 	};
     27 	return oval.it_value.tv_sec: uint;
     28 };
     29 
     30 export def ITIMER_REAL: int = 0;
     31 export def ITIMER_VIRTUAL: int = 1;
     32 export def ITIMER_PROF: int = 2;
     33 
     34 export type itimerval = struct {
     35 	it_interval: timeval,
     36 	it_value: timeval,
     37 };
     38 
     39 // setitimer
     40 
     41 @symbol("setitimer") fn libc_setitimer(
     42 	which: int,
     43 	newval: *itimerval,
     44 	oldval: nullable *itimerval,
     45 ) int;
     46 
     47 export fn setitimer(
     48 	which: int,
     49 	newval: *itimerval,
     50 	oldval: nullable *itimerval,
     51 ) (void | errno) = {
     52 	let res = libc_setitimer(which, newval, oldval);
     53 	if (res != -1) {
     54 		return *__errno(): errno;
     55 	};
     56 };
     57 
     58 // getitimer
     59 
     60 @symbol("getitimer") fn libc_getitimer(
     61 	which: int,
     62 	cur: *itimerval,
     63 ) int;
     64 
     65 export fn getitimer(which: int, cur: *itimerval) (void | errno) = {
     66 	let res = libc_getitimer(which, cur);
     67 	if (res != -1) {
     68 		return *__errno(): errno;
     69 	};
     70 };
     71 
     72 export fn sigemptyset(set: *sigset) void = {
     73 	*set = 0;
     74 };
     75 
     76 export fn sigaddset(set: *sigset, signum: int) (void | errno) = {
     77 	if (signum < 1 || signum > NSIG) {
     78 		return *__errno(): errno;
     79 	};
     80 	*set |= 1u << (signum: uint - 1);
     81 };
     82 
     83 export fn sigdelset(set: *sigset, signum: int) (void | errno) = {
     84 	if (signum < 1 || signum > NSIG) {
     85 		return *__errno(): errno;
     86 	};
     87 	*set &= ~(1u << (signum: uint - 1));
     88 };
     89 
     90 export fn sigismember(set: *sigset, signum: int) (bool | errno) = {
     91 	if (signum < 1 || signum > NSIG) {
     92 		return *__errno(): errno;
     93 	};
     94 	return (*set & (1u << (signum: uint - 1))) != 0;
     95 };
     96 
     97 export fn sigfillset(set: *sigset) (void | errno) = {
     98 	*set = ~0u;
     99 };
    100 
    101 // Test sigset operations do not fail for valid signal numbers.
    102 @test fn sigset_valid_signum() void = {
    103 	let set: sigset = 0;
    104 	sigemptyset(&set);
    105 
    106 	assert(!(sigismember(&set, 1) is errno), "Unexpected error");
    107 	assert(!(sigismember(&set, 15) is errno), "Unexpected error");
    108 	assert(!(sigismember(&set, NSIG) is errno), "Unexpected error");
    109 
    110 	assert(!(sigaddset(&set, 1) is errno), "Unexpected error");
    111 	assert(!(sigaddset(&set, 15) is errno), "Unexpected error");
    112 	assert(!(sigaddset(&set, NSIG) is errno), "Unexpected error");
    113 
    114 	// It's ok to add a signal that is already present in the set.
    115 	assert(!(sigaddset(&set, 1) is errno), "Unexpected error");
    116 
    117 	assert(!(sigdelset(&set, 1) is errno), "Unexpected error");
    118 	assert(!(sigdelset(&set, 15) is errno), "Unexpected error");
    119 	assert(!(sigdelset(&set, NSIG) is errno), "Unexpected error");
    120 
    121 	// It's ok to delete a signal that is not present in the set.
    122 	assert(!(sigdelset(&set, 10) is errno), "Unexpected error");
    123 };
    124 
    125 // Test sigset operations fail for invalid signal numbers.
    126 @test fn sigset_invalid_signum() void = {
    127 	let set: sigset = 0;
    128 	sigemptyset(&set);
    129 
    130 	assert(sigismember(&set, -1) is errno, "Expected error");
    131 	assert(sigismember(&set, 0) is errno, "Expected error");
    132 	assert(sigismember(&set, NSIG + 1) is errno, "Expected error");
    133 
    134 	assert(sigaddset(&set, -1) is errno, "Expected error");
    135 	assert(sigaddset(&set, 0) is errno, "Expected error");
    136 	assert(sigaddset(&set, NSIG + 1) is errno, "Expected error");
    137 
    138 	assert(sigdelset(&set, -1) is errno, "Expected error");
    139 	assert(sigdelset(&set, 0) is errno, "Expected error");
    140 	assert(sigdelset(&set, NSIG + 1) is errno, "Expected error");
    141 };