Rainer Orth <r...@cebitec.uni-bielefeld.de> writes: > All tests hang with the default -test.timeout=240.
Thanks for providing access to a Solaris system. Right now it looks like there is a bug, or at least an incompatibility, in the 64-bit versions of getcontext and setcontext. It looks like calling setcontext on the 32-bit version does not change the value of TLS variables, which is also the case on GNU/Linux. In the 64-bit version, calling setcontext does change the value of TLS variables. That is, on the 64-bit version, getcontext preserves the value of TLS variables and setcontext restores the old value. (Of course it's really the pointer, not the TLS variables themselves). This incompatibility has to be a bug, and of course I would prefer that the incompatibility be resolved in favor of the implementation used on GNU/Linux. Here is a program which shows the issue. Compile with -pthread. With -m32 it prints go1: tls == 2. With -m64 it prints go1: tls == 1. The program is too complex for the problem, but it does show the issue. Ian
#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <pthread.h> #include <ucontext.h> __thread int tls; static void die (const char *) __attribute__ ((noreturn)); static void die (const char *msg) { perror (msg); exit (EXIT_FAILURE); } static ucontext_t c1; static void *s1[10]; static ucontext_t c2; static void *s2[10]; static void swap (ucontext_t *, void *fs[10], ucontext_t *, void *ts[10]); static void swap (ucontext_t *fu, void *fs[10], ucontext_t *tu, void *ts[10]) { swapcontext (fu, tu); } static void use_buffer (char *buf) __attribute__ ((noinline)); static void use_buffer (char *buf) { buf[0] = '\0'; } static void down (int i, const char *msg, ucontext_t *me, void *mes[10], ucontext_t *other, void *others[10]) { char buf[10000]; printf ("%s %d\n", msg, i); if (i > 0) { use_buffer (buf); swap (me, mes, other, others); down (i - 1, msg, me, mes, other, others); } else { printf ("i == 0\n"); } } static void go1 (void) { printf ("go1: tls == %d\n", tls); down (2, "go1", &c1, s1, &c2, s2); pthread_exit (NULL); } static void go2 (void) { printf ("go2: tls == %d\n", tls); down (2, "go2", &c2, s2, &c1, s1); pthread_exit (NULL); } struct thread_context { ucontext_t *u; void **s; }; static void * start_thread (void *context) { struct thread_context *tc = (struct thread_context *) context; int block; printf ("start_thread: tls == %d\n", tls); tls = 2; block = 0; setcontext (tc->u); die ("setcontext"); return NULL; } int main (int argc __attribute__ ((unused)), char **argv __attribute__ ((unused))) { pthread_t tid; int err; size_t size; struct thread_context tc; int block; tls = 1; if (getcontext (&c1) < 0) die ("getcontext"); c2 = c1; c1.uc_stack.ss_sp = malloc (1024 * 1024 * 1024); if (c1.uc_stack.ss_sp == NULL) die ("malloc"); c1.uc_stack.ss_flags = 0; c1.uc_stack.ss_size = 1024 * 1024 * 1024; c1.uc_link = NULL; block = 0; makecontext (&c1, go1, 0); c2.uc_stack.ss_sp = malloc (1024 * 1024 * 1024); if (c2.uc_stack.ss_sp == NULL) die ("malloc"); c2.uc_stack.ss_flags = 0; c2.uc_stack.ss_size = 1024 * 1024 * 1024; c2.uc_link = NULL; makecontext (&c2, go2, 0); tc.u = &c1; tc.s = &s1[0]; err = pthread_create (&tid, NULL, start_thread, &tc); if (err != 0) { errno = err; die ("pthread_create"); } err = pthread_join (tid, NULL); if (err != 0) { errno = err; die ("pthread_join"); } exit (EXIT_SUCCESS); }