Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEgor Duda <deo@logos-m.ru>2001-11-15 14:19:48 +0300
committerEgor Duda <deo@logos-m.ru>2001-11-15 14:19:48 +0300
commit4800c7477bc56de60f5a3fd917a8d4036b5375ae (patch)
tree84608005d7fcd6146b3de8a06af63e3d7cfe5fa3
parentf38ac9b70c69408b011797cf5b86579e60c5b7df (diff)
* 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.
-rw-r--r--winsup/testsuite/ChangeLog41
-rw-r--r--winsup/testsuite/winsup.api/pthread/cleanup2.c157
-rw-r--r--winsup/testsuite/winsup.api/pthread/cleanup3.c160
-rw-r--r--winsup/testsuite/winsup.api/pthread/condvar1.c65
-rw-r--r--winsup/testsuite/winsup.api/pthread/condvar2.c80
-rw-r--r--winsup/testsuite/winsup.api/pthread/condvar2_1.c107
-rw-r--r--winsup/testsuite/winsup.api/pthread/condvar3.c115
-rw-r--r--winsup/testsuite/winsup.api/pthread/condvar3_1.c148
-rw-r--r--winsup/testsuite/winsup.api/pthread/condvar3_2.c139
-rw-r--r--winsup/testsuite/winsup.api/pthread/condvar3_3.c100
-rw-r--r--winsup/testsuite/winsup.api/pthread/condvar4.c137
-rw-r--r--winsup/testsuite/winsup.api/pthread/condvar5.c136
-rw-r--r--winsup/testsuite/winsup.api/pthread/condvar6.c209
-rw-r--r--winsup/testsuite/winsup.api/pthread/condvar8.c221
-rw-r--r--winsup/testsuite/winsup.api/pthread/count1.c62
-rw-r--r--winsup/testsuite/winsup.api/pthread/create1.c34
-rw-r--r--winsup/testsuite/winsup.api/pthread/create2.c74
-rw-r--r--winsup/testsuite/winsup.api/pthread/equal1.c34
-rw-r--r--winsup/testsuite/winsup.api/pthread/exit1.c18
-rw-r--r--winsup/testsuite/winsup.api/pthread/exit2.c30
-rw-r--r--winsup/testsuite/winsup.api/pthread/exit3.c34
-rw-r--r--winsup/testsuite/winsup.api/pthread/inherit1.c99
-rw-r--r--winsup/testsuite/winsup.api/pthread/join0.c40
-rw-r--r--winsup/testsuite/winsup.api/pthread/join1.c51
-rw-r--r--winsup/testsuite/winsup.api/pthread/join2.c41
-rw-r--r--winsup/testsuite/winsup.api/pthread/mutex1.c36
-rw-r--r--winsup/testsuite/winsup.api/pthread/mutex1r.c42
-rw-r--r--winsup/testsuite/winsup.api/pthread/mutex2.c34
-rw-r--r--winsup/testsuite/winsup.api/pthread/mutex3.c43
-rw-r--r--winsup/testsuite/winsup.api/pthread/mutex6r.c68
-rw-r--r--winsup/testsuite/winsup.api/pthread/once1.c45
-rw-r--r--winsup/testsuite/winsup.api/pthread/priority1.c78
-rw-r--r--winsup/testsuite/winsup.api/pthread/priority2.c80
-rw-r--r--winsup/testsuite/winsup.api/pthread/self1.c26
-rw-r--r--winsup/testsuite/winsup.api/pthread/self2.c46
-rw-r--r--winsup/testsuite/winsup.api/pthread/test.h99
-rw-r--r--winsup/testsuite/winsup.api/pthread/tsd1.c170
37 files changed, 3099 insertions, 0 deletions
diff --git a/winsup/testsuite/ChangeLog b/winsup/testsuite/ChangeLog
index 849af81f3..67ed06a01 100644
--- a/winsup/testsuite/ChangeLog
+++ b/winsup/testsuite/ChangeLog
@@ -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
index 000000000..bcbaad3a7
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/cleanup2.c
@@ -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
index 000000000..f8201faa0
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/cleanup3.c
@@ -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
index 000000000..daa0f420e
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/condvar1.c
@@ -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
index 000000000..309f5dfdf
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/condvar2.c
@@ -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
index 000000000..da3416203
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/condvar2_1.c
@@ -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
index 000000000..249e260aa
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/condvar3.c
@@ -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
index 000000000..06f8bf704
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/condvar3_1.c
@@ -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
index 000000000..57e7eb439
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/condvar3_2.c
@@ -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
index 000000000..f6bcca9fa
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/condvar3_3.c
@@ -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
index 000000000..7a2007a4a
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/condvar4.c
@@ -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
index 000000000..b493ab136
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/condvar5.c
@@ -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
index 000000000..f011bea13
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/condvar6.c
@@ -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
index 000000000..771d91cb5
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/condvar8.c
@@ -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
index 000000000..ae30ed0a2
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/count1.c
@@ -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
index 000000000..192e52d9d
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/create1.c
@@ -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
index 000000000..40e637b9d
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/create2.c
@@ -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
index 000000000..617a95664
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/equal1.c
@@ -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
index 000000000..06b7692de
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/exit1.c
@@ -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
index 000000000..684305b40
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/exit2.c
@@ -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
index 000000000..0b6ec31c5
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/exit3.c
@@ -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
index 000000000..a909eb763
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/inherit1.c
@@ -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
index 000000000..54b0bee6b
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/join0.c
@@ -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
index 000000000..d74e0c484
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/join1.c
@@ -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
index 000000000..cdc8ca2d9
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/join2.c
@@ -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
index 000000000..b7f6b6f15
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/mutex1.c
@@ -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
index 000000000..b5131bb0e
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/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/winsup/testsuite/winsup.api/pthread/mutex2.c b/winsup/testsuite/winsup.api/pthread/mutex2.c
new file mode 100644
index 000000000..731c47fab
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/mutex2.c
@@ -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
index 000000000..07e75b187
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/mutex3.c
@@ -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
index 000000000..586cc841b
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/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/winsup/testsuite/winsup.api/pthread/once1.c b/winsup/testsuite/winsup.api/pthread/once1.c
new file mode 100644
index 000000000..91dc03832
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/once1.c
@@ -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
index 000000000..a31102895
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/priority1.c
@@ -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
index 000000000..4dcf3859f
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/priority2.c
@@ -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
index 000000000..d46081830
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/self1.c
@@ -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
index 000000000..83339f101
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/self2.c
@@ -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
index 000000000..a9a211dd7
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/test.h
@@ -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
index 000000000..a65cf66c8
--- /dev/null
+++ b/winsup/testsuite/winsup.api/pthread/tsd1.c
@@ -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);
+}