Skip to content

Commit eea8384

Browse files
Martin Krasulaxiaoxiang781216
authored andcommitted
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 <mkrasula@elektroline.cz>
1 parent 3da1f4e commit eea8384

1 file changed

Lines changed: 123 additions & 0 deletions

File tree

testing/ostest/timedmutex.c

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@
4242
* Private Data
4343
****************************************************************************/
4444

45+
struct timedwait_arg_s
46+
{
47+
FAR pthread_mutex_t *mutex;
48+
unsigned int timeout_ms;
49+
int result;
50+
};
51+
4552
static pthread_mutex_t g_mutex;
4653
static bool g_running;
4754
static int g_result;
@@ -50,6 +57,36 @@ static int g_result;
5057
* Private Functions
5158
****************************************************************************/
5259

60+
static void *timedwait_thread(FAR void *parameter)
61+
{
62+
FAR struct timedwait_arg_s *arg = parameter;
63+
struct timespec abstime;
64+
65+
clock_gettime(CLOCK_REALTIME, &abstime);
66+
abstime.tv_sec += arg->timeout_ms / 1000;
67+
abstime.tv_nsec += (arg->timeout_ms % 1000) * 1000000;
68+
if (abstime.tv_nsec >= 1000000000)
69+
{
70+
abstime.tv_sec++;
71+
abstime.tv_nsec -= 1000000000;
72+
}
73+
74+
arg->result = pthread_mutex_timedlock(arg->mutex, &abstime);
75+
if (arg->result == 0)
76+
{
77+
pthread_mutex_unlock(arg->mutex);
78+
}
79+
80+
return NULL;
81+
}
82+
83+
static void create_timedwaiter(FAR pthread_t *thread,
84+
FAR struct timedwait_arg_s *arg)
85+
{
86+
int status = pthread_create(thread, NULL, timedwait_thread, arg);
87+
ASSERT(status == 0);
88+
}
89+
5390
static void *thread_func(FAR void *parameter)
5491
{
5592
struct timespec ts;
@@ -114,6 +151,90 @@ static void *thread_func(FAR void *parameter)
114151
return NULL;
115152
}
116153

154+
static void timedmutex_timeout_regression_test(void)
155+
{
156+
struct timedwait_arg_s short_wait;
157+
struct timedwait_arg_s long_wait;
158+
pthread_mutex_t mutex;
159+
pthread_t short_thread;
160+
pthread_t long_thread;
161+
int status;
162+
163+
/* A mutex must remain usable after its only waiter times out. This
164+
* verifies that the mutex blocking bit is cleared with the empty wait
165+
* queue.
166+
*/
167+
168+
status = pthread_mutex_init(&mutex, NULL);
169+
ASSERT(status == 0);
170+
status = pthread_mutex_lock(&mutex);
171+
ASSERT(status == 0);
172+
173+
short_wait.mutex = &mutex;
174+
short_wait.timeout_ms = 200;
175+
short_wait.result = -1;
176+
create_timedwaiter(&short_thread, &short_wait);
177+
178+
status = pthread_join(short_thread, NULL);
179+
ASSERT(status == 0);
180+
ASSERT(short_wait.result == ETIMEDOUT);
181+
182+
status = pthread_mutex_unlock(&mutex);
183+
ASSERT(status == 0);
184+
status = pthread_mutex_trylock(&mutex);
185+
ASSERT(status == 0);
186+
if (status == 0)
187+
{
188+
pthread_mutex_unlock(&mutex);
189+
}
190+
191+
status = pthread_mutex_destroy(&mutex);
192+
ASSERT(status == 0);
193+
194+
/* If one of two waiters times out, the blocking bit must remain set for
195+
* the other waiter. Unlocking the mutex must then transfer ownership to
196+
* that remaining waiter.
197+
*/
198+
199+
status = pthread_mutex_init(&mutex, NULL);
200+
ASSERT(status == 0);
201+
status = pthread_mutex_lock(&mutex);
202+
ASSERT(status == 0);
203+
204+
short_wait.mutex = &mutex;
205+
short_wait.timeout_ms = 200;
206+
short_wait.result = -1;
207+
long_wait.mutex = &mutex;
208+
long_wait.timeout_ms = 2000;
209+
long_wait.result = -1;
210+
211+
create_timedwaiter(&short_thread, &short_wait);
212+
create_timedwaiter(&long_thread, &long_wait);
213+
214+
status = pthread_join(short_thread, NULL);
215+
ASSERT(status == 0);
216+
ASSERT(short_wait.result == ETIMEDOUT);
217+
218+
status = pthread_mutex_unlock(&mutex);
219+
ASSERT(status == 0);
220+
221+
status = pthread_join(long_thread, NULL);
222+
ASSERT(status == 0);
223+
ASSERT(long_wait.result == 0);
224+
225+
status = pthread_mutex_trylock(&mutex);
226+
ASSERT(status == 0);
227+
if (status == 0)
228+
{
229+
pthread_mutex_unlock(&mutex);
230+
}
231+
232+
status = pthread_mutex_destroy(&mutex);
233+
ASSERT(status == 0);
234+
235+
printf("timedmutex regression test: PASSED\n");
236+
}
237+
117238
/****************************************************************************
118239
* Public Functions
119240
****************************************************************************/
@@ -222,4 +343,6 @@ void timedmutex_test(void)
222343
pthread_mutex_unlock(&g_mutex);
223344
errout_with_mutex:
224345
pthread_mutex_destroy(&g_mutex);
346+
347+
timedmutex_timeout_regression_test();
225348
}

0 commit comments

Comments
 (0)