/* 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