diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/mutex1e.c | 42 | ||||
| -rw-r--r-- | tests/mutex1n.c | 42 | ||||
| -rw-r--r-- | tests/mutex1r.c | 42 | ||||
| -rw-r--r-- | tests/mutex5.c | 31 | ||||
| -rw-r--r-- | tests/mutex6.c | 51 | ||||
| -rw-r--r-- | tests/mutex6e.c | 70 | ||||
| -rw-r--r-- | tests/mutex6n.c | 61 | ||||
| -rw-r--r-- | tests/mutex6r.c | 68 | ||||
| -rw-r--r-- | tests/rwlock7.c | 185 | 
9 files changed, 592 insertions, 0 deletions
| diff --git a/tests/mutex1e.c b/tests/mutex1e.c new file mode 100644 index 0000000..2feb16c --- /dev/null +++ b/tests/mutex1e.c @@ -0,0 +1,42 @@ +/*  + * mutex1e.c + * + * As for mutex1.c but with type set to PTHREAD_MUTEX_ERRORCHECK. + * + * Create a simple mutex object, lock it, unlock it, then destroy it. + * This is the simplest test of the pthread mutex family that we can do. + * + * Depends on API functions: + *	pthread_mutexattr_settype() + * 	pthread_mutex_init() + *	pthread_mutex_destroy() + */ + +#include "test.h" + +pthread_mutex_t mutex = NULL; +pthread_mutexattr_t mxAttr; + +int +main() +{ +  assert(pthread_mutexattr_init(&mxAttr) == 0); + +  assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_ERRORCHECK) == 0); + +  assert(mutex == NULL); + +  assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + +  assert(mutex != NULL); + +  assert(pthread_mutex_lock(&mutex) == 0); + +  assert(pthread_mutex_unlock(&mutex) == 0); + +  assert(pthread_mutex_destroy(&mutex) == 0); + +  assert(mutex == NULL); + +  return 0; +} diff --git a/tests/mutex1n.c b/tests/mutex1n.c new file mode 100644 index 0000000..9af3d5f --- /dev/null +++ b/tests/mutex1n.c @@ -0,0 +1,42 @@ +/*  + * mutex1n.c + * + * As for mutex1.c but with type set to PTHREAD_MUTEX_NORMAL. + * + * Create a simple mutex object, lock it, unlock it, then destroy it. + * This is the simplest test of the pthread mutex family that we can do. + * + * Depends on API functions: + *	pthread_mutexattr_settype() + * 	pthread_mutex_init() + *	pthread_mutex_destroy() + */ + +#include "test.h" + +pthread_mutex_t mutex = NULL; +pthread_mutexattr_t mxAttr; + +int +main() +{ +  assert(pthread_mutexattr_init(&mxAttr) == 0); + +  assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_NORMAL) == 0); + +  assert(mutex == NULL); + +  assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + +  assert(mutex != NULL); + +  assert(pthread_mutex_lock(&mutex) == 0); + +  assert(pthread_mutex_unlock(&mutex) == 0); + +  assert(pthread_mutex_destroy(&mutex) == 0); + +  assert(mutex == NULL); + +  return 0; +} diff --git a/tests/mutex1r.c b/tests/mutex1r.c new file mode 100644 index 0000000..b5131bb --- /dev/null +++ b/tests/mutex1r.c @@ -0,0 +1,42 @@ +/*  + * mutex1r.c + * + * As for mutex1.c but with type set to PTHREAD_MUTEX_RECURSIVE. + * + * Create a simple mutex object, lock it, unlock it, then destroy it. + * This is the simplest test of the pthread mutex family that we can do. + * + * Depends on API functions: + *	pthread_mutexattr_settype() + * 	pthread_mutex_init() + *	pthread_mutex_destroy() + */ + +#include "test.h" + +pthread_mutex_t mutex = NULL; +pthread_mutexattr_t mxAttr; + +int +main() +{ +  assert(pthread_mutexattr_init(&mxAttr) == 0); + +  assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE) == 0); + +  assert(mutex == NULL); + +  assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + +  assert(mutex != NULL); + +  assert(pthread_mutex_lock(&mutex) == 0); + +  assert(pthread_mutex_unlock(&mutex) == 0); + +  assert(pthread_mutex_destroy(&mutex) == 0); + +  assert(mutex == NULL); + +  return 0; +} diff --git a/tests/mutex5.c b/tests/mutex5.c new file mode 100644 index 0000000..6a9a917 --- /dev/null +++ b/tests/mutex5.c @@ -0,0 +1,31 @@ +/*  + * mutex5.c + * + * Confirm the equality/inequality of the various mutex types, + * and the default not-set value. + */ + +#include "test.h" + +static pthread_mutexattr_t mxAttr; + +int +main() +{ +  int mxType = -1; + +  assert(PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL); +  assert(PTHREAD_MUTEX_DEFAULT != PTHREAD_MUTEX_ERRORCHECK); +  assert(PTHREAD_MUTEX_DEFAULT != PTHREAD_MUTEX_RECURSIVE); +  assert(PTHREAD_MUTEX_RECURSIVE != PTHREAD_MUTEX_ERRORCHECK); + +  assert(PTHREAD_MUTEX_NORMAL == PTHREAD_MUTEX_FAST_NP); +  assert(PTHREAD_MUTEX_RECURSIVE == PTHREAD_MUTEX_RECURSIVE_NP); +  assert(PTHREAD_MUTEX_ERRORCHECK == PTHREAD_MUTEX_ERRORCHECK_NP); + +  assert(pthread_mutexattr_init(&mxAttr) == 0); +  assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); +  assert(mxType == PTHREAD_MUTEX_NORMAL); + +  return 0; +} diff --git a/tests/mutex6.c b/tests/mutex6.c new file mode 100644 index 0000000..39b95e5 --- /dev/null +++ b/tests/mutex6.c @@ -0,0 +1,51 @@ +/*  + * mutex6.c + * + * Test the default (type not set) mutex type. + * Should be the same as PTHREAD_MUTEX_NORMAL. + * Thread locks mutex twice (recursive lock). + * Locking thread should deadlock on second attempt. + * + * Depends on API functions:  + *	pthread_mutex_lock() + *	pthread_mutex_trylock() + *	pthread_mutex_unlock() + */ + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; + +void * locker(void * arg) +{ +  assert(pthread_mutex_lock(&mutex) == 0); +  lockCount++; +  assert(pthread_mutex_lock(&mutex) != 0); +  lockCount++; +  Sleep(1000); +  assert(pthread_mutex_unlock(&mutex) == 0); +  assert(pthread_mutex_unlock(&mutex) == 0); + +  return 0; +} +  +int +main() +{ +  pthread_t t; + +  assert(pthread_mutex_init(&mutex, NULL) == 0); + +  assert(pthread_create(&t, NULL, locker, NULL) == 0); + +  Sleep(2000); + +  assert(lockCount == 1); + +  exit(0); + +  /* Never reached */ +  return 0; +} diff --git a/tests/mutex6e.c b/tests/mutex6e.c new file mode 100644 index 0000000..e22550f --- /dev/null +++ b/tests/mutex6e.c @@ -0,0 +1,70 @@ +/*  + * mutex6e.c + * + * Tests PTHREAD_MUTEX_ERRORCHECK mutex type. + * Thread locks mutex twice (recursive lock). + * This should fail with an EDEADLK error. + * The second unlock attempt should fail with an EPERM error. + * + * Depends on API functions:  + *      pthread_create() + *      pthread_join() + *      pthread_mutexattr_init() + *      pthread_mutexattr_destroy() + *      pthread_mutexattr_settype() + *      pthread_mutexattr_gettype() + *      pthread_mutex_init() + *      pthread_mutex_destroy() + *	pthread_mutex_lock() + *	pthread_mutex_unlock() + */ + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; +static pthread_mutexattr_t mxAttr; + +void * locker(void * arg) +{ +  assert(pthread_mutex_lock(&mutex) == 0); +  lockCount++; +  assert(pthread_mutex_lock(&mutex) == EDEADLK); +  lockCount++; +  assert(pthread_mutex_unlock(&mutex) == 0); +  assert(pthread_mutex_unlock(&mutex) == EPERM); + +  return (void *) 555; +} +  +int +main() +{ +  pthread_t t; +  int result = 0; +  int mxType = -1; + +  assert(pthread_mutexattr_init(&mxAttr) == 0); +  assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_ERRORCHECK) == 0); +  assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); +  assert(mxType == PTHREAD_MUTEX_ERRORCHECK); + +  assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + +  assert(pthread_create(&t, NULL, locker, NULL) == 0); + +  assert(pthread_join(t, (void **) &result) == 0); +  assert(result == 555); + +  assert(lockCount == 2); + +  assert(pthread_mutex_destroy(&mutex) == 0); +  assert(pthread_mutexattr_destroy(&mxAttr) == 0); + +  exit(0); + +  /* Never reached */ +  return 0; +} + diff --git a/tests/mutex6n.c b/tests/mutex6n.c new file mode 100644 index 0000000..19e917c --- /dev/null +++ b/tests/mutex6n.c @@ -0,0 +1,61 @@ +/*  + * mutex6n.c + * + * Tests PTHREAD_MUTEX_NORMAL mutex type. + * Thread locks mutex twice (recursive lock). + * The thread should deadlock. + * + * Depends on API functions:  + *      pthread_create() + *      pthread_mutexattr_init() + *      pthread_mutexattr_settype() + *      pthread_mutexattr_gettype() + *      pthread_mutex_init() + *	pthread_mutex_lock() + *	pthread_mutex_unlock() + */ + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; +static pthread_mutexattr_t mxAttr; + +void * locker(void * arg) +{ +  assert(pthread_mutex_lock(&mutex) == 0); +  lockCount++; +  assert(pthread_mutex_lock(&mutex) != 0); +  lockCount++; +  assert(pthread_mutex_unlock(&mutex) == 0); +  assert(pthread_mutex_unlock(&mutex) == 0); + +  return (void *) 555; +} +  +int +main() +{ +  pthread_t t; +  int mxType = -1; + +  assert(pthread_mutexattr_init(&mxAttr) == 0); +  assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_NORMAL) == 0); +  assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); +  assert(mxType == PTHREAD_MUTEX_NORMAL); + +  assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + +  assert(pthread_create(&t, NULL, locker, NULL) == 0); + +  Sleep(1000); + +  assert(lockCount == 1); + +  exit(0); + +  /* Never reached */ +  return 0; +} + diff --git a/tests/mutex6r.c b/tests/mutex6r.c new file mode 100644 index 0000000..586cc84 --- /dev/null +++ b/tests/mutex6r.c @@ -0,0 +1,68 @@ +/*  + * mutex6r.c + * + * Tests PTHREAD_MUTEX_RECURSIVE mutex type. + * Thread locks mutex twice (recursive lock). + * Both locks and unlocks should succeed. + * + * Depends on API functions:  + *      pthread_create() + *      pthread_join() + *      pthread_mutexattr_init() + *      pthread_mutexattr_destroy() + *      pthread_mutexattr_settype() + *      pthread_mutexattr_gettype() + *      pthread_mutex_init() + *      pthread_mutex_destroy() + *	pthread_mutex_lock() + *	pthread_mutex_unlock() + */ + +#include "test.h" + +static int lockCount = 0; + +static pthread_mutex_t mutex; +static pthread_mutexattr_t mxAttr; + +void * locker(void * arg) +{ +  assert(pthread_mutex_lock(&mutex) == 0); +  lockCount++; +  assert(pthread_mutex_lock(&mutex) == 0); +  lockCount++; +  assert(pthread_mutex_unlock(&mutex) == 0); +  assert(pthread_mutex_unlock(&mutex) == 0); + +  return (void *) 555; +} +  +int +main() +{ +  pthread_t t; +  int result = 0; +  int mxType = -1; + +  assert(pthread_mutexattr_init(&mxAttr) == 0); +  assert(pthread_mutexattr_settype(&mxAttr, PTHREAD_MUTEX_RECURSIVE) == 0); +  assert(pthread_mutexattr_gettype(&mxAttr, &mxType) == 0); +  assert(mxType == PTHREAD_MUTEX_RECURSIVE); + +  assert(pthread_mutex_init(&mutex, &mxAttr) == 0); + +  assert(pthread_create(&t, NULL, locker, NULL) == 0); + +  assert(pthread_join(t, (void **) &result) == 0); +  assert(result == 555); + +  assert(lockCount == 2); + +  assert(pthread_mutex_destroy(&mutex) == 0); +  assert(pthread_mutexattr_destroy(&mxAttr) == 0); + +  exit(0); + +  /* Never reached */ +  return 0; +} diff --git a/tests/rwlock7.c b/tests/rwlock7.c new file mode 100644 index 0000000..9c6a5f1 --- /dev/null +++ b/tests/rwlock7.c @@ -0,0 +1,185 @@ +/* + * rwlock7.c + * + * Hammer on a bunch of rwlocks to test robustness and fairness. + * Printed stats should be roughly even for each thread. + */ + +#include "test.h" +#include <sys/timeb.h> + +#ifdef __GNUC__ +#include <stdlib.h> +#endif + +#define THREADS         5 +#define DATASIZE        15 +#define ITERATIONS      1000000 + +/* + * Keep statistics for each thread. + */ +typedef struct thread_tag { +  int         thread_num; +  pthread_t   thread_id; +  int         updates; +  int         reads; +  int         interval; +} thread_t; + +/* + * Read-write lock and shared data + */ +typedef struct data_tag { +  pthread_rwlock_t    lock; +  int                 data; +  int                 updates; +} data_t; + +static thread_t threads[THREADS]; +static data_t data[DATASIZE]; + +/* + * Thread start routine that uses read-write locks + */ +void *thread_routine (void *arg) +{ +  thread_t *self = (thread_t*)arg; +  int repeats = 0; +  int iteration; +  int element = 0; + +  for (iteration = 0; iteration < ITERATIONS; iteration++) +    { +      if (iteration % (ITERATIONS / 10) == 0) +        { +          putchar('.'); +          fflush(stdout); +        } +      /* +       * Each "self->interval" iterations, perform an +       * update operation (write lock instead of read +       * lock). +       */ +      if ((iteration % self->interval) == 0) +        { +          assert(pthread_rwlock_wrlock (&data[element].lock) == 0); +          data[element].data = self->thread_num; +          data[element].updates++; +          self->updates++; +          assert(pthread_rwlock_unlock (&data[element].lock) == 0); +        } else { +          /* +           * Look at the current data element to see whether +           * the current thread last updated it. Count the +           * times, to report later. +           */ +          assert(pthread_rwlock_rdlock (&data[element].lock) == 0); + +          self->reads++; + +          if (data[element].data == self->thread_num) +            { +              repeats++; +            } + +          assert(pthread_rwlock_unlock (&data[element].lock) == 0); +        } + +      element++; + +      if (element >= DATASIZE) +        { +          element = 0; +        } +    } + +  if (repeats > 0) +    { +      printf ("\nThread %d found unchanged elements %d times", +              self->thread_num, repeats); +      fflush(stdout); +    } + +  return NULL; +} + +int +main (int argc, char *argv[]) +{ +  int count; +  int data_count; +  int thread_updates = 0; +  int data_updates = 0; +  int seed = 1; + +  struct _timeb currSysTime1; +  struct _timeb currSysTime2; + +  /* +   * Initialize the shared data. +   */ +  for (data_count = 0; data_count < DATASIZE; data_count++) +    { +      data[data_count].data = 0; +      data[data_count].updates = 0; + +      assert(pthread_rwlock_init (&data[data_count].lock, NULL) == 0); +    } + +  _ftime(&currSysTime1); + +  /* +   * Create THREADS threads to access shared data. +   */ +  for (count = 0; count < THREADS; count++) +    { +      threads[count].thread_num = count; +      threads[count].updates = 0; +      threads[count].reads = 0; +      threads[count].interval = rand_r (&seed) % 71; + +      assert(pthread_create (&threads[count].thread_id, +                             NULL, thread_routine, (void*)&threads[count]) == 0); +    } + +  /* +   * Wait for all threads to complete, and collect +   * statistics. +   */ +  for (count = 0; count < THREADS; count++) +    { +      assert(pthread_join (threads[count].thread_id, NULL) == 0); +      thread_updates += threads[count].updates; +      printf ("%02d: interval %d, updates %d, reads %d\n", +              count, threads[count].interval, +              threads[count].updates, threads[count].reads); +    } + +  putchar('\n'); +  fflush(stdout); + +  /* +   * Collect statistics for the data. +   */ +  for (data_count = 0; data_count < DATASIZE; data_count++) +    { +      data_updates += data[data_count].updates; +      printf ("data %02d: value %d, %d updates\n", +              data_count, data[data_count].data, data[data_count].updates); +      assert(pthread_rwlock_destroy (&data[data_count].lock) == 0); +    } + +  printf ("%d thread updates, %d data updates\n", +          thread_updates, data_updates); + +  _ftime(&currSysTime2); + +  printf( "\nstart: %ld/%d, stop: %ld/%d, duration:%ld\n", +          currSysTime1.time,currSysTime1.millitm, +          currSysTime2.time,currSysTime2.millitm, +          (currSysTime2.time*1000+currSysTime2.millitm) - +          (currSysTime1.time*1000+currSysTime1.millitm)); + +  return 0; +} | 
