/* Test of condition variables in multithreaded situations. Copyright (C) 2008-2023 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #if USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS /* Which tests to perform. Uncomment some of these, to verify that all tests crash if no locking is enabled. */ #define DO_TEST_COND 1 #define DO_TEST_TIMEDCOND 1 /* Whether to help the scheduler through explicit yield(). Uncomment this to see if the operating system has a fair scheduler. */ #define EXPLICIT_YIELD 1 /* Whether to print debugging messages. */ #define ENABLE_DEBUGGING 0 #include #include #include #include #include #include "glthread/cond.h" #include "glthread/lock.h" #include "glthread/thread.h" #include "glthread/yield.h" #if ENABLE_DEBUGGING # define dbgprintf printf #else # define dbgprintf if (0) printf #endif #if EXPLICIT_YIELD # define yield() gl_thread_yield () #else # define yield() #endif /* * Condition check */ static int cond_value = 0; gl_cond_define_initialized(static, condtest) gl_lock_define_initialized(static, lockcond) static void * cond_routine (void *arg) { gl_lock_lock (lockcond); while (!cond_value) { gl_cond_wait (condtest, lockcond); } gl_lock_unlock (lockcond); cond_value = 2; return NULL; } static void test_cond () { int remain = 2; gl_thread_t thread; cond_value = 0; thread = gl_thread_create (cond_routine, NULL); do { yield (); remain = sleep (remain); } while (remain); /* signal condition */ gl_lock_lock (lockcond); cond_value = 1; gl_cond_signal (condtest); gl_lock_unlock (lockcond); gl_thread_join (thread, NULL); if (cond_value != 2) abort (); } /* * Timed Condition check */ static int cond_timeout; static void get_ts (struct timespec *ts) { struct timeval now; gettimeofday (&now, NULL); ts->tv_sec = now.tv_sec + 1; ts->tv_nsec = now.tv_usec * 1000; } static void * timedcond_routine (void *arg) { int ret; struct timespec ts; gl_lock_lock (lockcond); while (!cond_value) { get_ts (&ts); ret = glthread_cond_timedwait (&condtest, &lockcond, &ts); if (ret == ETIMEDOUT) cond_timeout = 1; } gl_lock_unlock (lockcond); return NULL; } static void test_timedcond (void) { int remain = 2; gl_thread_t thread; cond_value = cond_timeout = 0; thread = gl_thread_create (timedcond_routine, NULL); do { yield (); remain = sleep (remain); } while (remain); /* signal condition */ gl_lock_lock (lockcond); cond_value = 1; gl_cond_signal (condtest); gl_lock_unlock (lockcond); gl_thread_join (thread, NULL); if (!cond_timeout) abort (); } int main () { #if DO_TEST_COND printf ("Starting test_cond ..."); fflush (stdout); test_cond (); printf (" OK\n"); fflush (stdout); #endif #if DO_TEST_TIMEDCOND printf ("Starting test_timedcond ..."); fflush (stdout); test_timedcond (); printf (" OK\n"); fflush (stdout); #endif return 0; } #else /* No multithreading available. */ #include int main () { fputs ("Skipping test: multithreading not enabled\n", stderr); return 77; } #endif