static void * outer_thread (void *closure) { pthread_t *threads = xcalloc (sizeof (*threads), inner_thread_count); while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED)) { pthread_barrier_t barrier; xpthread_barrier_init (&barrier, NULL, inner_thread_count + 1); for (int i = 0; i < inner_thread_count; ++i) { void *(*func) (void *); if ((i % 2) == 0) func = malloc_first_thread; else func = wait_first_thread; threads[i] = xpthread_create (NULL, func, &barrier); } xpthread_barrier_wait (&barrier); for (int i = 0; i < inner_thread_count; ++i) xpthread_join (threads[i]); xpthread_barrier_destroy (&barrier); } free (threads); return NULL; }
static int do_test (void) { /* Limit the size of the process, so that memory allocation will fail without impacting the entire system. */ { struct rlimit limit; if (getrlimit (RLIMIT_AS, &limit) != 0) { printf ("FAIL: getrlimit (RLIMIT_AS) failed: %m\n"); return 1; } /* This limit, 800MB, is just a heuristic. Any value can be picked. */ long target = 800 * 1024 * 1024; if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > target) { limit.rlim_cur = target; if (setrlimit (RLIMIT_AS, &limit) != 0) { printf ("FAIL: setrlimit (RLIMIT_AS) failed: %m\n"); return 1; } } } xpthread_attr_init (&detached); xpthread_attr_setdetachstate (&detached, PTHREAD_CREATE_DETACHED); /* A large thread stack seems beneficial for reproducing a race condition in detached thread creation. The goal is to reach the limit of the runtime thread stack cache such that the detached thread's stack is unmapped after exit and causes a segfault when the parent reads the thread descriptor data stored on the the unmapped stack. */ xpthread_attr_setstacksize (&detached, 16 * 1024 * 1024); xpthread_barrier_init (&barrier, NULL, creator_threads); pthread_t threads[creator_threads]; for (int i = 0; i < creator_threads; ++i) threads[i] = xpthread_create (NULL, creator_thread, NULL); for (int i = 0; i < creator_threads; ++i) xpthread_join (threads[i]); xpthread_attr_destroy (&detached); xpthread_barrier_destroy (&barrier); return 0; }
static int do_test (void) { unsigned int i; printf ("Starting %d threads to run %lld iterations.\n", thread_count, iteration_count); pthread_t *threads = xmalloc (thread_count * sizeof (pthread_t)); xpthread_barrier_init (&barrier, NULL, thread_count); xpthread_mutex_init (&mutex, NULL); for (i = 0; i < thread_count; i++) threads[i] = xpthread_create (NULL, thr_func, (void *) (uintptr_t) i); for (i = 0; i < thread_count; i++) xpthread_join (threads[i]); xpthread_barrier_destroy (&barrier); free (threads); return EXIT_SUCCESS; }