/* Test of locking in multithreaded situations. Copyright (C) 2005 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_POSIX_THREADS || USE_SOLARIS_THREADS || USE_PTH_THREADS || USE_WIN32_THREADS /* Whether to enable locking. Uncomment this to get a test program without locking, to verify that it crashes. */ #define ENABLE_LOCKING 1 /* 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 #if !ENABLE_LOCKING # undef USE_POSIX_THREADS # undef USE_SOLARIS_THREADS # undef USE_PTH_THREADS # undef USE_WIN32_THREADS #endif #include "glthread/thread.h" #include "glthread/cond.h" #include "glthread/lock.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 */ #include static int cond_value = 0; static gl_cond_t condtest = gl_cond_initializer; static gl_lock_t lockcond = gl_lock_initializer; 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; } 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; } void test_timedcond() { int remain = 2; gl_thread_t thread; cond_value = cond_timeout = 0; thread = gl_thread_create(timedcond_routine, NULL); remain = 2; 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 TEST_PTH_THREADS if (!pth_init ()) abort (); #endif #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. */ int main () { return 77; } #endif