Index: contrib/netbsd-tests/lib/libpthread/t_cond.c =================================================================== --- contrib/netbsd-tests/lib/libpthread/t_cond.c +++ contrib/netbsd-tests/lib/libpthread/t_cond.c @@ -541,23 +541,45 @@ static void unlock(void *arg) { - pthread_mutex_unlock((pthread_mutex_t *)arg); + fprintf(stderr, "2: cancel callback\n"); + /* + * We may or may not hold the mutex here depending on when the + * cancellation request was handled. + */ + if (pthread_mutex_isowned_np((pthread_mutex_t *)arg)) { + pthread_mutex_unlock((pthread_mutex_t *)arg); + fprintf(stderr, "2: unlocked\n"); + } else { + fprintf(stderr, "2: mutex was not owned\n"); + } } static void * destroy_after_cancel_threadfunc(void *arg) { + // fprintf(stderr, "2: locking\n"); PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); - + ATF_REQUIRE(pthread_mutex_isowned_np(&mutex)); + // fprintf(stderr, "2: locked\n"); pthread_cleanup_push(unlock, &mutex); + // fprintf(stderr, "2: pushed\n"); + PTHREAD_REQUIRE(pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, + NULL)); + // fprintf(stderr, "2: enabled async cancel\n"); while (1) { share = 1; + // fprintf(stderr, "2: bcast\n"); + ATF_REQUIRE(pthread_mutex_isowned_np(&mutex)); PTHREAD_REQUIRE(pthread_cond_broadcast(&cond)); + // fprintf(stderr, "2: wait...\n"); PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex)); + // fprintf(stderr, "2: waited\n"); } - + // Should be unreachable. + // fprintf(stderr, "2: pop\n"); pthread_cleanup_pop(0); + // fprintf(stderr, "2: unlock\n"); PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); return NULL; @@ -572,23 +594,48 @@ ATF_TC_BODY(destroy_after_cancel, tc) { pthread_t thread; + void *retval; + unsigned num_cancel_requests = 0; PTHREAD_REQUIRE(pthread_mutex_init(&mutex, NULL)); PTHREAD_REQUIRE(pthread_cond_init(&cond, NULL)); PTHREAD_REQUIRE(pthread_mutex_lock(&mutex)); + ATF_REQUIRE(pthread_mutex_isowned_np(&mutex)); + // fprintf(stderr, "1: creating...\n"); PTHREAD_REQUIRE(pthread_create(&thread, NULL, destroy_after_cancel_threadfunc, NULL)); while (share == 0) { + // fprintf(stderr, "1: share=0 waiting...\n"); PTHREAD_REQUIRE(pthread_cond_wait(&cond, &mutex)); + // fprintf(stderr, "1: woken\n"); } + // fprintf(stderr, "1: after loop\n"); + ATF_REQUIRE(pthread_mutex_isowned_np(&mutex)); + // fprintf(stderr, "1: unlock\n"); PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); - PTHREAD_REQUIRE(pthread_cancel(thread)); - - PTHREAD_REQUIRE(pthread_join(thread, NULL)); + // fprintf(stderr, "1: unlocked\n"); + /* + * Note: The pthread_cancel request might not be received by the target + * thread depending on where it is in the pthread_cond_wait() + * implementation. To avoid this missed wakeup, keep cancelling the + * thread until the mutex is unlocked (i.e. the callback finished). + */ + // fprintf(stderr, "1: pthread_cancel loop\n"); + while (!pthread_mutex_trylock(&mutex)) { + num_cancel_requests++; + // fprintf(stderr, "1: pthread_cancel #%d\n", num_cancel_requests); + PTHREAD_REQUIRE(pthread_cancel(thread)); + pthread_yield(); + } + // fprintf(stderr, "1: mutex acquired, joining...\n"); + PTHREAD_REQUIRE(pthread_join(thread, &retval)); + PTHREAD_REQUIRE(pthread_mutex_unlock(&mutex)); + ATF_CHECK_EQ(retval, PTHREAD_CANCELED); + // fprintf(stderr, "1: destroy cond\n"); PTHREAD_REQUIRE(pthread_cond_destroy(&cond)); - + // fprintf(stderr, "1: destroy mutex\n"); PTHREAD_REQUIRE(pthread_mutex_destroy(&mutex)); }