From a8744086b476e4007c1d8fc0fae84ecfcade99ba Mon Sep 17 00:00:00 2001
From: rpj <rpj>
Date: Thu, 31 May 2001 02:05:25 +0000
Subject: New test.

---
 tests/mutex1e.c |  42 +++++++++++++
 tests/mutex1n.c |  42 +++++++++++++
 tests/mutex1r.c |  42 +++++++++++++
 tests/mutex5.c  |  31 ++++++++++
 tests/mutex6.c  |  51 ++++++++++++++++
 tests/mutex6e.c |  70 +++++++++++++++++++++
 tests/mutex6n.c |  61 +++++++++++++++++++
 tests/mutex6r.c |  68 +++++++++++++++++++++
 tests/rwlock7.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 592 insertions(+)
 create mode 100644 tests/mutex1e.c
 create mode 100644 tests/mutex1n.c
 create mode 100644 tests/mutex1r.c
 create mode 100644 tests/mutex5.c
 create mode 100644 tests/mutex6.c
 create mode 100644 tests/mutex6e.c
 create mode 100644 tests/mutex6n.c
 create mode 100644 tests/mutex6r.c
 create mode 100644 tests/rwlock7.c

(limited to 'tests')

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;
+}
-- 
cgit v1.2.3