9#include <sys/syscall.h>
15 return clock_gettime(CLOCK_MONOTONIC, &now) ? -1 : (int64_t)now.tv_sec * 1000000000 + now.tv_nsec;
18int cw_read(
int fd,
void* data,
size_t size) {
19 unsigned char* bytes = data;
20 const int64_t end = cw_now() + INT64_C(10000000000);
22 int64_t left = end - cw_now();
25 struct pollfd ready = {.fd = fd, .events = POLLIN};
26 int result = poll(&ready, 1, (
int)(left / 1000000 + 1));
27 if (result < 0 && errno == EINTR)
31 ssize_t n = read(fd, bytes, size);
32 if (n < 0 && errno == EINTR)
42int cw_write(
int fd,
const void* data,
size_t size) {
43 const unsigned char* bytes = data;
45 ssize_t n = write(fd, bytes, size);
46 if (n < 0 && errno == EINTR)
56int cw_send(
int fd,
char value) {
57 return cw_write(fd, &value, 1);
60int cw_receive(
int fd,
char value) {
62 return cw_read(fd, &actual, 1) || actual != value ? -1 : 0;
65int cw_atomic_wait(atomic_uint* value,
unsigned expected) {
66 const int64_t end = cw_now() + INT64_C(10000000000);
67 while (cw_now() < end) {
68 if (atomic_load_explicit(value, memory_order_acquire) == expected)
75int cw_spawn(
struct cw_child* child, pid_t group, uid_t uid,
int exit_code) {
76 int command[2], report[2];
89 if ((group >= 0 && setpgid(0, group)) ||
90 (uid != (uid_t)-1 && setresuid(uid, uid + 1, uid + 2)) || cw_send(report[1],
'R'))
94 if (cw_read(command[0], &request, 1))
99 if (raise(SIGSTOP) || cw_send(report[1],
'C'))
101 }
else if (request ==
'B') {
102 volatile unsigned value = 1;
103 for (
unsigned i = 0; i < 2000000; ++i)
104 value = value * 1664525u + i;
105 if (cw_send(report[1],
'B'))
119 *child = (
struct cw_child){pid, command[1], report[0]};
120 if (cw_receive(child->report,
'R')) {
127int cw_reap(pid_t pid,
int milliseconds) {
128 const int64_t end = cw_now() + (int64_t)milliseconds * 1000000;
129 while (cw_now() < end) {
131 pid_t result = waitpid(pid, &status, WNOHANG);
133 return WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status);
134 if (result < 0 && errno != EINTR)
136 struct timespec delay = {0, 2000000};
137 nanosleep(&delay, NULL);
140 while (waitpid(pid, NULL, 0) < 0 && errno == EINTR) {
145void cw_cleanup(
struct cw_child* child) {
146 if (child->pid > 0) {
147 kill(child->pid, SIGKILL);
148 cw_reap(child->pid, 1000);
150 if (child->command >= 0)
151 close(child->command);
152 if (child->report >= 0)
153 close(child->report);
154 *child = (
struct cw_child)CW_CHILD_INIT;
157int cw_info(
const siginfo_t* info, pid_t pid, uid_t uid,
int code,
int status) {
158 if (info->si_signo == SIGCHLD && !info->si_errno && info->si_pid == pid && info->si_uid == uid &&
159 info->si_code == code && info->si_status == status)
162 "siginfo: signo=%d errno=%d pid=%d uid=%u code=%d status=%d; expected %d/%u/%d/%d\n",
163 info->si_signo, info->si_errno, info->si_pid, info->si_uid, info->si_code,
164 info->si_status, pid, uid, code, status);
168int cw_empty_info(
const siginfo_t* info) {
169 return info->si_signo || info->si_errno || info->si_pid || info->si_uid || info->si_code ||
173int cw_usage(
const struct rusage*
usage) {
174 return usage->ru_utime.tv_sec < 0 ||
usage->ru_utime.tv_usec < 0 ||
175 usage->ru_utime.tv_usec >= 1000000 ||
usage->ru_stime.tv_sec < 0 ||
176 usage->ru_stime.tv_usec < 0 ||
usage->ru_stime.tv_usec >= 1000000 ||
177 cw_bytes((
const unsigned char*)
usage + CW_RUSAGE_BYTES,
sizeof(*
usage) - CW_RUSAGE_BYTES,
181int cw_bytes(
const void* buffer,
size_t size,
unsigned char value) {
182 const unsigned char* bytes = buffer;
183 for (
size_t i = 0; i < size; ++i)
184 if (bytes[i] != value)
189long cw_raw_waitid(idtype_t type, id_t
id,
void* info,
int options,
struct rusage*
usage) {
190 return syscall(SYS_waitid, type,
id, info,
options,
usage);