static void * allocation_thread_function (void *closure) { struct list { struct list *next; long dummy[4]; }; struct list *head = NULL; size_t allocated = 0; while (allocated < per_thread_allocations) { struct list *new_head = xmalloc (sizeof (*new_head)); allocated += sizeof (*new_head); new_head->next = head; head = new_head; } xpthread_barrier_wait (&barrier); /* Main thread prints first statistics here. */ xpthread_barrier_wait (&barrier); while (head != NULL) { struct list *next_head = head->next; free (head); head = next_head; } return NULL; }
static void * tf_read (void *arg) { int fd; if (arg == NULL) fd = fds[0]; else { char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; tempfd = fd = mkstemp (fname); if (fd == -1) FAIL_EXIT1 ("mkstemp failed: %m"); unlink (fname); xpthread_barrier_wait (&b2); } xpthread_barrier_wait (&b2); ssize_t s; pthread_cleanup_push (cl, NULL); char buf[100]; s = read (fd, buf, sizeof (buf)); pthread_cleanup_pop (0); FAIL_EXIT1 ("read returns with %zd", s); }
static void * tf_readv (void *arg) { int fd; if (arg == NULL) fd = fds[0]; else { char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; tempfd = fd = mkstemp (fname); if (fd == -1) FAIL_EXIT1 ("mkstemp failed: %m"); unlink (fname); xpthread_barrier_wait (&b2); } xpthread_barrier_wait (&b2); ssize_t s; pthread_cleanup_push (cl, NULL); char buf[100]; struct iovec iov[1] = { [0] = { .iov_base = buf, .iov_len = sizeof (buf) } };
static void * thr_func (void *arg) { long long int i; for (i = 0; i < iteration_count; i++) { if ((uintptr_t) arg == 0) { xpthread_mutex_destroy (&mutex); xpthread_mutex_init (&mutex, NULL); } xpthread_barrier_wait (&barrier); /* Test if enabling lock elision works if it is enabled concurrently. There was a race in FORCE_ELISION macro which leads to either pthread_mutex_destroy returning EBUSY as the owner was recorded by pthread_mutex_lock - in "normal mutex" code path - but was not resetted in pthread_mutex_unlock - in "elision" code path. Or it leads to the assertion in nptl/pthread_mutex_lock.c: assert (mutex->__data.__owner == 0); Please ensure that the test is run with lock elision: export GLIBC_TUNABLES=glibc.elision.enable=1 */ xpthread_mutex_lock (&mutex); xpthread_mutex_unlock (&mutex); xpthread_barrier_wait (&barrier); } return NULL; }
static void * tf (void *arg) { xpthread_barrier_wait (&b); posix_spawn_file_actions_t a; if (posix_spawn_file_actions_init (&a) != 0) { puts ("error: spawn_file_actions_init failed"); exit (1); } if (posix_spawn_file_actions_adddup2 (&a, pipefd[1], STDOUT_FILENO) != 0) { puts ("error: spawn_file_actions_adddup2 failed"); exit (1); } if (posix_spawn_file_actions_addclose (&a, pipefd[0]) != 0) { puts ("error: spawn_file_actions_addclose"); exit (1); } char *argv[] = { (char *) _PATH_BSHELL, (char *) "-c", (char *) "echo $$", NULL }; if (posix_spawn (&pid, _PATH_BSHELL, &a, NULL, argv, NULL) != 0) { puts ("error: spawn failed"); exit (1); } return NULL; }
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 void * wait_first_thread (void * closure) { pthread_barrier_t *barrier = closure; xpthread_barrier_wait (barrier); void *ptr = xmalloc (malloc_size); unoptimized_free (ptr); return NULL; }
static int do_test (void) { xpthread_barrier_init (&barrier, NULL, thread_count + 1); pthread_t threads[thread_count]; for (size_t i = 0; i < array_length (threads); ++i) threads[i] = xpthread_create (NULL, allocation_thread_function, NULL); xpthread_barrier_wait (&barrier); puts ("info: After allocation:"); malloc_info (0, stdout); xpthread_barrier_wait (&barrier); for (size_t i = 0; i < array_length (threads); ++i) xpthread_join (threads[i]); puts ("\ninfo: After deallocation:"); malloc_info (0, stdout); return 0; }
static void * creator_thread (void *arg) { int ret; xpthread_barrier_wait (&barrier); while (true) { pthread_t thr; /* Thread creation will fail if the kernel does not free old threads quickly enough, so we do not report errors. */ ret = pthread_create (&thr, &detached, do_nothing, NULL); if (ret == 0 && __atomic_add_fetch (&threads_created, 1, __ATOMIC_SEQ_CST) >= threads_to_create) break; } return NULL; }
static int do_test (void) { /* The test basically pipe a 'echo $$' created by a thread with a cancellation pending. It then checks if the thread is not cancelled, the process is created and if the output is the expected one. */ if (pipe (pipefd) != 0) { puts ("error: pipe failed"); exit (1); } /* Not interested in knowing when the pipe is closed. */ if (sigignore (SIGPIPE) != 0) { puts ("error: sigignore failed"); exit (1); } /* To synchronize with the thread. */ if (pthread_barrier_init (&b, NULL, 2) != 0) { puts ("error: pthread_barrier_init failed"); exit (1); } pthread_t th = xpthread_create (NULL, &tf, NULL); if (pthread_cancel (th) != 0) { puts ("error: pthread_cancel failed"); return 1; } xpthread_barrier_wait (&b); if (xpthread_join (th) == PTHREAD_CANCELED) { puts ("error: thread cancelled"); exit (1); } close (pipefd[1]); /* The global 'pid' should be set by thread posix_spawn calling. Check below if it was executed correctly and with expected output. */ char buf[64]; ssize_t n; bool seen_pid = false; while (TEMP_FAILURE_RETRY ((n = read (pipefd[0], buf, sizeof (buf)))) > 0) { /* We only expect to read the PID. */ char *endp; long int rpid = strtol (buf, &endp, 10); if (*endp != '\n') { printf ("error: didn't parse whole line: \"%s\"\n", buf); exit (1); } if (endp == buf) { puts ("error: read empty line"); exit (1); } if (rpid != pid) { printf ("error: found \"%s\", expected PID %ld\n", buf, (long int) pid); exit (1); } if (seen_pid) { puts ("error: found more than one PID line"); exit (1); } seen_pid = true; } close (pipefd[0]); int status; int err = waitpid (pid, &status, 0); if (err != pid) { puts ("errnor: waitpid failed"); exit (1); } if (!seen_pid) { puts ("error: didn't get PID"); exit (1); } return 0; }