/* See also https://bugs.kde.org/show_bug.cgi?id=432381. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include typedef struct thread_local { ucontext_t uc[3]; size_t nrsw; int tfd; } thread_local_t; static void f(void *data, int n) { enum { NR_SWITCHES = 200000 }; struct pollfd pfd; thread_local_t *tlocal = data; while (1) { memset(&pfd, 0, sizeof(pfd)); pfd.fd = tlocal->tfd; pfd.events = POLLIN; if (poll(&pfd, 1, 0) == 1) { if (++tlocal->nrsw == NR_SWITCHES) return; swapcontext(&tlocal->uc[n], &tlocal->uc[3 - n]); } } } void __valgrind_register_current_stack(void) { pthread_attr_t attr; size_t stacksize; void *stack; if (pthread_getattr_np(pthread_self(), &attr) != 0) abort(); if (pthread_attr_getstack(&attr, &stack, &stacksize) != 0) abort(); VALGRIND_STACK_REGISTER(stack, stack + stacksize); } #define STACKSIZE 8192 void *worker(void *data) { thread_local_t *tlocal = data; struct itimerspec it; __valgrind_register_current_stack(); tlocal->tfd = timerfd_create(CLOCK_REALTIME, 0); if (tlocal->tfd < 0) abort(); it.it_interval.tv_sec = 0; it.it_interval.tv_nsec = 1000; it.it_value.tv_sec = time(NULL); it.it_value.tv_nsec = 1000; if (timerfd_settime(tlocal->tfd, TFD_TIMER_ABSTIME, &it, NULL) < 0) abort(); if (getcontext(&(tlocal->uc[1])) < 0) abort(); if (getcontext(&(tlocal->uc[2])) < 0) abort(); tlocal->uc[1].uc_link = &tlocal->uc[0]; tlocal->uc[1].uc_stack.ss_sp = malloc(STACKSIZE); tlocal->uc[1].uc_stack.ss_size = STACKSIZE; makecontext(&tlocal->uc[1], (void (*)(void))f, 2, tlocal, 1); VALGRIND_STACK_REGISTER(tlocal->uc[1].uc_stack.ss_sp, tlocal->uc[1].uc_stack.ss_sp + tlocal->uc[1].uc_stack.ss_size); tlocal->uc[2].uc_link = &tlocal->uc[0]; tlocal->uc[2].uc_stack.ss_sp = malloc(STACKSIZE); tlocal->uc[2].uc_stack.ss_size = STACKSIZE; makecontext(&tlocal->uc[2], (void (*)(void))f, 2, tlocal, 2); VALGRIND_STACK_REGISTER(tlocal->uc[2].uc_stack.ss_sp, tlocal->uc[2].uc_stack.ss_sp + tlocal->uc[2].uc_stack.ss_size); swapcontext(&tlocal->uc[0], &tlocal->uc[1]); return NULL; } int main(int argc, char *argv[]) { enum { NR = 32 }; thread_local_t tlocal[NR]; pthread_t thread[NR]; int i; memset(tlocal, 0, sizeof(tlocal)); for (i = 0; i < NR; i++) pthread_create(&thread[i], NULL, worker, &tlocal[i]); // Wait until the threads have been created. sleep(1); for (i = 0; i < NR; i++) pthread_kill(thread[i], SIGINT); for (i = 0; i < NR; i++) pthread_join(thread[i], NULL); return 0; }