This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push:
new eea8384ff testing/ostest: Add timed mutex timeout regression tests
eea8384ff is described below
commit eea8384ff577f8f323309ae568eaaf9ad29d9c8d
Author: Martin Krasula <[email protected]>
AuthorDate: Tue Aug 4 07:48:48 2026 +0200
testing/ostest: Add timed mutex timeout regression tests
Verify that a mutex remains reusable after its last waiter times out
and that ownership is transferred when another waiter remains queued.
Signed-off-by: Martin Krasula <[email protected]>
---
testing/ostest/timedmutex.c | 123 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 123 insertions(+)
diff --git a/testing/ostest/timedmutex.c b/testing/ostest/timedmutex.c
index 303dc260c..007ed56ba 100644
--- a/testing/ostest/timedmutex.c
+++ b/testing/ostest/timedmutex.c
@@ -42,6 +42,13 @@
* Private Data
****************************************************************************/
+struct timedwait_arg_s
+{
+ FAR pthread_mutex_t *mutex;
+ unsigned int timeout_ms;
+ int result;
+};
+
static pthread_mutex_t g_mutex;
static bool g_running;
static int g_result;
@@ -50,6 +57,36 @@ static int g_result;
* Private Functions
****************************************************************************/
+static void *timedwait_thread(FAR void *parameter)
+{
+ FAR struct timedwait_arg_s *arg = parameter;
+ struct timespec abstime;
+
+ clock_gettime(CLOCK_REALTIME, &abstime);
+ abstime.tv_sec += arg->timeout_ms / 1000;
+ abstime.tv_nsec += (arg->timeout_ms % 1000) * 1000000;
+ if (abstime.tv_nsec >= 1000000000)
+ {
+ abstime.tv_sec++;
+ abstime.tv_nsec -= 1000000000;
+ }
+
+ arg->result = pthread_mutex_timedlock(arg->mutex, &abstime);
+ if (arg->result == 0)
+ {
+ pthread_mutex_unlock(arg->mutex);
+ }
+
+ return NULL;
+}
+
+static void create_timedwaiter(FAR pthread_t *thread,
+ FAR struct timedwait_arg_s *arg)
+{
+ int status = pthread_create(thread, NULL, timedwait_thread, arg);
+ ASSERT(status == 0);
+}
+
static void *thread_func(FAR void *parameter)
{
struct timespec ts;
@@ -114,6 +151,90 @@ static void *thread_func(FAR void *parameter)
return NULL;
}
+static void timedmutex_timeout_regression_test(void)
+{
+ struct timedwait_arg_s short_wait;
+ struct timedwait_arg_s long_wait;
+ pthread_mutex_t mutex;
+ pthread_t short_thread;
+ pthread_t long_thread;
+ int status;
+
+ /* A mutex must remain usable after its only waiter times out. This
+ * verifies that the mutex blocking bit is cleared with the empty wait
+ * queue.
+ */
+
+ status = pthread_mutex_init(&mutex, NULL);
+ ASSERT(status == 0);
+ status = pthread_mutex_lock(&mutex);
+ ASSERT(status == 0);
+
+ short_wait.mutex = &mutex;
+ short_wait.timeout_ms = 200;
+ short_wait.result = -1;
+ create_timedwaiter(&short_thread, &short_wait);
+
+ status = pthread_join(short_thread, NULL);
+ ASSERT(status == 0);
+ ASSERT(short_wait.result == ETIMEDOUT);
+
+ status = pthread_mutex_unlock(&mutex);
+ ASSERT(status == 0);
+ status = pthread_mutex_trylock(&mutex);
+ ASSERT(status == 0);
+ if (status == 0)
+ {
+ pthread_mutex_unlock(&mutex);
+ }
+
+ status = pthread_mutex_destroy(&mutex);
+ ASSERT(status == 0);
+
+ /* If one of two waiters times out, the blocking bit must remain set for
+ * the other waiter. Unlocking the mutex must then transfer ownership to
+ * that remaining waiter.
+ */
+
+ status = pthread_mutex_init(&mutex, NULL);
+ ASSERT(status == 0);
+ status = pthread_mutex_lock(&mutex);
+ ASSERT(status == 0);
+
+ short_wait.mutex = &mutex;
+ short_wait.timeout_ms = 200;
+ short_wait.result = -1;
+ long_wait.mutex = &mutex;
+ long_wait.timeout_ms = 2000;
+ long_wait.result = -1;
+
+ create_timedwaiter(&short_thread, &short_wait);
+ create_timedwaiter(&long_thread, &long_wait);
+
+ status = pthread_join(short_thread, NULL);
+ ASSERT(status == 0);
+ ASSERT(short_wait.result == ETIMEDOUT);
+
+ status = pthread_mutex_unlock(&mutex);
+ ASSERT(status == 0);
+
+ status = pthread_join(long_thread, NULL);
+ ASSERT(status == 0);
+ ASSERT(long_wait.result == 0);
+
+ status = pthread_mutex_trylock(&mutex);
+ ASSERT(status == 0);
+ if (status == 0)
+ {
+ pthread_mutex_unlock(&mutex);
+ }
+
+ status = pthread_mutex_destroy(&mutex);
+ ASSERT(status == 0);
+
+ printf("timedmutex regression test: PASSED\n");
+}
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -222,4 +343,6 @@ errout_with_lock:
pthread_mutex_unlock(&g_mutex);
errout_with_mutex:
pthread_mutex_destroy(&g_mutex);
+
+ timedmutex_timeout_regression_test();
}