]> sourceware.org Git - newlib-cygwin.git/commitdiff
* winsup.api/pthread/: New directory. Ports of pthread functionality
authorEgor Duda <deo@logos-m.ru>
Thu, 15 Nov 2001 11:19:48 +0000 (11:19 +0000)
committerEgor Duda <deo@logos-m.ru>
Thu, 15 Nov 2001 11:19:48 +0000 (11:19 +0000)
tests ported from pthreads-win32 project.
* winsup.api/pthread/test.h: Commmon declaraions for pthread tests.
* winsup.api/pthread/cleanup2.c: New test.
* winsup.api/pthread/cleanup3.c: Ditto.
* winsup.api/pthread/condvar1.c: Ditto.
* winsup.api/pthread/condvar2.c: Ditto.
* winsup.api/pthread/condvar2_1.c: Ditto.
* winsup.api/pthread/condvar3.c: Ditto.
* winsup.api/pthread/condvar3_1.c: Ditto.
* winsup.api/pthread/condvar3_2.c: Ditto.
* winsup.api/pthread/condvar3_3.c: Ditto.
* winsup.api/pthread/condvar4.c: Ditto.
* winsup.api/pthread/condvar5.c: Ditto.
* winsup.api/pthread/condvar6.c: Ditto.
* winsup.api/pthread/condvar8.c: Ditto.
* winsup.api/pthread/count1.c: Ditto.
* winsup.api/pthread/create1.c: Ditto.
* winsup.api/pthread/create2.c: Ditto.
* winsup.api/pthread/equal1.c: Ditto.
* winsup.api/pthread/exit1.c: Ditto.
* winsup.api/pthread/exit2.c: Ditto.
* winsup.api/pthread/exit3.c: Ditto.
* winsup.api/pthread/inherit1.c: Ditto.
* winsup.api/pthread/join0.c: Ditto.
* winsup.api/pthread/join1.c: Ditto.
* winsup.api/pthread/join2.c: Ditto.
* winsup.api/pthread/mutex1.c: Ditto.
* winsup.api/pthread/mutex1r.c: Ditto.
* winsup.api/pthread/mutex2.c: Ditto.
* winsup.api/pthread/mutex3.c: Ditto.
* winsup.api/pthread/mutex6r.c: Ditto.
* winsup.api/pthread/once1.c: Ditto.
* winsup.api/pthread/priority1.c: Ditto.
* winsup.api/pthread/priority2.c: Ditto.
* winsup.api/pthread/self1.c: Ditto.
* winsup.api/pthread/self2.c: Ditto.
* winsup.api/pthread/tsd1.c: Ditto.

37 files changed:
winsup/testsuite/ChangeLog
winsup/testsuite/winsup.api/pthread/cleanup2.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/cleanup3.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/condvar1.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/condvar2.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/condvar2_1.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/condvar3.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/condvar3_1.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/condvar3_2.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/condvar3_3.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/condvar4.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/condvar5.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/condvar6.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/condvar8.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/count1.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/create1.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/create2.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/equal1.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/exit1.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/exit2.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/exit3.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/inherit1.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/join0.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/join1.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/join2.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/mutex1.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/mutex1r.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/mutex2.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/mutex3.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/mutex6r.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/once1.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/priority1.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/priority2.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/self1.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/self2.c [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/test.h [new file with mode: 0644]
winsup/testsuite/winsup.api/pthread/tsd1.c [new file with mode: 0644]

index 849af81f381b66397ac3d291c1d885e9796d3420..67ed06a0121d7e2058f29fe1c4eb0930e061a446 100644 (file)
@@ -1,3 +1,44 @@
+2001-11-15  Egor Duda  <deo@logos-m.ru>
+
+       * winsup.api/pthread/: New directory. Ports of pthread functionality
+       tests ported from pthreads-win32 project.
+       * winsup.api/pthread/test.h: Commmon declaraions for pthread tests.
+       * winsup.api/pthread/cleanup2.c: New test.
+       * winsup.api/pthread/cleanup3.c: Ditto.
+       * winsup.api/pthread/condvar1.c: Ditto.
+       * winsup.api/pthread/condvar2.c: Ditto.
+       * winsup.api/pthread/condvar2_1.c: Ditto.
+       * winsup.api/pthread/condvar3.c: Ditto.
+       * winsup.api/pthread/condvar3_1.c: Ditto.
+       * winsup.api/pthread/condvar3_2.c: Ditto.
+       * winsup.api/pthread/condvar3_3.c: Ditto.
+       * winsup.api/pthread/condvar4.c: Ditto.
+       * winsup.api/pthread/condvar5.c: Ditto.
+       * winsup.api/pthread/condvar6.c: Ditto.
+       * winsup.api/pthread/condvar8.c: Ditto.
+       * winsup.api/pthread/count1.c: Ditto.
+       * winsup.api/pthread/create1.c: Ditto.
+       * winsup.api/pthread/create2.c: Ditto.
+       * winsup.api/pthread/equal1.c: Ditto.
+       * winsup.api/pthread/exit1.c: Ditto.
+       * winsup.api/pthread/exit2.c: Ditto.
+       * winsup.api/pthread/exit3.c: Ditto.
+       * winsup.api/pthread/inherit1.c: Ditto.
+       * winsup.api/pthread/join0.c: Ditto.
+       * winsup.api/pthread/join1.c: Ditto.
+       * winsup.api/pthread/join2.c: Ditto.
+       * winsup.api/pthread/mutex1.c: Ditto.
+       * winsup.api/pthread/mutex1r.c: Ditto.
+       * winsup.api/pthread/mutex2.c: Ditto.
+       * winsup.api/pthread/mutex3.c: Ditto.
+       * winsup.api/pthread/mutex6r.c: Ditto.
+       * winsup.api/pthread/once1.c: Ditto.
+       * winsup.api/pthread/priority1.c: Ditto.
+       * winsup.api/pthread/priority2.c: Ditto.
+       * winsup.api/pthread/self1.c: Ditto.
+       * winsup.api/pthread/self2.c: Ditto.
+       * winsup.api/pthread/tsd1.c: Ditto.
+
 2001-11-08  Corinna Vinschen <corinna@vinschen.de>
 
        * checksignal.c: New testcase.
diff --git a/winsup/testsuite/winsup.api/pthread/cleanup2.c b/winsup/testsuite/winsup.api/pthread/cleanup2.c
new file mode 100644 (file)
index 0000000..bcbaad3
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * File: cleanup2.c
+ *
+ * Test Synopsis: Test cleanup handler executes (when thread is not canceled).
+ *
+ * Test Method (Validation or Falsification):
+ * - 
+ *
+ * Requirements Tested:
+ * -
+ *
+ * Features Tested:
+ * - 
+ *
+ * Cases Tested:
+ * - 
+ *
+ * Description:
+ * - 
+ *
+ * Environment:
+ * - 
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock
+ *   pthread_testcancel, pthread_cancel, pthread_join
+ *
+ * Pass Criteria:
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+
+/*
+ * Create NUMTHREADS threads in addition to the Main thread.
+ */
+enum {
+  NUMTHREADS = 10
+};
+
+typedef struct bag_t_ bag_t;
+struct bag_t_ {
+  int threadnum;
+  int started;
+  /* Add more per-thread state variables here */
+  int count;
+};
+
+static bag_t threadbag[NUMTHREADS + 1];
+
+static int pop_count = 0;
+
+static void
+increment_pop_count(void * arg)
+{
+  int * c = (int *) arg;
+
+  (*c)++;
+}
+
+void *
+mythread(void * arg)
+{
+  int result = 0;
+  bag_t * bag = (bag_t *) arg;
+
+  assert(bag == &threadbag[bag->threadnum]);
+  assert(bag->started == 0);
+  bag->started = 1;
+
+  pthread_cleanup_push(increment_pop_count, (void *) &pop_count);
+
+  sched_yield();
+
+  pthread_cleanup_pop(1);
+
+  return (void *) result;
+}
+
+int
+main()
+{
+  int failed = 0;
+  int i;
+  pthread_t t[NUMTHREADS + 1];
+
+  assert((t[0] = pthread_self()) != NULL);
+
+  for (i = 1; i <= NUMTHREADS; i++)
+    {
+      threadbag[i].started = 0;
+      threadbag[i].threadnum = i;
+      assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0);
+    }
+
+  /*
+   * Code to control or munipulate child threads should probably go here.
+   */
+  Sleep(1000);
+
+  /*
+   * Standard check that all threads started.
+   */
+  for (i = 1; i <= NUMTHREADS; i++)
+    { 
+      if (!threadbag[i].started)
+       {
+         failed |= !threadbag[i].started;
+         fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started);
+       }
+    }
+
+  assert(!failed);
+
+  /*
+   * Check any results here. Set "failed" and only print output on failure.
+   */
+  failed = 0;
+  for (i = 1; i <= NUMTHREADS; i++)
+    {
+      int fail = 0;
+      int result = 0;
+
+      assert(pthread_join(t[i], (void **) &result) == 0);
+
+      fail = (result != 0);
+
+      if (fail)
+       {
+         fprintf(stderr, "Thread %d: started %d: result: %d\n",
+                 i,
+                 threadbag[i].started,
+                 result);
+       }
+      failed = (failed || fail);
+    }
+
+  assert(!failed);
+
+  assert(pop_count == NUMTHREADS);
+
+  /*
+   * Success.
+   */
+  return 0;
+}
+
diff --git a/winsup/testsuite/winsup.api/pthread/cleanup3.c b/winsup/testsuite/winsup.api/pthread/cleanup3.c
new file mode 100644 (file)
index 0000000..f8201fa
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * File: cleanup3.c
+ *
+ * Test Synopsis: Test cleanup handler does not execute (when thread is
+ * not canceled).
+ *
+ * Test Method (Validation or Falsification):
+ * - 
+ *
+ * Requirements Tested:
+ * -
+ *
+ * Features Tested:
+ * - 
+ *
+ * Cases Tested:
+ * - 
+ *
+ * Description:
+ * - 
+ *
+ * Environment:
+ * - 
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * - have working pthread_create, pthread_self, pthread_mutex_lock/unlock
+ *   pthread_testcancel, pthread_cancel, pthread_join
+ *
+ * Pass Criteria:
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+
+/*
+ * Create NUMTHREADS threads in addition to the Main thread.
+ */
+enum {
+  NUMTHREADS = 10
+};
+
+typedef struct bag_t_ bag_t;
+struct bag_t_ {
+  int threadnum;
+  int started;
+  /* Add more per-thread state variables here */
+  int count;
+};
+
+static bag_t threadbag[NUMTHREADS + 1];
+
+static int pop_count = 0;
+
+static void
+increment_pop_count(void * arg)
+{
+  int * c = (int *) arg;
+
+  (*c)++;
+}
+
+void *
+mythread(void * arg)
+{
+  int result = 0;
+  bag_t * bag = (bag_t *) arg;
+
+  assert(bag == &threadbag[bag->threadnum]);
+  assert(bag->started == 0);
+  bag->started = 1;
+
+  pthread_cleanup_push(increment_pop_count, (void *) &pop_count);
+
+  sched_yield();
+
+  pop_count--;
+
+  pthread_cleanup_pop(0);
+
+  return (void *) result;
+}
+
+int
+main()
+{
+  int failed = 0;
+  int i;
+  pthread_t t[NUMTHREADS + 1];
+
+  assert((t[0] = pthread_self()) != NULL);
+
+  for (i = 1; i <= NUMTHREADS; i++)
+    {
+      threadbag[i].started = 0;
+      threadbag[i].threadnum = i;
+      assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0);
+    }
+
+  /*
+   * Code to control or munipulate child threads should probably go here.
+   */
+  Sleep(1000);
+
+  /*
+   * Standard check that all threads started.
+   */
+  for (i = 1; i <= NUMTHREADS; i++)
+    { 
+      if (!threadbag[i].started)
+       {
+         failed |= !threadbag[i].started;
+         fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started);
+       }
+    }
+
+  assert(!failed);
+
+  /*
+   * Check any results here. Set "failed" and only print output on failure.
+   */
+  failed = 0;
+  for (i = 1; i <= NUMTHREADS; i++)
+    {
+      int fail = 0;
+      int result = 0;
+
+      assert(pthread_join(t[i], (void **) &result) == 0);
+
+      fail = (result != 0);
+
+      if (fail)
+       {
+         fprintf(stderr, "Thread %d: started %d: result: %d\n",
+                 i,
+                 threadbag[i].started,
+                 result);
+       }
+      failed = (failed || fail);
+    }
+
+  assert(!failed);
+
+  assert(pop_count == -(NUMTHREADS));
+
+  /*
+   * Success.
+   */
+  return 0;
+}
+
diff --git a/winsup/testsuite/winsup.api/pthread/condvar1.c b/winsup/testsuite/winsup.api/pthread/condvar1.c
new file mode 100644 (file)
index 0000000..daa0f42
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * File: condvar1.c
+ *
+ * Test Synopsis:
+ * - Test initialisation and destruction of a CV.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * - 
+ *
+ * Features Tested:
+ * - 
+ *
+ * Cases Tested:
+ * - 
+ *
+ * Description:
+ * - Creates and then imediately destroys a CV. Does not
+ *   test the CV.
+ *
+ * Environment:
+ * - 
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * - 
+ *
+ * Pass Criteria:
+ * - pthread_cond_init returns 0, and
+ * - pthread_cond_destroy returns 0.
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - pthread_cond_init returns non-zero, or
+ * - pthread_cond_destroy returns non-zero.
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+
+static pthread_cond_t cv = NULL;
+
+int
+main()
+{
+  assert(cv == NULL);
+
+  assert(pthread_cond_init(&cv, NULL) == 0);
+
+  assert(cv != NULL);
+
+  assert(pthread_cond_destroy(&cv) == 0);
+
+  assert(cv == NULL);
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/condvar2.c b/winsup/testsuite/winsup.api/pthread/condvar2.c
new file mode 100644 (file)
index 0000000..309f5df
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * File: condvar2.c
+ *
+ * Test Synopsis:
+ * - Test timed wait on a CV.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * - 
+ *
+ * Features Tested:
+ * - 
+ *
+ * Cases Tested:
+ * - 
+ *
+ * Description:
+ * - Because the CV is never signaled, we expect the wait to time out.
+ *
+ * Environment:
+ * -
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * - 
+ *
+ * Pass Criteria:
+ * - pthread_cond_timedwait returns ETIMEDOUT.
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - pthread_cond_timedwait does not return ETIMEDOUT.
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+#include <sys/timeb.h>
+
+pthread_cond_t cv;
+pthread_mutex_t mutex;
+
+int
+main()
+{
+  struct timespec abstime = { 0, 0 };
+  struct timeb currSysTime;
+  const DWORD NANOSEC_PER_MILLISEC = 1000000;
+  int result;
+
+  assert(pthread_cond_init(&cv, NULL) == 0);
+
+  assert(pthread_mutex_init(&mutex, NULL) == 0);
+
+  assert(pthread_mutex_lock(&mutex) == 0);
+
+  /* get current system time */
+  ftime(&currSysTime);
+
+  abstime.tv_sec = currSysTime.time;
+  abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+  abstime.tv_sec += 5;
+
+  assert(pthread_cond_timedwait(&cv, &mutex, &abstime) == ETIMEDOUT);
+  
+  assert(pthread_mutex_unlock(&mutex) == 0);
+
+  result = pthread_cond_destroy(&cv);
+  assert(result == 0);
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/condvar2_1.c b/winsup/testsuite/winsup.api/pthread/condvar2_1.c
new file mode 100644 (file)
index 0000000..da34162
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * File: condvar2_1.c
+ *
+ * Test Synopsis:
+ * - Test timeout of multiple waits on a CV with no signal/broadcast.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * - 
+ *
+ * Features Tested:
+ * - 
+ *
+ * Cases Tested:
+ * - 
+ *
+ * Description:
+ * - Because the CV is never signaled, we expect the waits to time out.
+ *
+ * Environment:
+ * -
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * - 
+ *
+ * Pass Criteria:
+ * - pthread_cond_timedwait returns ETIMEDOUT.
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - pthread_cond_timedwait does not return ETIMEDOUT.
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+#include <sys/timeb.h>
+
+static pthread_cond_t cv;
+static pthread_mutex_t mutex;
+static struct timespec abstime = { 0, 0 };
+
+enum {
+  NUMTHREADS = 60
+};
+
+void *
+mythread(void * arg)
+{
+  assert(pthread_mutex_lock(&mutex) == 0);
+
+  assert(pthread_cond_timedwait(&cv, &mutex, &abstime) == ETIMEDOUT);
+
+  assert(pthread_mutex_unlock(&mutex) == 0);
+
+  return arg;
+}
+
+int
+main()
+{
+  int i;
+  pthread_t t[NUMTHREADS + 1];
+  int result = 0;
+  struct timeb currSysTime;
+  const DWORD NANOSEC_PER_MILLISEC = 1000000;
+
+  assert(pthread_cond_init(&cv, NULL) == 0);
+
+  assert(pthread_mutex_init(&mutex, NULL) == 0);
+
+  /* get current system time */
+  ftime(&currSysTime);
+
+  abstime.tv_sec = currSysTime.time;
+  abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+  abstime.tv_sec += 5;
+
+  assert(pthread_mutex_lock(&mutex) == 0);
+
+  for (i = 1; i <= NUMTHREADS; i++)
+    {
+      assert(pthread_create(&t[i], NULL, mythread, (void *) i) == 0);
+    }
+
+  assert(pthread_mutex_unlock(&mutex) == 0);
+
+  for (i = 1; i <= NUMTHREADS; i++)
+    {
+      assert(pthread_join(t[i], (void **) &result) == 0);
+      assert(result == i);
+    }
+
+  result = pthread_cond_destroy(&cv);
+  assert(result == 0);
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/condvar3.c b/winsup/testsuite/winsup.api/pthread/condvar3.c
new file mode 100644 (file)
index 0000000..249e260
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * File: condvar3.c
+ *
+ * Test Synopsis:
+ * - Test basic function of a CV
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * - 
+ *
+ * Features Tested:
+ * - 
+ *
+ * Cases Tested:
+ * - 
+ *
+ * Description:
+ * - The primary thread takes the lock before creating any threads.
+ *   The secondary thread blocks on the lock allowing the primary
+ *   thread to enter the cv wait state which releases the lock.
+ *   The secondary thread then takes the lock and signals the waiting
+ *   primary thread.
+ *
+ * Environment:
+ * - 
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * - 
+ *
+ * Pass Criteria:
+ * - pthread_cond_timedwait returns 0.
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - pthread_cond_timedwait returns ETIMEDOUT.
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+#include <sys/timeb.h>
+
+static pthread_cond_t cv;
+static pthread_mutex_t mutex;
+static int shared = 0;
+
+enum {
+  NUMTHREADS = 2         /* Including the primary thread. */
+};
+
+void *
+mythread(void * arg)
+{
+  int result = 0;
+
+  assert(pthread_mutex_lock(&mutex) == 0);
+
+  shared++;
+
+  assert(pthread_mutex_unlock(&mutex) == 0);
+
+  if ((result = pthread_cond_signal(&cv)) != 0)
+    {
+      printf("Error = %s\n", error_string[result]);
+    }
+  assert(result == 0);
+
+  return (void *) 0;
+}
+
+int
+main()
+{
+  pthread_t t[NUMTHREADS];
+  struct timespec abstime = { 0, 0 };
+  struct timeb currSysTime;
+  const DWORD NANOSEC_PER_MILLISEC = 1000000;
+
+  assert((t[0] = pthread_self()) != NULL);
+
+  assert(pthread_cond_init(&cv, NULL) == 0);
+
+  assert(pthread_mutex_init(&mutex, NULL) == 0);
+
+  assert(pthread_mutex_lock(&mutex) == 0);
+
+  /* get current system time */
+  ftime(&currSysTime);
+
+  abstime.tv_sec = currSysTime.time;
+  abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+  assert(pthread_create(&t[1], NULL, mythread, (void *) 1) == 0);
+
+  abstime.tv_sec += 5;
+
+  while (! (shared > 0))
+    assert(pthread_cond_timedwait(&cv, &mutex, &abstime) == 0);
+
+  assert(shared > 0);
+
+  assert(pthread_mutex_unlock(&mutex) == 0);
+
+  assert(pthread_cond_destroy(&cv) == 0);
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/condvar3_1.c b/winsup/testsuite/winsup.api/pthread/condvar3_1.c
new file mode 100644 (file)
index 0000000..06f8bf7
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * File: condvar3_1.c
+ *
+ * Test Synopsis:
+ * - Test timeout of multiple waits on a CV with some signaled.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * - 
+ *
+ * Features Tested:
+ * - 
+ *
+ * Cases Tested:
+ * - 
+ *
+ * Description:
+ * - Because some CVs are never signaled, we expect their waits to time out.
+ *   Some are signaled, the rest time out. Pthread_cond_destroy() will fail
+ *   unless all are accounted for, either signaled or timedout.
+ *
+ * Environment:
+ * -
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * - 
+ *
+ * Pass Criteria:
+ * - pthread_cond_timedwait returns ETIMEDOUT.
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - pthread_cond_timedwait does not return ETIMEDOUT.
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+#include <sys/timeb.h>
+
+static pthread_cond_t cv;
+static pthread_cond_t cv1;
+static pthread_mutex_t mutex;
+static struct timespec abstime = { 0, 0 };
+static int timedout = 0;
+static int signaled = 0;
+static int awoken = 0;
+static int waiting = 0;
+
+enum {
+  NUMTHREADS = 60
+};
+
+void *
+mythread(void * arg)
+{
+  int result;
+
+  assert(pthread_mutex_lock(&mutex) == 0);
+
+  if ( ++waiting == NUMTHREADS)
+    assert(pthread_cond_signal(&cv1) == 0);
+
+  result = pthread_cond_timedwait(&cv, &mutex, &abstime);
+  if (result == ETIMEDOUT)
+    {
+      printf ("thread N %d has timed out\n", (int)arg);
+      timedout++;
+    }
+  else
+    {
+      printf ("thread N %d has waken up\n", (int)arg);
+      awoken++;
+    }
+
+  assert(pthread_mutex_unlock(&mutex) == 0);
+
+  return arg;
+}
+
+int
+main()
+{
+  int i;
+  pthread_t t[NUMTHREADS + 1];
+  int result = 0;
+  struct timeb currSysTime;
+  const DWORD NANOSEC_PER_MILLISEC = 1000000;
+
+  assert(pthread_cond_init(&cv, NULL) == 0);
+  assert(pthread_cond_init(&cv1, NULL) == 0);
+
+  assert(pthread_mutex_init(&mutex, NULL) == 0);
+
+  /* get current system time */
+  ftime(&currSysTime);
+
+  abstime.tv_sec = currSysTime.time;
+  abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+  abstime.tv_sec += 5;
+
+  assert(pthread_mutex_lock(&mutex) == 0);
+
+  for (i = 1; i <= NUMTHREADS; i++)
+    {
+      assert(pthread_create(&t[i], NULL, mythread, (void *) i) == 0);
+    }
+
+  do {
+    assert(pthread_cond_wait(&cv1,&mutex) == 0);
+  } while ( NUMTHREADS != waiting );
+
+  assert(pthread_mutex_unlock(&mutex) == 0);
+
+  for (i = NUMTHREADS/3; i <= 2*NUMTHREADS/3; i++)
+    {
+      printf ("sending signal N %d\n", signaled + 1);
+      assert(pthread_cond_signal(&cv) == 0);
+      signaled++;
+    }
+
+  for (i = 1; i <= NUMTHREADS; i++)
+    {
+      assert(pthread_join(t[i], (void **) &result) == 0);
+        assert(result == i);
+    }
+
+  fprintf(stderr, "awk = %d\n", awoken);
+  fprintf(stderr, "sig = %d\n", signaled);
+  fprintf(stderr, "tot = %d\n", timedout);
+
+  assert(signaled == awoken);
+  assert(timedout == NUMTHREADS - signaled);
+
+  result = pthread_cond_destroy(&cv);
+  assert(result == 0);
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/condvar3_2.c b/winsup/testsuite/winsup.api/pthread/condvar3_2.c
new file mode 100644 (file)
index 0000000..57e7eb4
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * File: condvar3_2.c
+ *
+ * Test Synopsis:
+ * - Test timeout of multiple waits on a CV with remainder broadcast awoken.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * - 
+ *
+ * Features Tested:
+ * - 
+ *
+ * Cases Tested:
+ * - 
+ *
+ * Description:
+ * - Because some CVs are never signaled, we expect their waits to time out.
+ *   Some time out, the rest are broadcast signaled. Pthread_cond_destroy() will fail
+ *   unless all are accounted for, either signaled or timedout.
+ *
+ * Environment:
+ * -
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * - 
+ *
+ * Pass Criteria:
+ * - pthread_cond_timedwait returns ETIMEDOUT.
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - pthread_cond_timedwait does not return ETIMEDOUT.
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+#include <sys/timeb.h>
+
+static pthread_cond_t cv;
+static pthread_mutex_t mutex;
+static struct timespec abstime = { 0, 0 };
+static struct timespec abstime2 = { 0, 0 };
+static int timedout = 0;
+static int awoken = 0;
+
+enum {
+  NUMTHREADS = 60
+};
+
+void *
+mythread(void * arg)
+{
+  int result;
+
+  assert(pthread_mutex_lock(&mutex) == 0);
+
+  abstime2.tv_sec = abstime.tv_sec;
+
+  if ((int) arg % 3 == 0)
+    {
+      abstime2.tv_sec += 2;
+    }
+
+  result = pthread_cond_timedwait(&cv, &mutex, &abstime2);
+  if (result == ETIMEDOUT)
+    {
+      timedout++;
+    }
+  else
+    {
+      awoken++;
+    }
+
+  assert(pthread_mutex_unlock(&mutex) == 0);
+
+  return arg;
+}
+
+int
+main()
+{
+  int i;
+  pthread_t t[NUMTHREADS + 1];
+  int result = 0;
+  struct timeb currSysTime;
+  const DWORD NANOSEC_PER_MILLISEC = 1000000;
+
+  assert(pthread_cond_init(&cv, NULL) == 0);
+
+  assert(pthread_mutex_init(&mutex, NULL) == 0);
+
+  /* get current system time */
+  ftime(&currSysTime);
+
+  abstime.tv_sec = abstime.tv_sec = currSysTime.time + 5;
+  abstime.tv_nsec = abstime2.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+  assert(pthread_mutex_lock(&mutex) == 0);
+
+  for (i = 1; i <= NUMTHREADS; i++)
+    {
+      assert(pthread_create(&t[i], NULL, mythread, (void *) i) == 0);
+    }
+
+  assert(pthread_mutex_unlock(&mutex) == 0);
+
+  for (i = 1; i <= NUMTHREADS; i++)
+    {
+      assert(pthread_join(t[i], (void **) &result) == 0);
+       assert(result == i);
+      /*
+       * Approximately 2/3rds of the threads are expected to time out.
+       * Signal the remainder after some threads have woken up and exited
+       * and while some are still waking up after timeout.
+       * Also tests that redundant broadcasts don't return errors.
+       */
+      if (awoken > NUMTHREADS/3)
+        {
+          assert(pthread_cond_broadcast(&cv) == 0);
+        }
+    }
+
+  assert(awoken == NUMTHREADS - timedout);
+
+  result = pthread_cond_destroy(&cv);
+  assert(result == 0);
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/condvar3_3.c b/winsup/testsuite/winsup.api/pthread/condvar3_3.c
new file mode 100644 (file)
index 0000000..f6bcca9
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * File: condvar3_3.c
+ *
+ * Test Synopsis:
+ * - Test timeouts and lost signals on a CV.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * - 
+ *
+ * Features Tested:
+ * - 
+ *
+ * Cases Tested:
+ * - 
+ *
+ * Description:
+ * -
+ *
+ * Environment:
+ * -
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * - 
+ *
+ * Pass Criteria:
+ * - pthread_cond_timedwait returns ETIMEDOUT.
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - pthread_cond_timedwait does not return ETIMEDOUT.
+ * - Process returns non-zero exit status.
+ */
+
+/* Timur Aydin (taydin@snet.net) */
+
+#include "test.h"
+
+#include <sys/timeb.h>
+
+pthread_cond_t cnd;
+pthread_mutex_t mtx;
+
+int main()
+{
+   int rc;
+
+   struct timespec abstime = { 0, 0 };
+   struct timeb currSysTime;
+   const DWORD NANOSEC_PER_MILLISEC = 1000000;
+
+   assert(pthread_cond_init(&cnd, 0) == 0);
+   assert(pthread_mutex_init(&mtx, 0) == 0);
+
+   /* get current system time */
+   ftime(&currSysTime);
+
+   abstime.tv_sec = currSysTime.time;
+   abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+   abstime.tv_sec += 1;
+
+   /* Here pthread_cond_timedwait should time out after one second. */
+
+   assert(pthread_mutex_lock(&mtx) == 0);
+
+   assert((rc = pthread_cond_timedwait(&cnd, &mtx, &abstime)) == ETIMEDOUT);
+
+   assert(pthread_mutex_unlock(&mtx) == 0);
+
+   /* Here, the condition variable is signaled, but there are no
+      threads waiting on it. The signal should be lost and
+      the next pthread_cond_timedwait should time out too. */
+
+   assert(pthread_mutex_lock(&mtx) == 0);
+
+   assert((rc = pthread_cond_signal(&cnd)) == 0);
+
+   assert(pthread_mutex_unlock(&mtx) == 0);
+
+   assert(pthread_mutex_lock(&mtx) == 0);
+
+   abstime.tv_sec = currSysTime.time;
+   abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+   abstime.tv_sec += 1;
+
+   assert((rc = pthread_cond_timedwait(&cnd, &mtx, &abstime)) == ETIMEDOUT);
+
+   assert(pthread_mutex_unlock(&mtx) == 0);
+
+   return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/condvar4.c b/winsup/testsuite/winsup.api/pthread/condvar4.c
new file mode 100644 (file)
index 0000000..7a2007a
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * File: condvar4.c
+ *
+ * Test Synopsis:
+ * - Test PTHREAD_COND_INITIALIZER.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * - 
+ *
+ * Features Tested:
+ * - 
+ *
+ * Cases Tested:
+ * - 
+ *
+ * Description:
+ * - Test basic CV function but starting with a static initialised
+ *   CV.
+ *
+ * Environment:
+ * - 
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * - 
+ *
+ * Pass Criteria:
+ * - pthread_cond_timedwait returns 0.
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - pthread_cond_timedwait returns ETIMEDOUT.
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+#include <sys/timeb.h>
+
+typedef struct cvthing_t_ cvthing_t;
+
+struct cvthing_t_ {
+  pthread_cond_t notbusy;
+  pthread_mutex_t lock;
+  int shared;
+};
+
+static cvthing_t cvthing = {
+  PTHREAD_COND_INITIALIZER,
+  PTHREAD_MUTEX_INITIALIZER,
+  0
+};
+
+enum {
+  NUMTHREADS = 2
+};
+
+void *
+mythread(void * arg)
+{
+  assert(pthread_mutex_lock(&cvthing.lock) == 0);
+
+  cvthing.shared++;
+
+  assert(pthread_mutex_unlock(&cvthing.lock) == 0);
+
+  assert(pthread_cond_signal(&cvthing.notbusy) == 0);
+
+  return (void *) 0;
+}
+
+int
+main()
+{
+  pthread_t t[NUMTHREADS];
+  struct timespec abstime = { 0, 0 };
+  struct timeb currSysTime;
+  const DWORD NANOSEC_PER_MILLISEC = 1000000;
+
+  cvthing.shared = 0;
+
+  assert((t[0] = pthread_self()) != NULL);
+
+  assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER);
+
+  assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER);
+
+  assert(pthread_mutex_lock(&cvthing.lock) == 0);
+
+  assert(cvthing.lock != PTHREAD_MUTEX_INITIALIZER);
+
+  /* get current system time */
+  ftime(&currSysTime);
+
+  abstime.tv_sec = currSysTime.time;
+  abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+  abstime.tv_sec += 5;
+
+  assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == ETIMEDOUT);
+  
+  assert(cvthing.notbusy != PTHREAD_COND_INITIALIZER);
+
+  assert(pthread_create(&t[1], NULL, mythread, (void *) 1) == 0);
+
+  ftime(&currSysTime);
+
+  abstime.tv_sec = currSysTime.time;
+  abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+  abstime.tv_sec += 5;
+
+  while (! (cvthing.shared > 0))
+    assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0);
+
+  assert(cvthing.shared > 0);
+
+  assert(pthread_mutex_unlock(&cvthing.lock) == 0);
+
+  assert(pthread_mutex_destroy(&cvthing.lock) == 0);
+
+  assert(cvthing.lock == NULL);
+
+  assert(pthread_cond_destroy(&cvthing.notbusy) == 0);
+
+  assert(cvthing.notbusy == NULL);
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/condvar5.c b/winsup/testsuite/winsup.api/pthread/condvar5.c
new file mode 100644 (file)
index 0000000..b493ab1
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * File: condvar5.c
+ *
+ * Test Synopsis:
+ * - Test pthread_cond_broadcast.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * - 
+ *
+ * Features Tested:
+ * - 
+ *
+ * Cases Tested:
+ * - 
+ *
+ * Description:
+ * - Test broadcast with one waiting CV.
+ *
+ * Environment:
+ * - 
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * - 
+ *
+ * Pass Criteria:
+ * - pthread_cond_timedwait returns 0.
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - pthread_cond_timedwait returns ETIMEDOUT.
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+#include <sys/timeb.h>
+
+typedef struct cvthing_t_ cvthing_t;
+
+struct cvthing_t_ {
+  pthread_cond_t notbusy;
+  pthread_mutex_t lock;
+  int shared;
+};
+
+static cvthing_t cvthing = {
+  PTHREAD_COND_INITIALIZER,
+  PTHREAD_MUTEX_INITIALIZER,
+  0
+};
+
+enum {
+  NUMTHREADS = 2
+};
+
+void *
+mythread(void * arg)
+{
+  assert(pthread_mutex_lock(&cvthing.lock) == 0);
+
+  cvthing.shared++;
+
+  assert(pthread_mutex_unlock(&cvthing.lock) == 0);
+
+  assert(pthread_cond_broadcast(&cvthing.notbusy) == 0);
+
+  return (void *) 0;
+}
+
+int
+main()
+{
+  pthread_t t[NUMTHREADS];
+  struct timespec abstime = { 0, 0 };
+  struct timeb currSysTime;
+  const DWORD NANOSEC_PER_MILLISEC = 1000000;
+
+  cvthing.shared = 0;
+
+  assert((t[0] = pthread_self()) != NULL);
+
+  assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER);
+
+  assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER);
+
+  assert(pthread_mutex_lock(&cvthing.lock) == 0);
+
+  assert(cvthing.lock != PTHREAD_MUTEX_INITIALIZER);
+
+  /* get current system time */
+  ftime(&currSysTime);
+
+  abstime.tv_sec = currSysTime.time;
+  abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+  abstime.tv_sec += 5;
+
+  assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == ETIMEDOUT);
+  
+  assert(cvthing.notbusy != PTHREAD_COND_INITIALIZER);
+
+  assert(pthread_create(&t[1], NULL, mythread, (void *) 1) == 0);
+
+  ftime(&currSysTime);
+
+  abstime.tv_sec = currSysTime.time;
+  abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+  abstime.tv_sec += 5;
+
+  while (! (cvthing.shared > 0))
+    assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0);
+
+  assert(cvthing.shared > 0);
+
+  assert(pthread_mutex_unlock(&cvthing.lock) == 0);
+
+  assert(pthread_mutex_destroy(&cvthing.lock) == 0);
+
+  assert(cvthing.lock == NULL);
+
+  assert(pthread_cond_destroy(&cvthing.notbusy) == 0);
+
+  assert(cvthing.notbusy == NULL);
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/condvar6.c b/winsup/testsuite/winsup.api/pthread/condvar6.c
new file mode 100644 (file)
index 0000000..f011bea
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * File: 
+ *
+ * Test Synopsis:
+ * - Test pthread_cond_broadcast.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * - 
+ *
+ * Features Tested:
+ * - 
+ *
+ * Cases Tested:
+ * - 
+ *
+ * Description:
+ * - Test broadcast with NUMTHREADS (=5) waiting CVs.
+ *
+ * Environment:
+ * - 
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * - 
+ *
+ * Pass Criteria:
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+#include <sys/timeb.h>
+
+/*
+ * Create NUMTHREADS threads in addition to the Main thread.
+ */
+enum {
+  NUMTHREADS = 5
+};
+
+typedef struct bag_t_ bag_t;
+struct bag_t_ {
+  int threadnum;
+  int started;
+  /* Add more per-thread state variables here */
+};
+
+static bag_t threadbag[NUMTHREADS + 1];
+
+typedef struct cvthing_t_ cvthing_t;
+
+struct cvthing_t_ {
+  pthread_cond_t notbusy;
+  pthread_mutex_t lock;
+  int shared;
+};
+
+static cvthing_t cvthing = {
+  PTHREAD_COND_INITIALIZER,
+  PTHREAD_MUTEX_INITIALIZER,
+  0
+};
+
+static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER;
+
+static struct timespec abstime = { 0, 0 };
+
+static int awoken;
+
+void *
+mythread(void * arg)
+{
+  bag_t * bag = (bag_t *) arg;
+
+  assert(bag == &threadbag[bag->threadnum]);
+  assert(bag->started == 0);
+  bag->started = 1;
+
+  /* Wait for the start gun */
+  assert(pthread_mutex_lock(&start_flag) == 0);
+  assert(pthread_mutex_unlock(&start_flag) == 0);
+
+  assert(pthread_mutex_lock(&cvthing.lock) == 0);
+
+  while (! (cvthing.shared > 0))
+    assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0);
+
+  assert(cvthing.shared > 0);
+
+  awoken++;
+
+  assert(pthread_mutex_unlock(&cvthing.lock) == 0);
+
+  return (void *) 0;
+}
+
+int
+main()
+{
+  int failed = 0;
+  int i;
+  pthread_t t[NUMTHREADS + 1];
+
+  struct timeb currSysTime;
+  const DWORD NANOSEC_PER_MILLISEC = 1000000;
+
+  cvthing.shared = 0;
+
+  assert((t[0] = pthread_self()) != NULL);
+
+  assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER);
+
+  assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER);
+
+  assert(pthread_mutex_lock(&start_flag) == 0);
+
+  ftime(&currSysTime);
+
+  abstime.tv_sec = currSysTime.time;
+  abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+  abstime.tv_sec += 5;
+
+  assert((t[0] = pthread_self()) != NULL);
+
+  awoken = 0;
+
+  for (i = 1; i <= NUMTHREADS; i++)
+    {
+      threadbag[i].started = 0;
+      threadbag[i].threadnum = i;
+      assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0);
+    }
+
+  /*
+   * Code to control or munipulate child threads should probably go here.
+   */
+
+  assert(pthread_mutex_unlock(&start_flag) == 0);
+
+  /*
+   * Give threads time to start.
+   */
+  Sleep(2000);
+
+  assert(pthread_mutex_lock(&cvthing.lock) == 0);
+
+  cvthing.shared++;
+
+  assert(pthread_mutex_unlock(&cvthing.lock) == 0);
+
+  assert(pthread_cond_broadcast(&cvthing.notbusy) == 0);
+
+  /*
+   * Give threads time to complete.
+   */
+  Sleep(2000);
+
+  /* 
+   * Cleanup the CV.
+   */
+  
+  assert(pthread_mutex_destroy(&cvthing.lock) == 0);
+
+  assert(cvthing.lock == NULL);
+
+  assert(pthread_cond_destroy(&cvthing.notbusy) == 0);
+
+  assert(cvthing.notbusy == NULL);
+
+  /*
+   * Standard check that all threads started.
+   */
+  for (i = 1; i <= NUMTHREADS; i++)
+    { 
+      failed = !threadbag[i].started;
+
+      if (failed)
+       {
+         fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started);
+       }
+    }
+
+  assert(!failed);
+
+  /*
+   * Check any results here.
+   */
+
+  assert(awoken == NUMTHREADS);
+
+  /*
+   * Success.
+   */
+  return 0;
+}
+
+
diff --git a/winsup/testsuite/winsup.api/pthread/condvar8.c b/winsup/testsuite/winsup.api/pthread/condvar8.c
new file mode 100644 (file)
index 0000000..771d91c
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * File: condvar8.c
+ *
+ * Test Synopsis:
+ * - Test multiple pthread_cond_broadcasts.
+ *
+ * Test Method (Validation or Falsification):
+ * - Validation
+ *
+ * Requirements Tested:
+ * - 
+ *
+ * Features Tested:
+ * - 
+ *
+ * Cases Tested:
+ * - 
+ *
+ * Description:
+ * - Make NUMTHREADS threads wait on CV, broadcast signal them, and then repeat.
+ *
+ * Environment:
+ * - 
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * - 
+ *
+ * Pass Criteria:
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+#include <sys/timeb.h>
+
+/*
+ * Create NUMTHREADS threads in addition to the Main thread.
+ */
+enum {
+  NUMTHREADS = 5
+};
+
+typedef struct bag_t_ bag_t;
+struct bag_t_ {
+  int threadnum;
+  int started;
+  /* Add more per-thread state variables here */
+};
+
+static bag_t threadbag[NUMTHREADS + 1];
+
+typedef struct cvthing_t_ cvthing_t;
+
+struct cvthing_t_ {
+  pthread_cond_t notbusy;
+  pthread_mutex_t lock;
+  int shared;
+};
+
+static cvthing_t cvthing = {
+  PTHREAD_COND_INITIALIZER,
+  PTHREAD_MUTEX_INITIALIZER,
+  0
+};
+
+static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER;
+
+static struct timespec abstime = { 0, 0 };
+
+static int awoken;
+
+static void *
+mythread(void * arg)
+{
+  bag_t * bag = (bag_t *) arg;
+
+  assert(bag == &threadbag[bag->threadnum]);
+  assert(bag->started == 0);
+  bag->started = 1;
+
+  /* Wait for the start gun */
+  assert(pthread_mutex_lock(&start_flag) == 0);
+  assert(pthread_mutex_unlock(&start_flag) == 0);
+
+  assert(pthread_mutex_lock(&cvthing.lock) == 0);
+
+  pthread_cleanup_push((__cleanup_routine_type)pthread_mutex_unlock,
+                      (void *) &cvthing.lock);
+
+  while (! (cvthing.shared > 0))
+    assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0);
+
+  pthread_cleanup_pop(0);
+
+  assert(cvthing.shared > 0);
+
+  awoken++;
+
+  assert(pthread_mutex_unlock(&cvthing.lock) == 0);
+
+  return (void *) 0;
+}
+
+int
+main()
+{
+  int failed = 0;
+  int i;
+  int first, last;
+  pthread_t t[NUMTHREADS + 1];
+
+  struct timeb currSysTime;
+  const DWORD NANOSEC_PER_MILLISEC = 1000000;
+
+  assert((t[0] = pthread_self()) != NULL);
+
+  assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER);
+
+  assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER);
+
+  ftime(&currSysTime);
+
+  abstime.tv_sec = currSysTime.time;
+  abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
+
+  abstime.tv_sec += 10;
+
+  assert((t[0] = pthread_self()) != NULL);
+
+  awoken = 0;
+
+  for (first = 1, last = NUMTHREADS / 2;
+       first < NUMTHREADS;
+       first = last + 1, last = NUMTHREADS)
+    {
+      assert(pthread_mutex_lock(&start_flag) == 0);
+
+      for (i = first; i <= last; i++)
+       {
+         threadbag[i].started = 0;
+         threadbag[i].threadnum = i;
+         assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0);
+         assert(pthread_detach(t[i]) == 0);
+       }
+
+      /*
+       * Code to control or munipulate child threads should probably go here.
+       */
+      cvthing.shared = 0;
+
+      assert(pthread_mutex_unlock(&start_flag) == 0);
+
+      /*
+       * Give threads time to start.
+       */
+      Sleep(1000);
+
+      assert(pthread_mutex_lock(&cvthing.lock) == 0);
+
+      cvthing.shared++;
+
+      assert(pthread_mutex_unlock(&cvthing.lock) == 0);
+
+      assert(pthread_cond_broadcast(&cvthing.notbusy) == 0);
+
+      /*
+       * Give threads time to complete.
+       */
+      Sleep(1000);
+
+      assert(awoken == (i - 1));
+    }
+
+
+  /*
+   * Standard check that all threads started.
+   */
+  for (i = 1; i <= NUMTHREADS; i++)
+    { 
+      failed = !threadbag[i].started;
+
+      if (failed)
+        {
+          fprintf(stderr, "Thread %d: started %d\n", i, threadbag[i].started);
+        }
+    }
+
+  /* 
+   * Cleanup the CV.
+   */
+  
+  assert(pthread_mutex_destroy(&cvthing.lock) == 0);
+
+  assert(cvthing.lock == NULL);
+
+  assert(pthread_cond_destroy(&cvthing.notbusy) == 0);
+
+  assert(cvthing.notbusy == NULL);
+
+  assert(!failed);
+
+  /*
+   * Check any results here.
+   */
+
+  assert(awoken == NUMTHREADS);
+
+  /*
+   * Success.
+   */
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/count1.c b/winsup/testsuite/winsup.api/pthread/count1.c
new file mode 100644 (file)
index 0000000..ae30ed0
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * count1.c
+ *
+ * Description:
+ * Test some basic assertions about the number of threads at runtime.
+ */
+
+#include "test.h"
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+#define NUMTHREADS (60)
+#else
+#define NUMTHREADS (59)
+#endif
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_t threads[NUMTHREADS];
+static unsigned numThreads = 0;
+
+void *
+myfunc(void *arg)
+{
+  pthread_mutex_lock(&lock);
+  numThreads++;
+  pthread_mutex_unlock(&lock);
+
+  Sleep(1000);
+  return 0;
+}
+int
+main()
+{
+  int i;
+  int maxThreads = sizeof(threads) / sizeof(pthread_t);
+
+  /*
+   * Spawn NUMTHREADS threads. Each thread should increment the
+   * numThreads variable, sleep for one second.
+   */
+  for (i = 0; i < maxThreads; i++)
+    {
+      assert(pthread_create(&threads[i], NULL, myfunc, 0) == 0);
+    }
+  
+  /*
+   * Wait for all the threads to exit.
+   */
+  for (i = 0; i < maxThreads; i++)
+    {
+      assert(pthread_join(threads[i], NULL) == 0);
+    }
+
+  /* 
+   * Check the number of threads created.
+   */
+  assert((int) numThreads == maxThreads);
+  
+  /*
+   * Success.
+   */
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/create1.c b/winsup/testsuite/winsup.api/pthread/create1.c
new file mode 100644 (file)
index 0000000..192e52d
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * create1.c
+ *
+ * Description:
+ * Create a thread and check that it ran.
+ *
+ * Depends on API functions: None.
+ */
+
+#include "test.h"
+
+static int washere = 0;
+
+void * func(void * arg)
+{
+  washere = 1;
+  return 0; 
+}
+int
+main()
+{
+  pthread_t t;
+
+  assert(pthread_create(&t, NULL, func, NULL) == 0);
+
+  /* A dirty hack, but we cannot rely on pthread_join in this
+     primitive test. */
+  Sleep(2000);
+
+  assert(washere == 1);
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/create2.c b/winsup/testsuite/winsup.api/pthread/create2.c
new file mode 100644 (file)
index 0000000..40e637b
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * File: create2.c
+ *
+ * Test Synopsis:
+ * - Test that threads have a Win32 handle when started.
+ *
+ * Test Method (Validation or Falsification):
+ * - Statistical, not absolute (depends on sample size).
+ *
+ * Requirements Tested:
+ * -
+ *
+ * Features Tested:
+ * -
+ *
+ * Cases Tested:
+ * -
+ *
+ * Description:
+ * -
+ *
+ * Environment:
+ * -
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * -
+ *
+ * Pass Criteria:
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+
+const int NUMTHREADS = 10000;
+
+static int washere = 0;
+
+void * func(void * arg)
+{
+  washere = 1;
+  return (void *) 0; 
+}
+int
+main()
+{
+  pthread_t t;
+  pthread_attr_t attr;
+  void * result = NULL;
+  int i;
+
+  pthread_attr_init(&attr);
+  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+  for (i = 0; i < NUMTHREADS; i++)
+    {
+      washere = 0;
+      assert(pthread_create(&t, &attr, func, NULL) == 0);
+      pthread_join(t, &result);
+      assert(washere == 1);
+    }
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/equal1.c b/winsup/testsuite/winsup.api/pthread/equal1.c
new file mode 100644 (file)
index 0000000..617a956
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Test for pthread_equal.
+ *
+ * Depends on functions: pthread_create().
+ */
+
+#include "test.h"
+
+void * func(void * arg)
+{
+  Sleep(2000);
+  return 0;
+}
+
+int 
+main()
+{
+  pthread_t t1, t2;
+
+  assert(pthread_create(&t1, NULL, func, (void *) 1) == 0);
+
+  assert(pthread_create(&t2, NULL, func, (void *) 2) == 0);
+
+  assert(pthread_equal(t1, t2) == 0);
+
+  assert(pthread_equal(t1,t1) != 0);
+
+  /* This is a hack. We don't want to rely on pthread_join
+     yet if we can help it. */
+   Sleep(4000);
+
+  /* Success. */
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/exit1.c b/winsup/testsuite/winsup.api/pthread/exit1.c
new file mode 100644 (file)
index 0000000..06b7692
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Test for pthread_exit().
+ *
+ * Depends on API functions: None.
+ */
+
+#include "test.h"
+
+int
+main(int argc, char * argv[])
+{
+       /* A simple test first. */
+       pthread_exit((void *) 0);
+
+       /* Not reached */
+       assert(0);
+       return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/exit2.c b/winsup/testsuite/winsup.api/pthread/exit2.c
new file mode 100644 (file)
index 0000000..684305b
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Test for pthread_exit().
+ *
+ * Depends on API functions:
+ *     pthread_create()
+ *     pthread_exit()
+ */
+
+#include "test.h"
+
+void *
+func(void * arg)
+{
+       pthread_exit(arg);
+
+       /* Never reached. */
+       assert(0);
+}
+
+int
+main(int argc, char * argv[])
+{
+  pthread_t t;
+
+  assert(pthread_create(&t, NULL, func, (void *) NULL) == 0);
+
+  Sleep(1000);
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/exit3.c b/winsup/testsuite/winsup.api/pthread/exit3.c
new file mode 100644 (file)
index 0000000..0b6ec31
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Test for pthread_exit().
+ *
+ * Depends on API functions: pthread_create().
+ */
+
+#include "test.h"
+
+void *
+func(void * arg)
+{
+       pthread_exit(arg);
+
+       /* Never reached. */
+       assert(0);
+}
+
+int
+main(int argc, char * argv[])
+{
+       pthread_t id[4];
+       int i;
+
+       /* Create a few threads and then exit. */
+       for (i = 0; i < 4; i++)
+         {
+           assert(pthread_create(&id[i], NULL, func, (void *) i) == 0);
+         }
+
+       Sleep(1000);
+
+       /* Success. */
+       return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/inherit1.c b/winsup/testsuite/winsup.api/pthread/inherit1.c
new file mode 100644 (file)
index 0000000..a909eb7
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * File: inherit1.c
+ *
+ * Test Synopsis:
+ * - Test thread priority inheritance.
+ *
+ * Test Method (Validation or Falsification):
+ * - 
+ *
+ * Requirements Tested:
+ * -
+ *
+ * Features Tested:
+ * -
+ *
+ * Cases Tested:
+ * -
+ *
+ * Description:
+ * -
+ *
+ * Environment:
+ * -
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * -
+ *
+ * Pass Criteria:
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+
+void * func(void * arg)
+{
+  int policy;
+  struct sched_param param;
+
+  assert(pthread_getschedparam(pthread_self(), &policy, &param) == 0);
+  return (void *) param.sched_priority;
+}
+
+int
+main()
+{
+  pthread_t t;
+  pthread_t mainThread = pthread_self();
+  pthread_attr_t attr;
+  void * result = NULL;
+  struct sched_param param;
+  struct sched_param mainParam;
+  int maxPrio;
+  int minPrio;
+  int prio;
+  int policy;
+  int inheritsched = -1;
+
+  assert((maxPrio = sched_get_priority_max(SCHED_OTHER)) != -1);
+  assert((minPrio = sched_get_priority_min(SCHED_OTHER)) != -1);
+
+  assert(pthread_attr_init(&attr) == 0);
+  assert(pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED) == 0);
+  assert(pthread_attr_getinheritsched(&attr, &inheritsched) == 0);
+  assert(inheritsched == PTHREAD_INHERIT_SCHED);
+
+  for (prio = minPrio; prio < maxPrio; prio++)
+    {
+      mainParam.sched_priority = prio;
+
+      /* Change the main thread priority */
+      assert(pthread_setschedparam(mainThread, SCHED_OTHER, &mainParam) == 0);
+      assert(pthread_getschedparam(mainThread, &policy, &mainParam) == 0);
+      assert(policy == SCHED_OTHER);
+      assert(mainParam.sched_priority == prio);
+
+      for (param.sched_priority = prio;
+           param.sched_priority <= maxPrio;
+           param.sched_priority++)
+        {
+          /* The new thread create should ignore this new priority */
+          assert(pthread_attr_setschedparam(&attr, &param) == 0);
+          assert(pthread_create(&t, &attr, func, NULL) == 0);
+          pthread_join(t, &result);
+          assert((int) result == mainParam.sched_priority);
+        }
+    }
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/join0.c b/winsup/testsuite/winsup.api/pthread/join0.c
new file mode 100644 (file)
index 0000000..54b0bee
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Test for pthread_join().
+ *
+ * Depends on API functions: pthread_create(), pthread_exit().
+ */
+
+#include "test.h"
+
+void *
+func(void * arg)
+{
+  Sleep(2000);
+
+  pthread_exit(arg);
+
+  /* Never reached. */
+  exit(1);
+}
+
+int
+main(int argc, char * argv[])
+{
+  pthread_t id;
+  int result;
+
+  /* Create a single thread and wait for it to exit. */
+  assert(pthread_create(&id, NULL, func, (void *) 123) == 0);
+
+  assert(pthread_join(id, (void **) &result) == 0);
+
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+  assert(result == 123);
+#else
+# warning pthread_join not fully supported in this configuration.
+  assert(result == 0);
+#endif
+
+  /* Success. */
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/join1.c b/winsup/testsuite/winsup.api/pthread/join1.c
new file mode 100644 (file)
index 0000000..d74e0c4
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Test for pthread_join().
+ *
+ * Depends on API functions: pthread_create(), pthread_join(), pthread_exit().
+ */
+
+#include "test.h"
+
+void *
+func(void * arg)
+{
+    int i = (int) arg;
+
+    Sleep(i * 500);
+
+    pthread_exit(arg);
+
+    /* Never reached. */
+    exit(1);
+}
+
+int
+main(int argc, char * argv[])
+{
+       pthread_t id[4];
+       int i;
+       int result;
+
+       /* Create a few threads and then exit. */
+       for (i = 0; i < 4; i++)
+         {
+           assert(pthread_create(&id[i], NULL, func, (void *) i) == 0);
+         }
+
+       /* Some threads will finish before they are joined, some after. */
+       Sleep(1000);
+
+       for (i = 0; i < 4; i++)
+         {
+           assert(pthread_join(id[i], (void **) &result) == 0);
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+           assert(result == i);
+#else
+# warning pthread_join not fully supported in this configuration.
+           assert(result == 0);
+#endif
+         }
+
+       /* Success. */
+       return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/join2.c b/winsup/testsuite/winsup.api/pthread/join2.c
new file mode 100644 (file)
index 0000000..cdc8ca2
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Test for pthread_join() returning return value from threads.
+ *
+ * Depends on API functions: pthread_create().
+ */
+
+#include "test.h"
+
+void *
+func(void * arg)
+{
+       Sleep(1000);
+       return arg;
+}
+
+int
+main(int argc, char * argv[])
+{
+       pthread_t id[4];
+       int i;
+       int result;
+
+       /* Create a few threads and then exit. */
+       for (i = 0; i < 4; i++)
+         {
+           assert(pthread_create(&id[i], NULL, func, (void *) i) == 0);
+         }
+
+       for (i = 0; i < 4; i++)
+         {
+           assert(pthread_join(id[i], (void **) &result) == 0);
+#if ! defined (__MINGW32__) || defined (__MSVCRT__)
+           /* CRTDLL _beginthread doesn't support return value, so
+              the assertion is guaranteed to fail. */
+           assert(result == i);
+#endif
+         }
+
+       /* Success. */
+       return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/mutex1.c b/winsup/testsuite/winsup.api/pthread/mutex1.c
new file mode 100644 (file)
index 0000000..b7f6b6f
--- /dev/null
@@ -0,0 +1,36 @@
+/* 
+ * mutex1.c
+ *
+ * Create a simple mutex object, lock it, and then unlock it again.
+ * This is the simplest test of the pthread mutex family that we can do.
+ *
+ * Depends on API functions:
+ *     pthread_mutex_init()
+ *     pthread_mutex_lock()
+ *     pthread_mutex_unlock()
+ *     pthread_mutex_destroy()
+ */
+
+#include "test.h"
+
+pthread_mutex_t mutex = NULL;
+
+int
+main()
+{
+  assert(mutex == NULL);
+
+  assert(pthread_mutex_init(&mutex, NULL) == 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/winsup/testsuite/winsup.api/pthread/mutex1r.c b/winsup/testsuite/winsup.api/pthread/mutex1r.c
new file mode 100644 (file)
index 0000000..b5131bb
--- /dev/null
@@ -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/winsup/testsuite/winsup.api/pthread/mutex2.c b/winsup/testsuite/winsup.api/pthread/mutex2.c
new file mode 100644 (file)
index 0000000..731c47f
--- /dev/null
@@ -0,0 +1,34 @@
+/* 
+ * mutex2.c
+ *
+ * Declare a static mutex object, lock it, 
+ * and then unlock it again.
+ *
+ * Depends on API functions: 
+ *     pthread_mutex_lock()
+ *     pthread_mutex_unlock()
+ */
+
+#include "test.h"
+pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+int
+main()
+{
+  assert(mutex == PTHREAD_MUTEX_INITIALIZER);
+
+  assert(pthread_mutex_lock(&mutex) == 0);
+
+  assert(mutex != PTHREAD_MUTEX_INITIALIZER);
+
+  assert(mutex != NULL);
+
+  assert(pthread_mutex_unlock(&mutex) == 0);
+
+  assert(pthread_mutex_destroy(&mutex) == 0);
+
+  assert(mutex == NULL);
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/mutex3.c b/winsup/testsuite/winsup.api/pthread/mutex3.c
new file mode 100644 (file)
index 0000000..07e75b1
--- /dev/null
@@ -0,0 +1,43 @@
+/* 
+ * mutex3.c
+ *
+ * Declare a static mutex object, lock it, trylock it, 
+ * and then unlock it again.
+ *
+ * Depends on API functions: 
+ *     pthread_mutex_lock()
+ *     pthread_mutex_trylock()
+ *     pthread_mutex_unlock()
+ */
+
+#include "test.h"
+pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
+
+static int washere = 0;
+
+void * func(void * arg)
+{
+  assert(pthread_mutex_trylock(&mutex1) == EBUSY);
+
+  washere = 1;
+
+  return 0; 
+}
+int
+main()
+{
+  pthread_t t;
+
+  assert(pthread_mutex_lock(&mutex1) == 0);
+
+  assert(pthread_create(&t, NULL, func, NULL) == 0);
+  assert(pthread_join(t, NULL) == 0);
+
+  assert(pthread_mutex_unlock(&mutex1) == 0);
+
+  assert(washere == 1);
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/mutex6r.c b/winsup/testsuite/winsup.api/pthread/mutex6r.c
new file mode 100644 (file)
index 0000000..586cc84
--- /dev/null
@@ -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/winsup/testsuite/winsup.api/pthread/once1.c b/winsup/testsuite/winsup.api/pthread/once1.c
new file mode 100644 (file)
index 0000000..91dc038
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * once1.c
+ *
+ * Create a static pthread_once and test that it calls myfunc once.
+ *
+ * Depends on API functions:
+ *     pthread_once()
+ *     pthread_create()
+ */
+
+#include "test.h"
+
+pthread_once_t once = PTHREAD_ONCE_INIT;
+
+static int washere = 0;
+
+void
+myfunc(void)
+{
+  washere++;
+}
+
+void *
+mythread(void * arg)
+{
+   assert(pthread_once(&once, myfunc) == 0);
+
+   return 0;
+}
+
+int
+main()
+{
+  pthread_t t1, t2;
+  
+  assert(pthread_create(&t1, NULL, mythread, NULL) == 0);
+
+  assert(pthread_create(&t2, NULL, mythread, NULL) == 0);
+
+  Sleep(2000);
+
+  assert(washere == 1);
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/priority1.c b/winsup/testsuite/winsup.api/pthread/priority1.c
new file mode 100644 (file)
index 0000000..a311028
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * File: priority1.c
+ *
+ * Test Synopsis:
+ * - Test thread priority explicit setting using thread attribute.
+ *
+ * Test Method (Validation or Falsification):
+ * - 
+ *
+ * Requirements Tested:
+ * -
+ *
+ * Features Tested:
+ * -
+ *
+ * Cases Tested:
+ * -
+ *
+ * Description:
+ * -
+ *
+ * Environment:
+ * -
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * -
+ *
+ * Pass Criteria:
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+
+void * func(void * arg)
+{
+  int policy;
+  struct sched_param param;
+
+  assert(pthread_getschedparam(pthread_self(), &policy, &param) == 0);
+  assert(policy == SCHED_OTHER);
+  return (void *) param.sched_priority;
+}
+int
+main()
+{
+  pthread_t t;
+  pthread_attr_t attr;
+  void * result = NULL;
+  struct sched_param param;
+  int maxPrio = sched_get_priority_max(SCHED_OTHER);
+  int minPrio = sched_get_priority_min(SCHED_OTHER);
+
+  assert(pthread_attr_init(&attr) == 0);
+  assert(pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) == 0);
+
+  for (param.sched_priority = minPrio;
+       param.sched_priority <= maxPrio;
+       param.sched_priority++)
+    {
+      assert(pthread_attr_setschedparam(&attr, &param) == 0);
+      assert(pthread_create(&t, &attr, func, NULL) == 0);
+      pthread_join(t, &result);
+      assert((int) result == param.sched_priority);
+    }
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/priority2.c b/winsup/testsuite/winsup.api/pthread/priority2.c
new file mode 100644 (file)
index 0000000..4dcf385
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * File: priority2.c
+ *
+ * Test Synopsis:
+ * - Test thread priority setting after creation.
+ *
+ * Test Method (Validation or Falsification):
+ * - 
+ *
+ * Requirements Tested:
+ * -
+ *
+ * Features Tested:
+ * -
+ *
+ * Cases Tested:
+ * -
+ *
+ * Description:
+ * -
+ *
+ * Environment:
+ * -
+ *
+ * Input:
+ * - None.
+ *
+ * Output:
+ * - File name, Line number, and failed expression on failure.
+ * - No output on success.
+ *
+ * Assumptions:
+ * -
+ *
+ * Pass Criteria:
+ * - Process returns zero exit status.
+ *
+ * Fail Criteria:
+ * - Process returns non-zero exit status.
+ */
+
+#include "test.h"
+
+pthread_mutex_t startMx = PTHREAD_MUTEX_INITIALIZER;
+
+void * func(void * arg)
+{
+  int policy;
+  struct sched_param param;
+
+  assert(pthread_mutex_lock(&startMx) == 0);
+  assert(pthread_getschedparam(pthread_self(), &policy, &param) == 0);
+  assert(pthread_mutex_unlock(&startMx) == 0);
+  assert(policy == SCHED_OTHER);
+  return (void *) param.sched_priority;
+}
+int
+main()
+{
+  pthread_t t;
+  void * result = NULL;
+  struct sched_param param;
+  int maxPrio = sched_get_priority_max(SCHED_OTHER);
+  int minPrio = sched_get_priority_min(SCHED_OTHER);
+
+  for (param.sched_priority = minPrio;
+       param.sched_priority <= maxPrio;
+       param.sched_priority++)
+    {
+      assert(pthread_mutex_lock(&startMx) == 0);
+      assert(pthread_create(&t, NULL, func, NULL) == 0);
+      assert(pthread_setschedparam(t, SCHED_OTHER, &param) == 0);
+      assert(pthread_mutex_unlock(&startMx) == 0);
+      pthread_join(t, &result);
+      assert((int) result == param.sched_priority);
+    }
+
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/self1.c b/winsup/testsuite/winsup.api/pthread/self1.c
new file mode 100644 (file)
index 0000000..d460818
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * self1.c
+ *
+ * Test for pthread_self().
+ *
+ * Depends on API functions:
+ *     pthread_self()
+ *
+ * Implicitly depends on:
+ *     pthread_getspecific()
+ *     pthread_setspecific()
+ */
+
+#include "test.h"
+
+int
+main(int argc, char * argv[])
+{
+       /*
+        * This should always succeed unless the system has no
+        * resources (memory) left.
+        */
+       assert(pthread_self() != NULL);
+
+       return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/self2.c b/winsup/testsuite/winsup.api/pthread/self2.c
new file mode 100644 (file)
index 0000000..83339f1
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * self2.c
+ *
+ * Test for pthread_self().
+ *
+ * Depends on API functions:
+ *     pthread_create()
+ *     pthread_self()
+ *
+ * Implicitly depends on:
+ *     pthread_getspecific()
+ *     pthread_setspecific()
+ */
+
+#include "test.h"
+#include <string.h>
+
+static pthread_t me;
+
+void *
+entry(void * arg)
+{
+  me = pthread_self();
+
+  return arg;
+}
+
+int
+main()
+{
+  pthread_t t;
+
+  assert(pthread_create(&t, NULL, entry, NULL) == 0);
+
+  Sleep(2000);
+
+  /*
+   * Not much more we can do here but bytewise compare t with
+   * what pthread_self returned.
+   */
+  assert(t == me);
+  assert(memcmp((const void *) t, (const void *) me, sizeof t) == 0);
+
+  /* Success. */
+  return 0;
+}
diff --git a/winsup/testsuite/winsup.api/pthread/test.h b/winsup/testsuite/winsup.api/pthread/test.h
new file mode 100644 (file)
index 0000000..a9a211d
--- /dev/null
@@ -0,0 +1,99 @@
+/* 
+ * test.h
+ *
+ * Useful definitions and declarations for tests.
+ */
+
+#ifndef _PTHREAD_TEST_H_
+#define _PTHREAD_TEST_H_
+
+#include "pthread.h"
+#include "sched.h"
+#include "semaphore.h"
+#include <stdio.h>
+#include <windows.h>
+#include <errno.h>
+
+/* #define assert(x) do { fprint (stderr, "assertion failed\n"); exit(1) } while (0) */
+
+char * error_string[] = {
+  "ZERO_or_EOK",
+  "EPERM",
+  "ENOFILE_or_ENOENT",
+  "ESRCH",
+  "EINTR",
+  "EIO",
+  "ENXIO",
+  "E2BIG",
+  "ENOEXEC",
+  "EBADF",
+  "ECHILD",
+  "EAGAIN",
+  "ENOMEM",
+  "EACCES",
+  "EFAULT",
+  "UNKNOWN_15",
+  "EBUSY",
+  "EEXIST",
+  "EXDEV",
+  "ENODEV",
+  "ENOTDIR",
+  "EISDIR",
+  "EINVAL",
+  "ENFILE",
+  "EMFILE",
+  "ENOTTY",
+  "UNKNOWN_26",
+  "EFBIG",
+  "ENOSPC",
+  "ESPIPE",
+  "EROFS",
+  "EMLINK",
+  "EPIPE",
+  "EDOM",
+  "ERANGE",
+  "UNKNOWN_35",
+  "EDEADLOCK_or_EDEADLK",
+  "UNKNOWN_37",
+  "ENAMETOOLONG",
+  "ENOLCK",
+  "ENOSYS",
+  "ENOTEMPTY",
+  "EILSEQ",
+};
+
+/*
+ * The Mingw32 assert macro calls the CRTDLL _assert function
+ * which pops up a dialog. We want to run in batch mode so
+ * we define our own assert macro.
+ */
+#ifdef assert
+# undef assert
+#endif
+
+#ifdef NDEBUG
+
+# define assert(e) ((void)0)
+
+#else /* NDEBUG */
+
+#ifndef ASSERT_TRACE
+# define ASSERT_TRACE 0
+#else
+# undef ASSERT_TRACE
+# define ASSERT_TRACE 1
+#endif
+
+# define assert(e) \
+   ((e) ? ((ASSERT_TRACE) ? fprintf(stderr, \
+                                    "Assertion succeeded: (%s), file %s, line %d\n", \
+                                   #e, __FILE__, (int) __LINE__), \
+                                   fflush(stderr) : \
+                             0) : \
+          (fprintf(stderr, "Assertion failed: (%s), file %s, line %d\n", \
+                   #e, __FILE__, (int) __LINE__), exit(1), 0))
+
+#endif /* NDEBUG */
+
+
+#endif
diff --git a/winsup/testsuite/winsup.api/pthread/tsd1.c b/winsup/testsuite/winsup.api/pthread/tsd1.c
new file mode 100644 (file)
index 0000000..a65cf66
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * tsd1.c
+ *
+ * Test Thread Specific Data (TSD) key creation and destruction.
+ *
+ * Description:
+ * - 
+ *
+ * Test Method (validation or falsification):
+ * - validation
+ *
+ * Requirements Tested:
+ * - keys are created for each existing thread including the main thread
+ * - keys are created for newly created threads
+ * - keys are thread specific
+ * - destroy routine is called on each thread exit including the main thread
+ *
+ * Features Tested:
+ * - 
+ *
+ * Cases Tested:
+ * - 
+ *
+ * Environment:
+ * - 
+ *
+ * Input:
+ * - none
+ *
+ * Output:
+ * - text to stdout
+ *
+ * Assumptions:
+ * - already validated:     pthread_create()
+ *                          pthread_once()
+ * - main thread also has a POSIX thread identity
+ *
+ * Pass Criteria:
+ * - stdout matches file reference/tsd1.out
+ *
+ * Fail Criteria:
+ * - fails to match file reference/tsd1.out
+ * - output identifies failed component
+ */
+
+#include <sched.h>
+#include "test.h"
+
+static pthread_key_t key = NULL;
+static int accesscount[10];
+static int thread_set[10];
+static int thread_destroyed[10];
+
+static void
+destroy_key(void * arg)
+{
+  int * j = (int *) arg;
+
+  (*j)++;
+
+  assert(*j == 2);
+
+  thread_destroyed[j - accesscount] = 1;
+}
+
+static void
+setkey(void * arg)
+{
+  int * j = (int *) arg;
+
+  thread_set[j - accesscount] = 1;
+
+  assert(*j == 0);
+
+  assert(pthread_getspecific(key) == NULL);
+
+  assert(pthread_setspecific(key, arg) == 0);
+
+  assert(pthread_getspecific(key) == arg);
+
+  (*j)++;
+
+  assert(*j == 1);
+}
+
+static void *
+mythread(void * arg)
+{
+  while (key == NULL)
+    {
+       sched_yield();
+    }
+
+  setkey(arg);
+
+  return 0;
+
+  /* Exiting the thread will call the key destructor. */
+}
+
+int
+main()
+{
+  int i;
+  int fail = 0;
+  pthread_t thread[10];
+
+  for (i = 1; i < 5; i++)
+    {
+       accesscount[i] = thread_set[i] = thread_destroyed[i] = 0;
+      assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0);
+    }
+
+  Sleep(2000);
+
+  /*
+   * Here we test that existing threads will get a key created
+   * for them.
+   */
+  assert(pthread_key_create(&key, destroy_key) == 0);
+
+  /*
+   * Test main thread key.
+   */
+  accesscount[0] = 0;
+  setkey((void *) &accesscount[0]);
+
+  /*
+   * Here we test that new threads will get a key created
+   * for them.
+   */
+  for (i = 5; i < 10; i++)
+    {
+       accesscount[i] = thread_set[i] = thread_destroyed[i] = 0;
+      assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0);
+    }
+
+  /*
+   * Wait for all threads to complete.
+   */
+  for (i = 1; i < 10; i++)
+    {
+       int result = 0;
+
+       assert(pthread_join(thread[i], (void **) &result) == 0);
+    }
+
+  assert(pthread_key_delete(key) == 0);
+
+  for (i = 1; i < 10; i++)
+    {
+       /*
+        * The counter is incremented once when the key is set to
+        * a value, and again when the key is destroyed. If the key
+        * doesn't get set for some reason then it will still be
+        * NULL and the destroy function will not be called, and
+        * hence accesscount will not equal 2.
+        */
+       if (accesscount[i] != 2)
+         {
+           fail++;
+           fprintf(stderr, "Thread %d key, set = %d, destroyed = %d\n",
+                       i, thread_set[i], thread_destroyed[i]);
+         }
+    }
+
+  fflush(stderr);
+
+  return (fail);
+}
This page took 0.09798 seconds and 5 git commands to generate.