From 05e6d71f6f98ebb49f69cbf8d7d99fb640c3927c Mon Sep 17 00:00:00 2001 From: fpagliughi Date: Mon, 13 Jan 2025 09:43:49 -0500 Subject: [PATCH] Fixed condition variable timed wait. Updated thread test for current implementation. --- src/Thread.c | 25 +++++++++++++++---------- test/thread.c | 22 ++++++++++++---------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/Thread.c b/src/Thread.c index f4d43fb6f..f8b5279f7 100644 --- a/src/Thread.c +++ b/src/Thread.c @@ -51,6 +51,8 @@ #include "OsWrapper.h" +#define NSEC_PER_SEC 1000000000L + /** * Start a new thread * @param fn the function to run, must be of the correct signature @@ -443,12 +445,8 @@ int Thread_wait_cond(cond_type condvar, int timeout_ms) { int rc = 0; struct timespec cond_timeout; - struct timespec interval; FUNC_ENTRY; - interval.tv_sec = timeout_ms / 1000; - interval.tv_nsec = (timeout_ms % 1000) * 1000000L; - #if defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 /* for older versions of MacOS */ struct timeval cur_time; gettimeofday(&cur_time, NULL); @@ -458,13 +456,20 @@ int Thread_wait_cond(cond_type condvar, int timeout_ms) clock_gettime(CLOCK_REALTIME, &cond_timeout); #endif - cond_timeout.tv_sec += interval.tv_sec; - cond_timeout.tv_nsec += (timeout_ms % 1000) * 1000000L; + if (timeout_ms > 0) { + struct timespec interval; - if (cond_timeout.tv_nsec >= 1000000000L) - { - cond_timeout.tv_sec++; - cond_timeout.tv_nsec += (cond_timeout.tv_nsec - 1000000000L); + interval.tv_sec = timeout_ms / 1000; + interval.tv_nsec = (timeout_ms % 1000) * 1000000L; + + cond_timeout.tv_sec += interval.tv_sec; + cond_timeout.tv_nsec += interval.tv_nsec; + + while (cond_timeout.tv_nsec >= NSEC_PER_SEC) + { + cond_timeout.tv_sec++; + cond_timeout.tv_nsec -= NSEC_PER_SEC; + } } pthread_mutex_lock(&condvar->mutex); diff --git a/test/thread.c b/test/thread.c index 9e6de963a..5f91cff37 100644 --- a/test/thread.c +++ b/test/thread.c @@ -244,7 +244,7 @@ static thread_return_type WINAPI sem_secondary(void* n) duration = elapsed(start); assert("rc 0 from lock mutex", rc == 0, "rc was %d", rc); MyLog(LOGA_INFO, "Lock duration was %ld", duration); - assert("duration is 2s", duration >= 2000L, "duration was %ld", duration); + assert("duration is 2s", duration >= 1999L && duration < 2050L, "duration was %ld", duration); MyLog(LOGA_DEBUG, "Secondary thread ending"); return 0; @@ -288,10 +288,14 @@ int test_sem(struct Options options) assert("rc 0 from post_sem", rc == 0, "rc was %d\n", rc); } + rc = Thread_check_sem(sem); + assert("rc 1 from check_sem", rc == 1, "rc was %d", rc); + + // Binary sem, so additional checks should be zero for (i = 0; i < 10; ++i) { rc = Thread_check_sem(sem); - assert("rc 1 from check_sem", rc == 1, "rc was %d", rc); + assert("rc 0 from check_sem", rc == 0, "rc was %d", rc); } rc = Thread_check_sem(sem); assert("rc 0 from check_sem", rc == 0, "rc was %d", rc); @@ -300,7 +304,7 @@ int test_sem(struct Options options) start = start_clock(); rc = Thread_wait_sem(sem, 1500); duration = elapsed(start); - assert("rc ETIMEDOUT from lock mutex", rc == ETIMEDOUT, "rc was %d", rc); + assert("rc ETIMEDOUT from lock mutex", rc == ETIMEDOUT || rc == EAGAIN, "rc was %d", rc); MyLog(LOGA_INFO, "Lock duration was %ld", duration); assert("duration is 2s", duration >= 1500L, "duration was %ld", duration); @@ -310,7 +314,7 @@ int test_sem(struct Options options) mysleep(2); MyLog(LOGA_DEBUG, "post secondary"); rc = Thread_post_sem(sem); - assert("rc 1 from post_sem", rc == 1, "rc was %d", rc); + assert("rc 0 from post_sem", rc == 0, "rc was %d", rc); mysleep(1); @@ -333,10 +337,10 @@ thread_return_type cond_secondary(void* n) MyLog(LOGA_DEBUG, "This will time out"); start = start_clock(); - rc = Thread_wait_cond(cond, 1); + rc = Thread_wait_cond(cond, 1000); duration = elapsed(start); MyLog(LOGA_INFO, "Lock duration was %ld", duration); - assert("duration is about 1s", duration >= 1000L && duration <= 1050L, "duration was %ld", duration); + assert("duration is about 1s", duration >= 999L && duration <= 1050L, "duration was %ld", duration); assert("rc non 0 from wait_cond", rc == ETIMEDOUT, "rc was %d", rc); MyLog(LOGA_DEBUG, "This should hang around a few seconds"); @@ -370,11 +374,11 @@ int test_cond(struct Options options) MyLog(LOGA_DEBUG, "Check timeout"); start = start_clock(); - rc = Thread_wait_cond(cond, 2); + rc = Thread_wait_cond(cond, 2000); duration = elapsed(start); assert("rc ETIMEDOUT from lock mutex", rc == ETIMEDOUT, "rc was %d", rc); MyLog(LOGA_INFO, "Lock duration was %ld", duration); - assert("duration is 2s", duration >= 2000L, "duration was %ld", duration); + assert("duration is 2s", duration >= 1999L && duration < 2050L, "duration was %ld", duration); /* multiple posts */ for (i = 0; i < 10; ++i) @@ -389,8 +393,6 @@ int test_cond(struct Options options) rc = Thread_wait_cond(cond, 0); assert("rc non-zero from wait_cond", rc == ETIMEDOUT, "rc was %d", rc); } - rc = Thread_wait_cond(cond, 0); - assert("rc non-zero from wait_cond", rc == ETIMEDOUT, "rc was %d", rc); MyLog(LOGA_DEBUG, "Post secondary but it will time out"); rc = Thread_signal_cond(cond);