#include <pthread.h> #include <stdio.h> #include <stdlib.h> static pthread_barrier_t b; static pthread_cond_t c = PTHREAD_COND_INITIALIZER; static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; static void cl (void *arg) { pthread_mutex_unlock (&m); } static void * tf (void *arg) { if (pthread_mutex_lock (&m) != 0) { printf ("%s: mutex_lock failed\n", __func__); exit (1); } int e = pthread_barrier_wait (&b); if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) { printf ("%s: barrier_wait failed\n", __func__); exit (1); } pthread_cleanup_push (cl, NULL); /* We have to loop here because the cancellation might come after the cond_wait call left the cancelable area and is then waiting on the mutex. In this case the beginning of the second cond_wait call will cause the cancellation to happen. */ do if (pthread_cond_wait (&c, &m) != 0) { printf ("%s: cond_wait failed\n", __func__); exit (1); } while (arg == NULL); pthread_cleanup_pop (0); if (pthread_mutex_unlock (&m) != 0) { printf ("%s: mutex_unlock failed\n", __func__); exit (1); } return NULL; } static int do_test (void) { int status = 0; if (pthread_barrier_init (&b, NULL, 2) != 0) { puts ("barrier_init failed"); return 1; } pthread_t th; if (pthread_create (&th, NULL, tf, NULL) != 0) { puts ("1st create failed"); return 1; } int e = pthread_barrier_wait (&b); if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) { puts ("1st barrier_wait failed"); return 1; } if (pthread_mutex_lock (&m) != 0) { puts ("1st mutex_lock failed"); return 1; } if (pthread_cond_signal (&c) != 0) { puts ("1st cond_signal failed"); return 1; } if (pthread_cancel (th) != 0) { puts ("cancel failed"); return 1; } if (pthread_mutex_unlock (&m) != 0) { puts ("1st mutex_unlock failed"); return 1; } void *res; if (pthread_join (th, &res) != 0) { puts ("1st join failed"); return 1; } if (res != PTHREAD_CANCELED) { puts ("first thread not canceled"); status = 1; } printf ("cond = { %d, %x, %lld, %lld, %lld, %p, %u, %u }\n", c.__data.__lock, c.__data.__futex, c.__data.__total_seq, c.__data.__wakeup_seq, c.__data.__woken_seq, c.__data.__mutex, c.__data.__nwaiters, c.__data.__broadcast_seq); if (pthread_create (&th, NULL, tf, (void *) 1l) != 0) { puts ("2nd create failed"); return 1; } e = pthread_barrier_wait (&b); if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) { puts ("2nd barrier_wait failed"); return 1; } if (pthread_mutex_lock (&m) != 0) { puts ("2nd mutex_lock failed"); return 1; } if (pthread_cond_signal (&c) != 0) { puts ("2nd cond_signal failed"); return 1; } if (pthread_mutex_unlock (&m) != 0) { puts ("2nd mutex_unlock failed"); return 1; } if (pthread_join (th, &res) != 0) { puts ("2nd join failed"); return 1; } if (res != NULL) { puts ("2nd thread canceled"); status = 1; } printf ("cond = { %d, %x, %lld, %lld, %lld, %p, %u, %u }\n", c.__data.__lock, c.__data.__futex, c.__data.__total_seq, c.__data.__wakeup_seq, c.__data.__woken_seq, c.__data.__mutex, c.__data.__nwaiters, c.__data.__broadcast_seq); return status; } #define TEST_FUNCTION do_test () #include "../test-skeleton.c"