diff --git a/components/pthread/pthread.c b/components/pthread/pthread.c index b7e57ee4d83..0319331c3d6 100644 --- a/components/pthread/pthread.c +++ b/components/pthread/pthread.c @@ -464,8 +464,14 @@ int pthread_join(pthread_t thread, void **retval) if (ret == 0) { if (wait) { - xTaskNotifyWait(0, 0, NULL, portMAX_DELAY); - _lock_acquire(&s_threads_lock); + for (;;) { + xTaskNotifyWait(0, 0, NULL, portMAX_DELAY); + _lock_acquire(&s_threads_lock); + if (pthread->state == PTHREAD_TASK_STATE_EXIT) { + break; + } + _lock_release(&s_threads_lock); + } child_task_retval = pthread->retval; pthread_delete(pthread); _lock_release(&s_threads_lock); @@ -536,12 +542,11 @@ void pthread_exit(void *value_ptr) } else { // Set return value pthread->retval = value_ptr; - // Remove from list, it indicates that task has exited + // Publish completion under the same lock checked by pthread_join. + pthread->state = PTHREAD_TASK_STATE_EXIT; if (pthread->join_task) { // notify join xTaskNotify(pthread->join_task, 0, eNoAction); - } else { - pthread->state = PTHREAD_TASK_STATE_EXIT; } } diff --git a/components/pthread/test_apps/pthread_unity_tests/main/test_pthread.c b/components/pthread/test_apps/pthread_unity_tests/main/test_pthread.c index 1f2232c3bad..88a9c2af29e 100644 --- a/components/pthread/test_apps/pthread_unity_tests/main/test_pthread.c +++ b/components/pthread/test_apps/pthread_unity_tests/main/test_pthread.c @@ -66,6 +66,27 @@ TEST_CASE("pthread create join", "[pthread]") } } +static void *join_notification_worker(void *arg) +{ + // Keep the child alive until the parent has entered pthread_join. + vTaskDelay(2); + return arg; +} + +TEST_CASE("pthread join ignores unrelated task notifications", "[pthread]") +{ + int token = 0; + pthread_t thread; + void *result = NULL; + + TEST_ASSERT_EQUAL_INT(0, pthread_create(&thread, NULL, join_notification_worker, &token)); + // A library may already have notified this task for an unrelated purpose. + xTaskNotifyGive(xTaskGetCurrentTaskHandle()); + TEST_ASSERT_EQUAL_INT(0, pthread_join(thread, &result)); + TEST_ASSERT_EQUAL_PTR(&token, result); + ulTaskNotifyTake(pdTRUE, 0); +} + static void *waiting_thread(void *arg) { TaskHandle_t *task_handle = (TaskHandle_t *)arg;