2024-06-28 Bruno Haible <bruno@clisp.org>
+ cond tests: Avoid theoretically possible failure.
+ * tests/test-cnd.c (cnd_wait_routine, cnd_timedwait_routine): Report to
+ the main thread if this thread comes too late.
+ (test_cnd_wait, test_cnd_timedwait): Return a 'skipped' value.
+ (main): Print SKIP instead of OK if the essence of the test was skipped.
+ * tests/test-cond.c (cond_routine, timedcond_routine): Report to the
+ main thread if this thread comes too late.
+ (test_cond, test_timedcond): Return a 'skipped' value.
+ (main): Print SKIP instead of OK if the essence of the test was skipped.
+ * tests/test-pthread-cond.c (pthread_cond_wait_routine,
+ pthread_cond_timedwait_routine): Report to the main thread if this
+ thread comes too late.
+ (test_pthread_cond_wait, test_pthread_cond_timedwait): Return a
+ 'skipped' value.
+ (main): Print SKIP instead of OK if the essence of the test was skipped.
+
cond tests: Improve multithread-safety.
* tests/test-cnd.c (cond_value, cond_timed_out): Mark as volatile.
* tests/test-cond.c (cond_value, cond_timed_out): Likewise.
cnd_wait_routine (void *arg)
{
ASSERT (mtx_lock (&lockcond) == thrd_success);
- while (!cond_value)
+ if (cond_value)
{
- ASSERT (cnd_wait (&condtest, &lockcond) == thrd_success);
+ /* The main thread already slept, and nevertheless this thread comes
+ too late. */
+ *(int *)arg = 1;
+ }
+ else
+ {
+ do
+ {
+ ASSERT (cnd_wait (&condtest, &lockcond) == thrd_success);
+ }
+ while (!cond_value);
}
ASSERT (mtx_unlock (&lockcond) == thrd_success);
return 0;
}
-static void
+static int
test_cnd_wait ()
{
+ int skipped = 0;
thrd_t thread;
int ret;
cond_value = 0;
/* Create a separate thread. */
- ASSERT (thrd_create (&thread, cnd_wait_routine, NULL) == thrd_success);
+ ASSERT (thrd_create (&thread, cnd_wait_routine, &skipped) == thrd_success);
/* Sleep for 2 seconds. */
{
if (cond_value != 2)
abort ();
+
+ return skipped;
}
struct timespec ts;
ASSERT (mtx_lock (&lockcond) == thrd_success);
- while (!cond_value)
+ if (cond_value)
+ {
+ /* The main thread already slept, and nevertheless this thread comes
+ too late. */
+ *(int *)arg = 1;
+ }
+ else
{
- get_ts (&ts);
- ret = cnd_timedwait (&condtest, &lockcond, &ts);
- if (ret == thrd_timedout)
- cond_timed_out = 1;
+ do
+ {
+ get_ts (&ts);
+ ret = cnd_timedwait (&condtest, &lockcond, &ts);
+ if (ret == thrd_timedout)
+ cond_timed_out = 1;
+ }
+ while (!cond_value);
}
ASSERT (mtx_unlock (&lockcond) == thrd_success);
return 0;
}
-static void
+static int
test_cnd_timedwait (void)
{
+ int skipped = 0;
thrd_t thread;
int ret;
cond_value = cond_timed_out = 0;
/* Create a separate thread. */
- ASSERT (thrd_create (&thread, cnd_timedwait_routine, NULL) == thrd_success);
+ ASSERT (thrd_create (&thread, cnd_timedwait_routine, &skipped)
+ == thrd_success);
/* Sleep for 2 seconds. */
{
if (!cond_timed_out)
abort ();
+
+ return skipped;
}
#if DO_TEST_COND
printf ("Starting test_cnd_wait ..."); fflush (stdout);
- test_cnd_wait ();
- printf (" OK\n"); fflush (stdout);
+ {
+ int skipped = test_cnd_wait ();
+ printf (skipped ? " SKIP\n" : " OK\n"); fflush (stdout);
+ }
#endif
#if DO_TEST_TIMEDCOND
printf ("Starting test_cnd_timedwait ..."); fflush (stdout);
- test_cnd_timedwait ();
- printf (" OK\n"); fflush (stdout);
+ {
+ int skipped = test_cnd_timedwait ();
+ printf (skipped ? " SKIP\n" : " OK\n"); fflush (stdout);
+ }
#endif
return test_exit_status;
cond_routine (void *arg)
{
gl_lock_lock (lockcond);
- while (!cond_value)
+ if (cond_value)
{
- gl_cond_wait (condtest, lockcond);
+ /* The main thread already slept, and nevertheless this thread comes
+ too late. */
+ *(int *)arg = 1;
+ }
+ else
+ {
+ do
+ {
+ gl_cond_wait (condtest, lockcond);
+ }
+ while (!cond_value);
}
gl_lock_unlock (lockcond);
return NULL;
}
-static void
+static int
test_cond ()
{
+ int skipped = 0;
gl_thread_t thread;
cond_value = 0;
/* Create a separate thread. */
- thread = gl_thread_create (cond_routine, NULL);
+ thread = gl_thread_create (cond_routine, &skipped);
/* Sleep for 2 seconds. */
{
if (cond_value != 2)
abort ();
+
+ return skipped;
}
struct timespec ts;
gl_lock_lock (lockcond);
- while (!cond_value)
+ if (cond_value)
+ {
+ /* The main thread already slept, and nevertheless this thread comes
+ too late. */
+ *(int *)arg = 1;
+ }
+ else
{
- get_ts (&ts);
- ret = glthread_cond_timedwait (&condtest, &lockcond, &ts);
- if (ret == ETIMEDOUT)
- cond_timed_out = 1;
+ do
+ {
+ get_ts (&ts);
+ ret = glthread_cond_timedwait (&condtest, &lockcond, &ts);
+ if (ret == ETIMEDOUT)
+ cond_timed_out = 1;
+ }
+ while (!cond_value);
}
gl_lock_unlock (lockcond);
return NULL;
}
-static void
+static int
test_timedcond (void)
{
+ int skipped = 0;
gl_thread_t thread;
cond_value = cond_timed_out = 0;
/* Create a separate thread. */
- thread = gl_thread_create (timedcond_routine, NULL);
+ thread = gl_thread_create (timedcond_routine, &skipped);
/* Sleep for 2 seconds. */
{
if (!cond_timed_out)
abort ();
+
+ return skipped;
}
{
#if DO_TEST_COND
printf ("Starting test_cond ..."); fflush (stdout);
- test_cond ();
- printf (" OK\n"); fflush (stdout);
+ {
+ int skipped = test_cond ();
+ printf (skipped ? " SKIP\n" : " OK\n"); fflush (stdout);
+ }
#endif
#if DO_TEST_TIMEDCOND
printf ("Starting test_timedcond ..."); fflush (stdout);
- test_timedcond ();
- printf (" OK\n"); fflush (stdout);
+ {
+ int skipped = test_timedcond ();
+ printf (skipped ? " SKIP\n" : " OK\n"); fflush (stdout);
+ }
#endif
return 0;
pthread_cond_wait_routine (void *arg)
{
ASSERT (pthread_mutex_lock (&lockcond) == 0);
- while (!cond_value)
+ if (cond_value)
{
- ASSERT (pthread_cond_wait (&condtest, &lockcond) == 0);
+ /* The main thread already slept, and nevertheless this thread comes
+ too late. */
+ *(int *)arg = 1;
+ }
+ else
+ {
+ do
+ {
+ ASSERT (pthread_cond_wait (&condtest, &lockcond) == 0);
+ }
+ while (!cond_value);
}
ASSERT (pthread_mutex_unlock (&lockcond) == 0);
return NULL;
}
-static void
+static int
test_pthread_cond_wait ()
{
+ int skipped = 0;
pthread_t thread;
int ret;
cond_value = 0;
/* Create a separate thread. */
- ASSERT (pthread_create (&thread, NULL, pthread_cond_wait_routine, NULL) == 0);
+ ASSERT (pthread_create (&thread, NULL, pthread_cond_wait_routine, &skipped)
+ == 0);
/* Sleep for 2 seconds. */
{
if (cond_value != 2)
abort ();
+
+ return skipped;
}
struct timespec ts;
ASSERT (pthread_mutex_lock (&lockcond) == 0);
- while (!cond_value)
+ if (cond_value)
+ {
+ /* The main thread already slept, and nevertheless this thread comes
+ too late. */
+ *(int *)arg = 1;
+ }
+ else
{
- get_ts (&ts);
- ret = pthread_cond_timedwait (&condtest, &lockcond, &ts);
- if (ret == ETIMEDOUT)
- cond_timed_out = 1;
+ do
+ {
+ get_ts (&ts);
+ ret = pthread_cond_timedwait (&condtest, &lockcond, &ts);
+ if (ret == ETIMEDOUT)
+ cond_timed_out = 1;
+ }
+ while (!cond_value);
}
ASSERT (pthread_mutex_unlock (&lockcond) == 0);
return NULL;
}
-static void
+static int
test_pthread_cond_timedwait (void)
{
+ int skipped = 0;
pthread_t thread;
int ret;
cond_value = cond_timed_out = 0;
/* Create a separate thread. */
- ASSERT (pthread_create (&thread, NULL, pthread_cond_timedwait_routine, NULL)
+ ASSERT (pthread_create (&thread, NULL,
+ pthread_cond_timedwait_routine, &skipped)
== 0);
/* Sleep for 2 seconds. */
if (!cond_timed_out)
abort ();
+
+ return skipped;
}
#if DO_TEST_COND
printf ("Starting test_pthread_cond_wait ..."); fflush (stdout);
- test_pthread_cond_wait ();
- printf (" OK\n"); fflush (stdout);
+ {
+ int skipped = test_pthread_cond_wait ();
+ printf (skipped ? " SKIP\n" : " OK\n"); fflush (stdout);
+ }
#endif
#if DO_TEST_TIMEDCOND
printf ("Starting test_pthread_cond_timedwait ..."); fflush (stdout);
- test_pthread_cond_timedwait ();
- printf (" OK\n"); fflush (stdout);
+ {
+ int skipped = test_pthread_cond_timedwait ();
+ printf (skipped ? " SKIP\n" : " OK\n"); fflush (stdout);
+ }
#endif
return test_exit_status;