//CFLAGS=-pthread //LDFLAGS=-lpthread #include #include #include #include #include #include #define NUM_THREADS 3 #define THREAD_FUNC thr_func #define USE_BARRIER 1 #ifndef ROUNDS # define ROUNDS 100000000 #endif typedef struct thr_info { int nr; pthread_t thread; } __attribute__ ((aligned (256))) thr_info_t; #define THR_INIT() \ thr_info_t *thr = (thr_info_t *) arg; #define THR_PRINTF(fmt, ...) \ printf ("#%d: " fmt, thr->nr, __VA_ARGS__) #define THR_PUTS(msg) \ printf ("#%d: " msg "\n", thr->nr) #if USE_BARRIER != 0 static pthread_barrier_t thrs_barrier; #endif static pthread_mutex_t mtx; static const struct timespec before = { 0, 0 }; /* ################################################################### thread func ############################################################### */ static void * thr_func (void *arg) { THR_INIT (); int state = 0; int fct; #if 0 /* 3 threads, 1xfct=0=pthread_mutex_lock, 2xfct=1=pthread_mutex_timedlock: EINVAL. */ fct = (thr->nr + 1) % 2; #elif 0 /* 3 threads, 2xfct=0=pthread_mutex_lock, 1xfct=1=pthread_mutex_timedlock: no fails. */ fct = (thr->nr) % 2; #elif 1 /* >3 threads, fct=1=only pthread_mutex_timedlock: EINVAL. */ fct = 1; #endif int round = 0; THR_PRINTF ("started: fct=%d\n", fct); #if USE_BARRIER != 0 pthread_barrier_wait (&thrs_barrier); #endif while (1) { if (state == 0) { round ++; int e; switch (fct) { case 0: e = pthread_mutex_lock (&mtx); if (e != 0) { THR_PRINTF ("mutex_lock failed with %d (round=%d)\n", e, round); exit (1); } state = 1; break; case 1: e = pthread_mutex_timedlock (&mtx, &before); if (e != 0 && e != ETIMEDOUT) { THR_PRINTF ("mutex_timedlock failed with %d (round=%d)\n", e, round); exit (1); } break; default: e = pthread_mutex_trylock (&mtx); if (e != 0 && e != EBUSY) { THR_PRINTF ("mutex_trylock failed with %d (round=%d)\n", e, round); exit (1); } break; } if (e == EOWNERDEAD) pthread_mutex_consistent (&mtx); if (e == 0 || e == EOWNERDEAD) state = 1; } else { int e = pthread_mutex_unlock (&mtx); if (e != 0) { THR_PRINTF ("mutex_unlock of failed with %d (round=%d)\n", e, round); exit (1); } state = 0; } if (round >= ROUNDS) { THR_PRINTF ("REACHED round %d. => exit\n", ROUNDS); if (state != 0) { int e = pthread_mutex_unlock (&mtx); if (e != 0) { THR_PRINTF ("mutex_unlock@exit of failed with %d (round=%d)\n", e, round); exit (1); } } break; } } return NULL; } int main (void) { int i; printf ("main: start %d threads.\n", NUM_THREADS); #if USE_BARRIER != 0 pthread_barrier_init (&thrs_barrier, NULL, NUM_THREADS + 1); #endif pthread_mutexattr_t ma; if (pthread_mutexattr_init (&ma) != 0) { puts ("mutexattr_init failed"); return 0; } if (pthread_mutexattr_setrobust (&ma, PTHREAD_MUTEX_ROBUST_NP) != 0) { puts ("mutexattr_setrobust failed"); return 1; } if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0) { puts ("mutexattr_setpshared failed"); return 1; } if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT) != 0) { puts ("pthread_mutexattr_setprotocol failed"); return 1; } if (pthread_mutex_init (&mtx, &ma) != 0) { puts ("pthread_mutex_init failed"); return 1; } thr_info_t thrs[NUM_THREADS]; for (i = 0; i < NUM_THREADS; i++) { thrs[i].nr = i; assert (pthread_create (&(thrs[i].thread), NULL, THREAD_FUNC, &(thrs[i])) == 0);; } #if USE_BARRIER != 0 /* All threads start work after this barrier. */ pthread_barrier_wait (&thrs_barrier); #endif for (i = 0; i < NUM_THREADS; i++) { pthread_join (thrs[i].thread, NULL); } #if USE_BARRIER != 0 pthread_barrier_destroy (&thrs_barrier); #endif printf ("main: end.\n"); return EXIT_SUCCESS; }