/*===========================================================================* * key_a * *===========================================================================*/ static void *key_a(void *arg) { int i; if (!first) mthread_yield(); /* Each new threads gets NULL-initialized values. */ for (i = 0; i < 5; i++) if (mthread_getspecific(key[i]) != NULL) err(17, 1); /* Make sure that the local values persist despite other threads' actions. */ for (i = 1; i < 5; i++) if (mthread_setspecific(key[i], (void *) i) != 0) err(17, 2); mthread_yield(); for (i = 1; i < 5; i++) if (mthread_getspecific(key[i]) != (void *) i) err(17, 3); mthread_yield(); /* The other thread has deleted this key by now. */ if (mthread_setspecific(key[3], NULL) != EINVAL) err(17, 4); /* If a key's value is set to NULL, its destructor must not be called. */ if (mthread_setspecific(key[4], NULL) != 0) err(17, 5); return(NULL); }
/*===========================================================================* * mutex_b * *===========================================================================*/ static void *mutex_b(void *arg) { mutex_t *mu = (mutex_t *) arg; /* At this point mutex_a thread should have acquired a lock on mu[0]. We * should not be able to unlock it on behalf of that thread. */ VERIFY_MUTEX(1, 0, 0, 4, 1); if (mthread_mutex_unlock(&mu[0]) != EPERM) err(4, 2); /* Probing mu[0] to lock it should tell us it's locked */ if (mthread_mutex_trylock(&mu[0]) != EBUSY) err(4, 4); if (mthread_mutex_lock(&mu[0]) != 0) err(4, 5); mutex_b_step = 1; VERIFY_MUTEX(2, 1, 0, 4, 6); if (mthread_mutex_lock(&mu[1]) != 0) err(4, 6); mutex_b_step = 2; VERIFY_MUTEX(3, 2, 2, 4, 7); mthread_yield(); VERIFY_MUTEX(3, 2, 2, 4, 8); if (mthread_mutex_unlock(&mu[0]) != 0) err(4, 7); mutex_b_step = 3; mthread_yield(); if (mthread_mutex_unlock(&mu[1]) != 0) err(4, 8); mutex_b_step = 4; return(NULL); }
/*===========================================================================* * rwlock_a * *===========================================================================*/ static void *rwlock_a(void *arg) { /* acquire read lock */ VERIFY_RWLOCK(0, 0, 24, 1); if (mthread_rwlock_rdlock(&rwlock) != 0) err(24, 2); rwlock_a_step = 1; mthread_yield(); /* release read lock */ VERIFY_RWLOCK(1, 1, 24, 3); if (mthread_rwlock_unlock(&rwlock) != 0) err(24, 4); rwlock_a_step = 2; /* get write lock */ if (mthread_rwlock_wrlock(&rwlock) != 0) err(24, 5); rwlock_a_step = 3; VERIFY_RWLOCK(3, 2, 24, 6); /* release write lock */ if (mthread_rwlock_unlock(&rwlock) != 0) err(24, 7); mthread_yield(); VERIFY_RWLOCK(3, 3, 24, 8); return(NULL); }
/*===========================================================================* * mutex_a * *===========================================================================*/ static void *mutex_a(void *arg) { mutex_t *mu = (mutex_t *) arg; VERIFY_MUTEX(0, 0, 0, 3, 1); if (mthread_mutex_lock(&mu[0]) != 0) err(3, 2); /* Trying to acquire lock again should fail with EDEADLK */ if (mthread_mutex_lock(&mu[0]) != EDEADLK) err(3, 2); #ifdef MTHREAD_STRICT /* Try to acquire lock on uninitialized mutex; should fail with EINVAL */ /* Note: this check only works when libmthread is compiled with * MTHREAD_STRICT turned on. In POSIX this situation is a MAY fail if... */ if (mthread_mutex_lock(&mu2) != EINVAL) { err(3, 4); mthread_mutex_unlock(&mu2); } if (mthread_mutex_trylock(&mu2) != EINVAL) { err(3, 6); mthread_mutex_unlock(&mu2); } #endif if (mthread_mutex_trylock(&mu[1]) != 0) err(3, 8); mutex_a_step = 1; mthread_yield(); VERIFY_MUTEX(1, 0, 0, 3, 9); if (mthread_mutex_trylock(&mu[2]) != EBUSY) err(3, 10); if (mthread_mutex_lock(&mu[2]) != 0) err(3, 12); /* Transfer control to main * loop. */ VERIFY_MUTEX(1, 0, 0, 3, 13); if (mthread_mutex_unlock(&mu[0]) != 0) err(3, 14); mutex_a_step = 2; mthread_yield(); VERIFY_MUTEX(2, 1, 0, 3, 15); if (mthread_mutex_unlock(&mu[1]) != 0) err(3, 16); mutex_a_step = 3; /* Try with faulty memory locations */ if (mthread_mutex_lock(NULL) == 0) err(3, 17); if (mthread_mutex_trylock(NULL) == 0) err(3, 18); if (mthread_mutex_unlock(NULL) == 0) err(3, 19); if (mthread_mutex_unlock(&mu[2]) != 0) err(3, 20); return(NULL); }
/*===========================================================================* * test_scheduling * *===========================================================================*/ static void test_scheduling(void) { unsigned int i; thread_t t[7]; #ifdef MDEBUG mthread_verify(); #endif th_a = th_b = th_c = th_d = th_e = 0; if (mthread_create(&t[0], NULL, thread_a, NULL) != 0) err(1, 1); if (mthread_create(&t[1], NULL, thread_a, NULL) != 0) err(1, 2); if (mthread_create(&t[2], NULL, thread_a, NULL) != 0) err(1, 3); if (mthread_create(&t[3], NULL, thread_d, NULL) != 0) err(1, 4); if (mthread_once(&once, thread_e) != 0) err(1, 5); mthread_yield(); if (mthread_create(&t[4], NULL, thread_c, NULL) != 0) err(1, 6); mthread_yield(); if (mthread_create(&t[5], NULL, thread_b, NULL) != 0) err(1, 7); if (mthread_create(&t[6], NULL, thread_a, NULL) != 0) err(1, 8); mthread_yield(); mthread_yield(); if (mthread_once(&once, thread_e) != 0) err(1, 9); if (mthread_once(&once, thread_e) != 0) err(1, 10); if (th_a != 4) err(1, 11); if (th_b != 1) err(1, 12); if (th_c != 1) err(1, 13); if (th_d != 1) err(1, 14); if (th_e != 1) err(1, 15); for (i = 0; i < (sizeof(t) / sizeof(thread_t)); i++) { if (mthread_join(t[i], NULL) != 0) err(1, 16); if (mthread_join(t[i], NULL) == 0) err(1, 17); /*Shouldn't work twice*/ } #ifdef MDEBUG mthread_verify(); #endif if (mthread_create(NULL, NULL, NULL, NULL) == 0) err(1, 18); mthread_yield(); #ifdef MDEBUG mthread_verify(); #endif if (mthread_create(&t[6], NULL, NULL, NULL) == 0) err(1, 19); mthread_yield(); #ifdef MDEBUG mthread_verify(); #endif if (mthread_join(0xc0ffee, NULL) == 0) err(1, 20); mthread_yield(); mthread_yield(); #ifdef MDEBUG mthread_verify(); #endif }
/*===========================================================================* * key_c * *===========================================================================*/ static void *key_c(void *arg) { /* The only thing that this thread should do, is set a value. */ if (mthread_setspecific(key[0], (void *) mthread_self()) != 0) err(19, 1); mthread_yield(); if (!mthread_equal((thread_t) mthread_getspecific(key[0]), mthread_self())) err(19, 2); return(NULL); }
static void * threadfunc(void * arg) { char *name = arg; printf("je suis le thread %p, lancé avec l'argument %s\n", mthread_self(), name); mthread_yield(); printf("je suis encore le thread %p, lancé avec l'argument %s\n", mthread_self(), name); mthread_exit(arg); return NULL; }
/*===========================================================================* * key_b * *===========================================================================*/ static void *key_b(void *arg) { int i; first = 1; mthread_yield(); /* Each new threads gets NULL-initialized values. */ for (i = 0; i < 5; i++) if (mthread_getspecific(key[i]) != NULL) err(18, 1); for (i = 0; i < 4; i++) if (mthread_setspecific(key[i], (void *) (i + 2)) != 0) err(18, 2); mthread_yield(); /* Deleting a key will not cause a call its destructor at any point. */ if (mthread_key_delete(key[3]) != 0) err(18, 3); mthread_exit(NULL); return(NULL); }
/*===========================================================================* * mutex_c * *===========================================================================*/ static void *mutex_c(void *arg) { mutex_t *mu = (mutex_t *) arg; VERIFY_MUTEX(1, 0, 0, 5, 1); if (mthread_mutex_lock(&mu[1]) != 0) err(5, 2); mutex_c_step = 1; VERIFY_MUTEX(3, 1, 1, 5, 3); mthread_yield(); VERIFY_MUTEX(3, 1, 1, 5, 4); if (mthread_mutex_unlock(&mu[1]) != 0) err(5, 5); mutex_c_step = 2; if (mthread_mutex_lock(&mu[0]) != 0) err(5, 6); mutex_c_step = 3; VERIFY_MUTEX(3, 3, 3, 5, 7); mthread_yield(); VERIFY_MUTEX(3, 4, 3, 5, 8); if (mthread_mutex_unlock(&mu[0]) != 0) err(5, 9); mutex_c_step = 4; return(NULL); }
/*===========================================================================* * cond_a * *===========================================================================*/ static void *cond_a(void *arg) { cond_t c; int did_count = 0; while(1) { if (mthread_mutex_lock(condition_mutex) != 0) err(6, 1); while (count >= THRESH1 && count <= THRESH2) { if (mthread_cond_wait(&condition, condition_mutex) != 0) err(6, 2); } if (mthread_mutex_unlock(condition_mutex) != 0) err(6, 3); mthread_yield(); if (mthread_mutex_lock(count_mutex) != 0) err(6, 4); count++; did_count++; if (mthread_mutex_unlock(count_mutex) != 0) err(6, 5); if (count >= ROUNDS) break; } if (!(did_count <= count - (THRESH2 - THRESH1 + 1))) err(6, 6); /* Try faulty addresses */ if (mthread_mutex_lock(condition_mutex) != 0) err(6, 7); #ifdef MTHREAD_STRICT /* Condition c is not initialized, so whatever we do with it should fail. */ if (mthread_cond_wait(&c, condition_mutex) == 0) err(6, 8); if (mthread_cond_wait(NULL, condition_mutex) == 0) err(6, 9); if (mthread_cond_signal(&c) == 0) err(6, 10); if (mthread_mutex_unlock(condition_mutex) != 0) err(6, 11); /* Try again with an unlocked mutex */ if (mthread_cond_wait(&c, condition_mutex) == 0) err(6, 12); if (mthread_cond_signal(&c) == 0) err(6, 13); #endif /* And again with an unlocked mutex, but initialized c */ if (mthread_cond_init(&c, NULL) != 0) err(6, 14); if (mthread_cond_wait(&c, condition_mutex) == 0) err(6, 15); if (mthread_cond_signal(&c) != 0) err(6, 16);/*c.f., 6.10 this should work!*/ if (mthread_cond_destroy(&c) != 0) err(6, 17); return(NULL); }
/*===========================================================================* * event_a * *===========================================================================*/ static void *event_a(void *arg) { VERIFY_EVENT(0, 0, 21, 1); /* Wait for main thread to signal us */ if (mthread_event_wait(&event) != 0) err(21, 2); /* Mark state transition and wakeup thread b */ event_a_step = 1; if (mthread_event_fire(&event) != 0) err(21, 3); mthread_yield(); VERIFY_EVENT(1, 1, 21, 4); /* Wait for main thread to signal again with fireall */ if (mthread_event_wait(&event) != 0) err(21, 5); /* Marks state transition and exit */ event_a_step = 2; return(NULL); }
/*===========================================================================* * test_mutex * *===========================================================================*/ static void test_mutex(void) { unsigned int i; thread_t t[3]; #ifdef MDEBUG mthread_verify(); #endif if (mthread_mutex_init(&mu[0], NULL) != 0) err(2, 1); if (mthread_mutex_init(&mu[1], NULL) != 0) err(2, 2); if (mthread_mutex_init(&mu[2], NULL) != 0) err(2, 3); if (mthread_create(&t[0], NULL, mutex_a, (void *) mu) != 0) err(2, 3); if (mthread_create(&t[1], NULL, mutex_b, (void *) mu) != 0) err(2, 4); if (mthread_create(&t[2], NULL, mutex_c, (void *) mu) != 0) err(2, 5); if (mthread_mutex_lock(&mu[2]) != 0) err(2, 6); mthread_yield_all(); /* Should result in a RUNNABLE mutex_a, and a blocked * on mutex mutex_b and mutex_c. */ VERIFY_MUTEX(1, 0, 0, 2, 7); /* err(2, 7) */ if (mthread_mutex_unlock(&mu[2]) != 0) err(2, 8); mthread_yield(); /* Should schedule mutex_a to release the lock on the * mu[0] mutex. Consequently allowing mutex_b and mutex_c * to acquire locks on the mutexes and exit. */ VERIFY_MUTEX(2, 0, 0, 2, 9); for (i = 0; i < (sizeof(t) / sizeof(thread_t)); i++) if (mthread_join(t[i], NULL) != 0) err(2, 10); if (mthread_mutex_destroy(&mu[0]) != 0) err(2, 11); if (mthread_mutex_destroy(&mu[1]) != 0) err(2, 12); if (mthread_mutex_destroy(&mu[2]) != 0) err(2, 13); #ifdef MDEBUG mthread_verify(); #endif }
/*===========================================================================* * rwlock_b * *===========================================================================*/ static void *rwlock_b(void *arg) { /* Step 1: acquire the read lock */ VERIFY_RWLOCK(1, 0, 25, 1); if (mthread_rwlock_rdlock(&rwlock) != 0) err(25, 2); rwlock_b_step = 1; mthread_yield(); /* We return back with first thread blocked on wrlock */ VERIFY_RWLOCK(2, 1, 25, 3); rwlock_b_step = 2; /* Release read lock and acquire write lock */ if (mthread_rwlock_unlock(&rwlock) != 0) err(25, 4); if (mthread_rwlock_wrlock(&rwlock) != 0) err(25, 5); rwlock_b_step = 3; VERIFY_RWLOCK(3, 3, 25, 6); if (mthread_rwlock_unlock(&rwlock) != 0) err(25, 6); return(NULL); }
/*===========================================================================* * cond_b * *===========================================================================*/ static void *cond_b(void *arg) { int did_count = 0; while(1) { if (mthread_mutex_lock(condition_mutex) != 0) err(7, 1); if (count < THRESH1 || count > THRESH2) if (mthread_cond_signal(&condition) != 0) err(7, 2); if (mthread_mutex_unlock(condition_mutex) != 0) err(7, 3); mthread_yield(); if (mthread_mutex_lock(count_mutex) != 0) err(7, 4); count++; did_count++; if (mthread_mutex_unlock(count_mutex) != 0) err(7, 5); if (count >= ROUNDS) break; } if (!(did_count >= count - (THRESH2 - THRESH1 + 1))) err(7, 6); return(NULL); }
/*===========================================================================* * test_condition * *===========================================================================*/ static void test_condition(void) { #define NTHREADS 10 int i; thread_t t[2], s[NTHREADS]; count_mutex = &mu[0]; condition_mutex = &mu[1]; /* Test simple condition variable behavior: Two threads increase a counter. * At some point one thread waits for a condition and the other thread * signals the condition. Consequently, one thread increased the counter a * few times less than other thread. Although the difference is 'random', * there is a guaranteed minimum difference that we can measure. */ #ifdef MDEBUG mthread_verify(); #endif if (mthread_mutex_init(count_mutex, NULL) != 0) err(8, 1); if (mthread_mutex_init(condition_mutex, NULL) != 0) err(8, 2); if (mthread_cond_init(&condition, NULL) != 0) err(8, 3); count = 0; if (mthread_create(&t[0], NULL, cond_a, NULL) != 0) err(8, 4); if (mthread_create(&t[1], NULL, cond_b, NULL) != 0) err(8, 5); for (i = 0; i < (sizeof(t) / sizeof(thread_t)); i++) if (mthread_join(t[i], NULL) != 0) err(8, 6); if (mthread_mutex_destroy(count_mutex) != 0) err(8, 7); if (mthread_mutex_destroy(condition_mutex) != 0) err(8, 8); if (mthread_cond_destroy(&condition) != 0) err(8, 9); #ifdef MTHREAD_STRICT /* Let's try to destroy it again. Should fails as it's uninitialized. */ /* Note: this only works when libmthread is compiled with MTHREAD_STRICT. In * POSIX this situation is a MAY fail if... */ if (mthread_cond_destroy(&condition) == 0) err(8, 10); #endif #ifdef MDEBUG mthread_verify(); #endif /* Test signal broadcasting: spawn N threads that will increase a counter * after a condition has been signaled. The counter must equal N. */ if (mthread_mutex_init(count_mutex, NULL) != 0) err(8, 11); if (mthread_mutex_init(condition_mutex, NULL) != 0) err(8, 12); if (mthread_cond_init(&condition, NULL) != 0) err(8, 13); condition_met = count = 0; for (i = 0; i < NTHREADS; i++) if (mthread_create(&s[i], NULL, cond_broadcast, NULL) != 0) err(8, 14); /* Allow other threads to block on the condition variable. If we don't yield, * the threads will only start running when we call mthread_join below. In * that case the while loop in cond_broadcast will never evaluate to true. */ mthread_yield(); if (mthread_mutex_lock(condition_mutex) != 0) err(8, 15); condition_met = 1; if (mthread_cond_broadcast(&condition) != 0) err(8, 16); if (mthread_mutex_unlock(condition_mutex) != 0) err(8, 17); for (i = 0; i < (sizeof(s) / sizeof(thread_t)); i++) if (mthread_join(s[i], NULL) != 0) err(8, 18); if (count != NTHREADS) err(8, 19); if (mthread_mutex_destroy(count_mutex) != 0) err(8, 20); if (mthread_mutex_destroy(condition_mutex) != 0) err(8, 21); if (mthread_cond_destroy(&condition) != 0) err(8, 22); #ifdef MTHREAD_STRICT /* Again, destroying the condition variable twice shouldn't work */ /* See previous note about MTHREAD_STRICT */ if (mthread_cond_destroy(&condition) == 0) err(8, 23); #endif #ifdef MDEBUG mthread_verify(); #endif }