11int64_t ed_now(clockid_t clock) {
13 return clock_gettime(clock, &now) ? -1 : (int64_t)now.tv_sec * 1000000000 + now.tv_nsec;
15struct timespec ed_timespec(int64_t nanoseconds) {
16 return (
struct timespec){nanoseconds / 1000000000, nanoseconds % 1000000000};
18void ed_pause(
int milliseconds) {
19 struct timespec pause = ed_timespec((int64_t)milliseconds * 1000000);
20 while (nanosleep(&pause, &pause) && errno == EINTR) {
23int ed_wait(
volatile int* flag,
int milliseconds) {
24 int64_t deadline = ed_now(CLOCK_MONOTONIC) + (int64_t)milliseconds * 1000000;
25 while (!__atomic_load_n(flag, __ATOMIC_ACQUIRE)) {
26 if (ed_now(CLOCK_MONOTONIC) >= deadline)
32int ed_reap(pid_t child,
int milliseconds) {
33 int64_t deadline = ed_now(CLOCK_MONOTONIC) + (int64_t)milliseconds * 1000000;
34 while (ed_now(CLOCK_MONOTONIC) < deadline) {
36 pid_t result = waitpid(child, &status, WNOHANG);
38 return WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status);
39 if (result < 0 && errno != EINTR)
44 while (waitpid(child, NULL, 0) < 0 && errno == EINTR) {
48int ed_send_fd(
int socket,
int fd) {
50 struct iovec iov = {&byte, 1};
53 char bytes[CMSG_SPACE(
sizeof(
int))];
55 struct msghdr
message = {.msg_iov = &iov,
57 .msg_control = control.bytes,
58 .msg_controllen =
sizeof(control.bytes)};
59 struct cmsghdr* item = CMSG_FIRSTHDR(&
message);
60 item->cmsg_level = SOL_SOCKET;
61 item->cmsg_type = SCM_RIGHTS;
62 item->cmsg_len = CMSG_LEN(
sizeof(
int));
63 memcpy(CMSG_DATA(item), &fd,
sizeof(fd));
64 return sendmsg(socket, &
message, 0) == 1 ? 0 : -1;
66int ed_receive_fd(
int socket) {
68 struct iovec iov = {&byte, 1};
71 char bytes[CMSG_SPACE(
sizeof(
int))];
73 struct msghdr
message = {.msg_iov = &iov,
75 .msg_control = control.bytes,
76 .msg_controllen =
sizeof(control.bytes)};
77 if (recvmsg(socket, &
message, MSG_CMSG_CLOEXEC) != 1 ||
message.msg_flags & MSG_CTRUNC)
79 struct cmsghdr* item = CMSG_FIRSTHDR(&
message);
80 if (!item || item->cmsg_level != SOL_SOCKET || item->cmsg_type != SCM_RIGHTS ||
81 item->cmsg_len != CMSG_LEN(
sizeof(
int)))
84 memcpy(&fd, CMSG_DATA(item),
sizeof(fd));
87int ed_readable(
int fd,
int milliseconds) {
88 struct pollfd entry = {.fd = fd, .events = POLLIN};
89 int result = poll(&entry, 1, milliseconds);
90 return result > 0 ? !!(entry.revents & POLLIN) : result;
92void* ed_read_thread(
void* argument) {
94 __atomic_store_n(&
reader->started, 1, __ATOMIC_RELEASE);
97 reader->finished = ed_now(CLOCK_MONOTONIC);
98 __atomic_store_n(&
reader->done, 1, __ATOMIC_RELEASE);
102static int run(
const char* name,
int (*test)(
void)) {
103 printf(
"EVENT-DESCRIPTOR-CONTRACT: BEGIN %s\n", name);
105 const int clock_suite = !strcmp(name,
"clock");
106 int64_t realtime = ed_now(CLOCK_REALTIME), monotonic = ed_now(CLOCK_MONOTONIC);
107 pid_t child = fork();
115 _exit(result ? 1 : 0);
117 int result = ed_reap(child, 35000);
118 if (clock_suite && geteuid() == 0) {
120 struct timespec restored = ed_timespec(realtime + ed_now(CLOCK_MONOTONIC) - monotonic);
121 if (clock_settime(CLOCK_REALTIME, &restored))
124 printf(
"EVENT-DESCRIPTOR-CONTRACT: %s %s status=%d\n", result ?
"FAIL" :
"PASS", name, result);
128int main(
int argc,
char** argv) {
129 if (argc > 1 && !strcmp(argv[1],
"signalfd-exec"))
130 return event_descriptor_signalfd_exec(argc, argv);
131 if (argc > 1 && !strcmp(argv[1],
"timerfd-exec"))
132 return event_descriptor_timerfd_exec(argc, argv);
133 static const struct {
136 } suites[] = {{
"signalfd", event_descriptor_test_signalfd},
137 {
"timerfd", event_descriptor_test_timerfd},
138 {
"clock", event_descriptor_test_clock}};
140 for (
unsigned n = 0; n <
sizeof(suites) /
sizeof(suites[0]); ++n) {
141 if (argc > 1 && strcmp(argv[1], suites[n].name))
144 if (run(suites[n].name, suites[n].test))
149 puts(
"EVENT-DESCRIPTOR-CONTRACT: END PASS");