diff options
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, ¶m) == 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, ¶m) == 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, ¶m) == 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, ¶m) == 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, ¶m) == 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, ¶m) == 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); +} |