7#include <sys/syscall.h>
10 pthread_mutex_t mutex;
11 pthread_cond_t condition;
14 int released, destination, cleanup_ok;
16static void condition_cleanup(
void* argument) {
18 waiter->cleanup_ok = sc_tls == 0x8291 && !sc_sample(
waiter->destination);
19 pthread_mutex_unlock(&
waiter->mutex);
21static void* condition_entry(
void* argument) {
23 if (sc_pin(0, sc_cpus[0]))
26 waiter->tid = (pid_t)syscall(SYS_gettid);
28 pthread_mutex_lock(&
waiter->mutex);
29 pthread_cleanup_push(condition_cleanup,
waiter);
30 atomic_store_explicit(&
waiter->ready, 1, memory_order_release);
31 while (!
waiter->released && !result)
32 result = pthread_cond_wait(&
waiter->condition, &
waiter->mutex);
33 result |= sc_sample(
waiter->destination) || sc_tls != 0x8291;
34 pthread_cleanup_pop(0);
35 pthread_mutex_unlock(&
waiter->mutex);
36 return (
void*)(intptr_t)result;
38static int condition_wakeup(
int cancel) {
39 int failed = 0, created = 0, locked = 0;
41 .condition = PTHREAD_COND_INITIALIZER,
42 .destination = sc_cpus[sc_count - 1]};
44 CHECK(pthread_create(&thread, NULL, condition_entry, &
waiter) == 0);
46 CHECK(sc_wait(&
waiter.ready, 1) == 0);
47 CHECK(pthread_mutex_lock(&
waiter.mutex) == 0);
53 CHECK(pthread_cancel(thread) == 0);
56 CHECK(pthread_cond_signal(&
waiter.condition) == 0);
58 CHECK(pthread_mutex_unlock(&
waiter.mutex) == 0);
61 CHECK(pthread_join(thread, &result) == 0);
63 CHECK(cancel ? result == PTHREAD_CANCELED &&
waiter.cleanup_ok : result == NULL);
66 pthread_mutex_unlock(&
waiter.mutex);
68 pthread_cancel(thread);
69 pthread_join(thread, NULL);
71 pthread_cond_destroy(&
waiter.condition);
72 pthread_mutex_destroy(&
waiter.mutex);
77 atomic_uint ready, handled;
79 int fd, mode, destination;
83static _Thread_local
struct io_waiter* current_waiter;
84static void migration_signal(
int number) {
89 unsigned cpu = UINT32_MAX, node = UINT32_MAX;
90 long result = syscall(SYS_getcpu, &cpu, &node, NULL);
92 waiter->handler_ok = number == SIGUSR1 && !result && !node && sc_tls == 0x3498;
93 atomic_store_explicit(&
waiter->handled, 1, memory_order_release);
96static void* io_entry(
void* argument) {
98 if (sc_pin(0, sc_cpus[0]))
102 waiter->tid = (pid_t)syscall(SYS_gettid);
105 sigaddset(&one, SIGUSR1);
106 if (pthread_sigmask(SIG_UNBLOCK, &one, NULL))
108 atomic_store_explicit(&
waiter->ready, 1, memory_order_release);
111 struct pollfd event = {.fd =
waiter->fd, .events = POLLIN};
114 result = poll(&event, 1, 10000);
115 while (result < 0 && errno == EINTR);
116 error = result != 1 || !(
event.revents & POLLIN);
121 count = read(
waiter->fd, &
byte, 1);
122 while (count < 0 && errno == EINTR);
123 error |= count != 1 ||
byte !=
'W' || sc_sample(
waiter->destination) || sc_tls != 0x3498;
124 current_waiter = NULL;
125 return (
void*)(intptr_t)error;
127static int io_wakeup(
int mode) {
128 int failed = 0, created = 0, action_set = 0;
129 int pipefd[2] = {-1, -1};
130 struct sigaction action = {.sa_handler = migration_signal}, previous;
131 sigemptyset(&action.sa_mask);
132 struct io_waiter waiter = {.mode = mode, .destination = sc_cpus[sc_count - 1]};
134 CHECK(sigaction(SIGUSR1, &action, &previous) == 0);
136 CHECK(pipe(pipefd) == 0);
138 CHECK(pthread_create(&thread, NULL, io_entry, &
waiter) == 0);
140 CHECK(sc_wait(&
waiter.ready, 1) == 0);
142 CHECK(pthread_kill(thread, SIGUSR1) == 0);
143 CHECK(sc_wait(&
waiter.handled, 1) == 0 &&
waiter.handler_ok &&
145 CHECK(sc_send(pipefd[1],
'W') == 0);
147 CHECK(pthread_join(thread, &result) == 0);
149 CHECK(result == NULL);
152 pthread_cancel(thread);
153 pthread_join(thread, NULL);
160 sigaction(SIGUSR1, &previous, NULL);
163static void* signal_entry(
void* argument) {
165 if (sc_pin(0, sc_cpus[0]))
168 waiter->tid = (pid_t)syscall(SYS_gettid);
169 atomic_store_explicit(&
waiter->ready, 1, memory_order_release);
172 sigaddset(&one, SIGUSR2);
173 struct timespec timeout = {10, 0};
175 int result = sigtimedwait(&one, &info, &timeout);
176 return (
void*)(intptr_t)(result != SIGUSR2 || info.si_signo != SIGUSR2 ||
177 sc_sample(
waiter->destination) || sc_tls != 0x4289);
179static int signal_wakeup(
void) {
180 int failed = 0, created = 0, masked = 0;
183 sigaddset(&one, SIGUSR2);
186 CHECK(pthread_sigmask(SIG_BLOCK, &one, &old) == 0);
188 CHECK(pthread_create(&thread, NULL, signal_entry, &
waiter) == 0);
191 CHECK(pthread_kill(thread, SIGUSR2) == 0);
193 CHECK(pthread_join(thread, &result) == 0);
195 CHECK(result == NULL);
198 pthread_cancel(thread);
199 pthread_join(thread, NULL);
202 pthread_sigmask(SIG_SETMASK, &old, NULL);
205int sc_wakeups(
void) {
206 return condition_wakeup(0) || condition_wakeup(1) || io_wakeup(0) || io_wakeup(1) ||