drd/tests/swapcontext: Improve the portability of this test further
[valgrind.git] / drd / tests / swapcontext.c
blob6257b6d930733ffb8dc39ae55f839d22d3cb4e3e
1 /* See also https://bugs.kde.org/show_bug.cgi?id=432381. */
3 #define _GNU_SOURCE
5 #include <assert.h>
6 #include <limits.h>
7 #include <pthread.h>
8 #include <signal.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/time.h>
12 #include <sys/timerfd.h>
13 #include <ucontext.h>
14 #include <unistd.h>
15 #include "valgrind.h"
17 #define STACKSIZE (PTHREAD_STACK_MIN + 4096)
19 typedef struct thread_local {
20 ucontext_t uc[3];
21 size_t nrsw;
22 } thread_local_t;
24 static void f(void *data, int n)
26 enum { NR_SWITCHES = 200000 };
27 thread_local_t *tlocal = data;
29 while (1) {
30 struct timespec delay = { .tv_nsec = 1000 };
31 nanosleep(&delay, NULL);
32 if (++tlocal->nrsw == NR_SWITCHES)
33 return;
34 swapcontext(&tlocal->uc[n], &tlocal->uc[3 - n]);
38 void *worker(void *data)
40 thread_local_t *tlocal = data;
42 if (getcontext(&(tlocal->uc[1])) < 0)
43 abort();
44 if (getcontext(&(tlocal->uc[2])) < 0)
45 abort();
47 tlocal->uc[1].uc_link = &tlocal->uc[0];
48 tlocal->uc[1].uc_stack.ss_sp = malloc(STACKSIZE);
49 tlocal->uc[1].uc_stack.ss_size = STACKSIZE;
50 makecontext(&tlocal->uc[1], (void (*)(void))f, 2, tlocal, 1);
51 (void)VALGRIND_STACK_REGISTER(tlocal->uc[1].uc_stack.ss_sp,
52 tlocal->uc[1].uc_stack.ss_sp +
53 tlocal->uc[1].uc_stack.ss_size);
55 tlocal->uc[2].uc_link = &tlocal->uc[0];
56 tlocal->uc[2].uc_stack.ss_sp = malloc(STACKSIZE);
57 tlocal->uc[2].uc_stack.ss_size = STACKSIZE;
58 makecontext(&tlocal->uc[2], (void (*)(void))f, 2, tlocal, 2);
59 (void)VALGRIND_STACK_REGISTER(tlocal->uc[2].uc_stack.ss_sp,
60 tlocal->uc[2].uc_stack.ss_sp +
61 tlocal->uc[2].uc_stack.ss_size);
63 swapcontext(&tlocal->uc[0], &tlocal->uc[1]);
64 return NULL;
67 int main(int argc, char *argv[])
69 enum { NR = 32 };
70 thread_local_t tlocal[NR];
71 pthread_t thread[NR];
72 pthread_attr_t attr;
73 int i, res;
75 memset(tlocal, 0, sizeof(tlocal));
77 pthread_attr_init(&attr);
78 res = pthread_attr_setstacksize(&attr, STACKSIZE);
79 assert(res == 0);
81 for (i = 0; i < NR; i++)
82 pthread_create(&thread[i], &attr, worker, &tlocal[i]);
84 pthread_attr_destroy(&attr);
86 // Wait until the threads have been created.
87 sleep(1);
88 for (i = 0; i < NR; i++)
89 pthread_kill(thread[i], SIGALRM);
91 for (i = 0; i < NR; i++)
92 pthread_join(thread[i], NULL);
94 return 0;