int do_cs_test(void) { int ret; int result=0; pthread_mutex_t mtxN, mtxI; pthread_cond_t cndN; pthread_condattr_t ca; pthread_t thN, thD; struct timespec ts, timeout; clockid_t cid; /* The 3 next data aim to minimize the impact on the * system time, when the monotonic clock is supported */ long monotonic_clk; struct timespec diff; char sens=0; /* We are going to initialize the cond vars and the mutexes */ dtN.pmtx = &mtxN; dtI.pmtx = &mtxI; dtN.pcnd = &cndN; dtI.pcnd = &cndI; ret = pthread_mutex_init(&mtxI, NULL); if (ret != 0) { UNRESOLVED(ret, "Unable to initialize a default mutex"); } ret = pthread_mutex_init(&mtxN, NULL); if (ret != 0) { UNRESOLVED(ret, "Unable to initialize a default mutex"); } ret = pthread_condattr_init(&ca); if (ret != 0) { UNRESOLVED(ret, "Unable to initialize cond attribute object"); } #if 0 /* Test if the testcase is valid: change the clock from the "NULL" cond var */ pthread_condattr_setclock(&ca, CLOCK_MONOTONIC); ret = pthread_cond_init(&cndN, &ca); pthread_condattr_setclock(&ca, CLOCK_REALTIME); #else ret = pthread_cond_init(&cndN, NULL); #endif if (ret != 0) { UNRESOLVED(ret, "Unable to initialize the NULL attribute conditional variable."); } dtI.ctrl = 0; dtN.ctrl = 0; dtI.rc = 0; dtN.rc = 0; #if VERBOSE > 1 output("Data initialized successfully for CS test.\n"); #endif monotonic_clk = sysconf(_SC_MONOTONIC_CLOCK); #if VERBOSE > 1 output("Sysconf for monotonix clock: %li\n", monotonic_clk); #endif /* Get the default clock ID */ ret = pthread_condattr_getclock(&ca, &cid); if (ret != 0) { UNRESOLVED(ret, "Unable to get clockid from the default cond attribute object"); } /* Check whether we can set the system clock */ /* Backup the current monotonic time if available */ if (monotonic_clk != -1L) { ret = clock_gettime(CLOCK_MONOTONIC, &diff); if (ret != 0) { output("Clock_gettime(CLOCK_MONOTONIC) failed when the system claims to support this option\n"); monotonic_clk = -1L; } } ret = clock_gettime(cid, &ts); if (ret != 0) { UNRESOLVED(errno, "Unable to get clock time"); } ret = clock_settime(cid, &ts); if (ret != 0) { #if VERBOSE > 1 output("clock_settime failed (%s)\n", strerror(errno)); output("We cannot test if both cond uses the same clock then...\n"); #endif UNTESTED("Was unable to set the default clock time. Need more privileges?"); } else /* We can do the test */ { #if VERBOSE > 1 output("clock_settime succeeded\n"); #endif if (monotonic_clk != -1L) { #if VERBOSE > 2 output("Monotonic clock : %10i.%09li\n", diff.tv_sec, diff.tv_nsec); output("Default clock : %10i.%09li\n", ts.tv_sec, ts.tv_nsec); #endif /* Save the decay between default clock and clock MONOTONIC */ if (diff.tv_sec > ts.tv_sec) { sens = -1; /* monotonic was bigger than system */ if (diff.tv_nsec < ts.tv_nsec) { diff.tv_nsec += 1000000000 - ts.tv_nsec; diff.tv_sec -= 1 + ts.tv_sec; } else { diff.tv_nsec -= ts.tv_nsec; diff.tv_sec -= ts.tv_sec; } } else { if (diff.tv_sec == ts.tv_sec) { diff.tv_sec = 0; if (diff.tv_nsec > ts.tv_nsec) { sens = -1; diff.tv_nsec -= ts.tv_nsec; } else { sens = 1; /* Default clock was bigger than monotonic */ diff.tv_nsec = ts.tv_nsec - diff.tv_nsec; } } else /* ts.tv_sec > diff.tv_sec */ { sens = 1; if (ts.tv_nsec < diff.tv_nsec) { diff.tv_nsec = 1000000000 + ts.tv_nsec - diff.tv_nsec; diff.tv_sec = ts.tv_sec - (1 + diff.tv_sec); } else { diff.tv_nsec = ts.tv_nsec - diff.tv_nsec; diff.tv_sec = ts.tv_sec - diff.tv_sec; } } } #if VERBOSE > 2 output("Computed diff : %10i.%09li\n", diff.tv_sec, diff.tv_nsec); output("With monotonic %s than default\n", sens>0?"smaller":"bigger"); #endif } /* Prepare the timeout parameters */ timeout.tv_nsec = 0; timeout.tv_sec = ts.tv_sec + 260000; /* About 3 days later */ dtN.timeout = &timeout; dtI.timeout = &timeout; /* create the threads */ ret = pthread_create(&thD, NULL, test_timeout, &dtI); if (ret != 0) { UNRESOLVED(ret, "Unable to create a thread"); } ret = pthread_create(&thN, NULL, test_timeout, &dtN); if (ret != 0) { UNRESOLVED(ret, "Unable to create a thread"); } /* Lock the two mutex and make sure the threads are in wait */ ret = pthread_mutex_lock(&mtxN); if (ret != 0) { UNRESOLVED(ret, "Unable to lock a mutex"); } while ((dtN.ctrl & FLAG_INWAIT) == 0) { ret = pthread_mutex_unlock(&mtxN); if (ret != 0) { UNRESOLVED(ret, "Unable to unlock a mutex"); } sched_yield(); ret = pthread_mutex_lock(&mtxN); if (ret != 0) { UNRESOLVED(ret, "Unable to lock a mutex"); } } ret = pthread_mutex_lock(&mtxI); if (ret != 0) { UNRESOLVED(ret, "Unable to lock a mutex"); } while ((dtI.ctrl & FLAG_INWAIT) == 0) { ret = pthread_mutex_unlock(&mtxI); if (ret != 0) { UNRESOLVED(ret, "Unable to unlock a mutex"); } sched_yield(); ret = pthread_mutex_lock(&mtxI); if (ret != 0) { UNRESOLVED(ret, "Unable to lock a mutex"); } } /* Now both threads are in the timed wait */ #if VERBOSE > 1 output("Two threads are created and waiting.\n"); output("About to change the default clock value.\n"); #endif /* We re-read the default clock time, to introduce minimal error on the clock */ ret = clock_gettime(cid, &ts); if (ret != 0) { UNRESOLVED(errno, "Unable to get clock time"); } ts.tv_sec += 604800; /* Exactly 1 week forth */ /* We set the clock to a date after the timeout parameter */ ret = clock_settime(cid, &ts); if (ret != 0) { UNRESOLVED(errno, "Unable to set clock time (again)"); } /* unlock the two mutex */ ret = pthread_mutex_unlock(&mtxI); if (ret != 0) { UNRESOLVED(ret, "Unable to unlock a mutex"); } ret = pthread_mutex_unlock(&mtxN); if (ret != 0) { UNRESOLVED(ret, "Unable to unlock a mutex"); } /* Let the others threads run */ sched_yield(); #if VERBOSE > 1 output("Checking that both threads have timedout...\n"); #endif /* Relock the mutexs */ ret = pthread_mutex_lock(&mtxN); if (ret != 0) { UNRESOLVED(ret, "Unable to lock a mutex"); } ret = pthread_mutex_lock(&mtxI); if (ret != 0) { UNRESOLVED(ret, "Unable to lock a mutex"); } /* Check whether the thread has timedout */ if (dtI.rc == 0) { #if VERBOSE > 0 output("The thread was not woken when the clock was changed so as the timeout expired\n"); output("Going to simulate this POSIX behavior...\n"); #endif ret = pthread_cond_signal(&cndN); if (ret != 0) { UNRESOLVED(ret, "Unable to signal the Null attribute condition"); } ret = pthread_cond_signal(&cndI); if (ret != 0) { UNRESOLVED(ret, "Unable to signal the Default attribute condition"); } /* The threads will now report a spurious wake up ... */ /* We give the threads another chance to timeout */ /* unlock the two mutex */ ret = pthread_mutex_unlock(&mtxI); if (ret != 0) { UNRESOLVED(ret, "Unable to unlock a mutex"); } ret = pthread_mutex_unlock(&mtxN); if (ret != 0) { UNRESOLVED(ret, "Unable to unlock a mutex"); } /* Let the others threads run */ sched_yield(); #if VERBOSE > 1 output("Rechecking that both threads have timedout...\n"); #endif /* Relock the mutexs */ ret = pthread_mutex_lock(&mtxN); if (ret != 0) { UNRESOLVED(ret, "Unable to lock a mutex"); } ret = pthread_mutex_lock(&mtxI); if (ret != 0) { UNRESOLVED(ret, "Unable to lock a mutex"); } } /* Process the Null condvar */ if ((dtN.ctrl & FLAG_TIMEDOUT) != 0) { #if VERBOSE > 1 output("Null attribute cond var timed out\n"); #endif /* Join the thread */ ret = pthread_join(thN, NULL); if (ret != 0) { UNRESOLVED(ret, "Join thread failed"); } /* Unlock the mutex */ ret = pthread_mutex_unlock(&mtxN); if (ret != 0) { UNRESOLVED(ret, "Unable to unlock a mutex"); } } else { #if VERBOSE > 1 output("Null attribute cond var did not time out\n"); #endif /* Signal the condition */ dtN.ctrl |= FLAG_CONDWAKE; ret = pthread_cond_signal(&cndN); if (ret != 0) { UNRESOLVED(ret, "Unable to signal the Null attribute condition"); } /* Unlock the mutex and join the thread */ ret = pthread_mutex_unlock(&mtxN); if (ret != 0) { UNRESOLVED(ret, "Unable to unlock a mutex"); } /* Join the thread */ ret = pthread_join(thN, NULL); if (ret != 0) { UNRESOLVED(ret, "Join thread failed"); } } /* Process the Default condvar */ if ((dtI.ctrl & FLAG_TIMEDOUT) != 0) { #if VERBOSE > 1 output("Default attribute cond var timed out\n"); #endif /* Join the thread */ ret = pthread_join(thD, NULL); if (ret != 0) { UNRESOLVED(ret, "Join thread failed"); } /* Unlock the mutex */ ret = pthread_mutex_unlock(&mtxI); if (ret != 0) { UNRESOLVED(ret, "Unable to unlock a mutex"); } } else { #if VERBOSE > 1 output("Default attribute cond var did not time out\n"); #endif /* Signal the condition */ dtI.ctrl |= FLAG_CONDWAKE; ret = pthread_cond_signal(&cndI); if (ret != 0) { UNRESOLVED(ret, "Unable to signal the Default attribute condition"); } /* Unlock the mutex and join the thread */ ret = pthread_mutex_unlock(&mtxI); if (ret != 0) { UNRESOLVED(ret, "Unable to unlock a mutex"); } /* Join the thread */ ret = pthread_join(thD, NULL); if (ret != 0) { UNRESOLVED(ret, "Join thread failed"); } } /* Set the system time back to its value */ if (monotonic_clk == -1L) /* Monotonic is not supported */ { ret = clock_gettime(cid, &ts); if (ret != 0) { UNRESOLVED(errno, "Unable to get clock time"); } ts.tv_sec -= 604800; /* Exactly 1 week back */ /* We set the clock to a date after the timeout parameter */ ret = clock_settime(cid, &ts); if (ret != 0) { UNRESOLVED(errno, "Unable to set clock time (3rd time)"); } #if VERBOSE > 1 output("Default clock was set back\n"); #endif } else { /* Read the monotonic time */ ret = clock_gettime(CLOCK_MONOTONIC, &ts); if (ret != 0) { UNRESOLVED(errno, "Unable to get monotonic clock time"); } /* Apply the difference back */ if (sens > 0) /* monotonic was smaller than system => we must add the diff value */ { ts.tv_sec += diff.tv_sec; ts.tv_nsec += diff.tv_nsec; if (ts.tv_nsec >= 1000000000) { ts.tv_nsec -= 1000000000; ts.tv_sec += 1; } } else /* monotonic was bigger than system => we must remove the diff value */ { ts.tv_sec -= diff.tv_sec; if (ts.tv_nsec < diff.tv_nsec) { ts.tv_sec -= 1; ts.tv_nsec += 1000000000 - diff.tv_nsec; } else { ts.tv_nsec -= diff.tv_nsec; } } /* We set the clock to a date after the timeout parameter */ ret = clock_settime(cid, &ts); if (ret != 0) { UNRESOLVED(errno, "Unable to set clock time (3rd time)"); } #if VERBOSE > 1 output("Default clock was set back using monotonic clock as a reference\n"); #endif } /* Compare the two cond vars */ #if VERBOSE > 2 output("Default attribute cond var timedwait return value: %d\n", dtI.rc); output("Default attribute cond var exited with a timeout : %s\n", (dtI.ctrl & FLAG_TIMEDOUT)?"yes":"no"); output("Default attribute cond var had to be signaled : %s\n", (dtI.ctrl & FLAG_CONDWAKE)?"yes":"no"); output("Default attribute cond var exited as signaled : %s\n", (dtI.ctrl & FLAG_AWAKEN)?"yes":"no"); output("Default attribute cond var spurious wakeups : %d\n", (dtI.ctrl & MASK_COUNTER) - 1); output(" Null attribute cond var timedwait return value: %d\n", dtN.rc); output(" Null attribute cond var exited with a timeout : %s\n", (dtN.ctrl & FLAG_TIMEDOUT)?"yes":"no"); output(" Null attribute cond var had to be signaled : %s\n", (dtN.ctrl & FLAG_CONDWAKE)?"yes":"no"); output(" Null attribute cond var exited as signaled : %s\n", (dtN.ctrl & FLAG_AWAKEN)?"yes":"no"); output(" Null attribute cond var spurious wakeups : %d\n", (dtN.ctrl & MASK_COUNTER) - 1); #endif if ((dtN.ctrl == dtI.ctrl) && (dtN.rc == dtI.rc)) { result = 0; #if VERBOSE > 1 output("The two cond vars behaved exactly in the same maneer\n"); #endif } else { if ((dtN.ctrl & FLAG_TIMEDOUT) != (dtI.ctrl & FLAG_TIMEDOUT)) { result += 1; /* The test has failed */ } else { if (dtN.rc != dtI.rc) { output("Error codes were different: N:%d D:%d\n",dtN.rc, dtI.rc); UNRESOLVED(dtN.rc>dtI.rc?dtN.rc:dtI.rc, "Different error codes?"); } if ((dtN.ctrl & FLAG_AWAKEN) == (dtI.ctrl & FLAG_AWAKEN)) { /* The number of spurious wakeups is different */ output("Different spurious wakeups: N:%d D:%d\n", (dtN.ctrl & MASK_COUNTER) - 1, (dtI.ctrl & MASK_COUNTER) - 1); result = 0; /* We don't consider this as a fail case */ } } } } /* We can cleanup things now */ ret = pthread_cond_destroy(&cndN); if (ret != 0) { UNRESOLVED(ret, "Cond destroy failed"); } ret = pthread_condattr_destroy(&ca); if (ret != 0) { UNRESOLVED(ret, "Cond attr destroy failed"); } ret = pthread_mutex_destroy(&mtxN); if (ret != 0) { UNRESOLVED(ret, "Mutex destroy failed"); } ret = pthread_mutex_destroy(&mtxI); if (ret != 0) { UNRESOLVED(ret, "Mutex destroy failed"); } return result; }
int main(int argc, char *argv[]) { int ret; pthread_mutexattr_t ma; pthread_condattr_t ca; int scenar; long pshared, monotonic, cs, mf; pid_t p_child[NTHREADS]; pthread_t t_child[NTHREADS]; int ch; pid_t pid; int status; pthread_t t_timer; testdata_t alternativ; output_init(); /* check the system abilities */ pshared = sysconf(_SC_THREAD_PROCESS_SHARED); cs = sysconf(_SC_CLOCK_SELECTION); monotonic = sysconf(_SC_MONOTONIC_CLOCK); mf = sysconf(_SC_MAPPED_FILES); #if VERBOSE > 0 output("Test starting\n"); output("System abilities:\n"); output(" TPS : %li\n", pshared); output(" CS : %li\n", cs); output(" MON : %li\n", monotonic); output(" MF : %li\n", mf); if ((mf < 0) || (pshared < 0)) output("Process-shared attributes won't be tested\n"); if ((cs < 0) || (monotonic < 0)) output("Alternative clock won't be tested\n"); #endif /* We are not interested in testing the clock if we have no other clock available.. */ if (monotonic < 0) cs = -1; #ifndef USE_ALTCLK if (cs > 0) output ("Implementation supports the MONOTONIC CLOCK but option is disabled in test.\n"); #endif /********** * Allocate space for the testdata structure */ if (mf < 0) { /* Cannot mmap a file, we use an alternative method */ td = &alternativ; pshared = -1; /* We won't do this testing anyway */ #if VERBOSE > 0 output("Testdata allocated in the process memory.\n"); #endif } else { /* We will place the test data in a mmaped file */ char filename[] = "/tmp/cond_wait_stress-XXXXXX"; size_t sz, ps; void *mmaped; int fd; char *tmp; /* We now create the temp files */ fd = mkstemp(filename); if (fd == -1) { UNRESOLVED(errno, "Temporary file could not be created"); } /* and make sure the file will be deleted when closed */ unlink(filename); #if VERBOSE > 1 output("Temp file created (%s).\n", filename); #endif ps = (size_t) sysconf(_SC_PAGESIZE); sz = ((sizeof(testdata_t) / ps) + 1) * ps; /* # pages needed to store the testdata */ tmp = calloc(1, sz); if (tmp == NULL) { UNRESOLVED(errno, "Memory allocation failed"); } /* Write the data to the file. */ if (write(fd, tmp, sz) != (ssize_t) sz) { UNRESOLVED(sz, "Writting to the file failed"); } free(tmp); /* Now we can map the file in memory */ mmaped = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mmaped == MAP_FAILED) { UNRESOLVED(errno, "mmap failed"); } td = (testdata_t *) mmaped; /* Our datatest structure is now in shared memory */ #if VERBOSE > 1 output("Testdata allocated in shared memory (%ib).\n", sizeof(testdata_t)); #endif } /* Do the test for each test scenario */ for (scenar = 0; scenar < NSCENAR; scenar++) { /* set / reset everything */ td->fork = 0; ret = pthread_mutexattr_init(&ma); if (ret != 0) { UNRESOLVED(ret, "[parent] Unable to initialize the mutex attribute object"); } ret = pthread_condattr_init(&ca); if (ret != 0) { UNRESOLVED(ret, "[parent] Unable to initialize the cond attribute object"); } #ifndef WITHOUT_XOPEN /* Set the mutex type */ ret = pthread_mutexattr_settype(&ma, scenarii[scenar].m_type); if (ret != 0) { UNRESOLVED(ret, "[parent] Unable to set mutex type"); } #endif /* Set the pshared attributes, if supported */ if ((pshared > 0) && (scenarii[scenar].mc_pshared != 0)) { ret = pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED); if (ret != 0) { UNRESOLVED(ret, "[parent] Unable to set the mutex process-shared"); } ret = pthread_condattr_setpshared(&ca, PTHREAD_PROCESS_SHARED); if (ret != 0) { UNRESOLVED(ret, "[parent] Unable to set the cond var process-shared"); } } /* Set the alternative clock, if supported */ #ifdef USE_ALTCLK if ((cs > 0) && (scenarii[scenar].c_clock != 0)) { ret = pthread_condattr_setclock(&ca, CLOCK_MONOTONIC); if (ret != 0) { UNRESOLVED(ret, "[parent] Unable to set the monotonic clock for the cond"); } } ret = pthread_condattr_getclock(&ca, &td->cid); if (ret != 0) { UNRESOLVED(ret, "Unable to get clock from cond attr"); } #else td->cid = CLOCK_REALTIME; #endif /* Tell whether the test will be across processes */ if ((pshared > 0) && (scenarii[scenar].fork != 0)) { td->fork = 1; } /* initialize the condvar */ ret = pthread_cond_init(&td->cnd, &ca); if (ret != 0) { UNRESOLVED(ret, "Cond init failed"); } /* initialize the mutex */ ret = pthread_mutex_init(&td->mtx, &ma); if (ret != 0) { UNRESOLVED(ret, "Mutex init failed"); } /* Destroy the attributes */ ret = pthread_condattr_destroy(&ca); if (ret != 0) { UNRESOLVED(ret, "Failed to destroy the cond var attribute object"); } ret = pthread_mutexattr_destroy(&ma); if (ret != 0) { UNRESOLVED(ret, "Failed to destroy the mutex attribute object"); } #if VERBOSE > 2 output("[parent] Starting test %s\n", scenarii[scenar].descr); #endif td->count = 0; /* Create all the children */ for (ch = 0; ch < NTHREADS; ch++) { if (td->fork == 0) { ret = pthread_create(&t_child[ch], NULL, child, NULL); if (ret != 0) { UNRESOLVED(ret, "Failed to create a child thread"); } } else { p_child[ch] = fork(); if (p_child[ch] == -1) { ret = errno; for (--ch; ch >= 0; ch--) kill(p_child[ch], SIGKILL); UNRESOLVED(ret, "Failed to create a child process"); } if (p_child[ch] == 0) { /* We are the child */ child(NULL); exit(0); } } } #if VERBOSE > 4 output("[parent] All children are running\n"); #endif /* Make sure all children are waiting */ ret = pthread_mutex_lock(&td->mtx); if (ret != 0) { UNRESOLVED_KILLALL(ret, "Failed to lock mutex", p_child); } ch = td->count; while (ch < NTHREADS) { ret = pthread_mutex_unlock(&td->mtx); if (ret != 0) { UNRESOLVED_KILLALL(ret, "Failed to unlock mutex", p_child); } sched_yield(); ret = pthread_mutex_lock(&td->mtx); if (ret != 0) { UNRESOLVED_KILLALL(ret, "Failed to lock mutex", p_child); } ch = td->count; } #if VERBOSE > 4 output("[parent] All children are waiting\n"); #endif /* create the timeout thread */ ret = pthread_create(&t_timer, NULL, timer, p_child); if (ret != 0) { UNRESOLVED_KILLALL(ret, "Unable to create timer thread", p_child); } /* Wakeup the children */ td->predicate = 1; ret = pthread_cond_signal(&td->cnd); if (ret != 0) { UNRESOLVED_KILLALL(ret, "Failed to signal the condition.", p_child); } #if VERBOSE > 4 output("[parent] Condition was signaled\n"); #endif ret = pthread_mutex_unlock(&td->mtx); if (ret != 0) { UNRESOLVED_KILLALL(ret, "Failed to unlock mutex", p_child); } #if VERBOSE > 4 output("[parent] Joining the children\n"); #endif /* join the children */ for (ch = (NTHREADS - 1); ch >= 0; ch--) { if (td->fork == 0) { ret = pthread_join(t_child[ch], NULL); if (ret != 0) { UNRESOLVED(ret, "Failed to join a child thread"); } } else { pid = waitpid(p_child[ch], &status, 0); if (pid != p_child[ch]) { ret = errno; output ("Waitpid failed (expected: %i, got: %i)\n", p_child[ch], pid); for (; ch >= 0; ch--) { kill(p_child[ch], SIGKILL); } UNRESOLVED(ret, "Waitpid failed"); } if (WIFEXITED(status)) { /* the child should return only failed or unresolved or passed */ if (ret != PTS_FAIL) ret |= WEXITSTATUS(status); } } } if (ret != 0) { output_fini(); exit(ret); } #if VERBOSE > 4 output("[parent] All children terminated\n"); #endif /* cancel the timeout thread */ ret = pthread_cancel(t_timer); if (ret != 0) { /* Strange error here... the thread cannot be terminated (app would be killed) */ UNRESOLVED(ret, "Failed to cancel the timeout handler"); } /* join the timeout thread */ ret = pthread_join(t_timer, NULL); if (ret != 0) { UNRESOLVED(ret, "Failed to join the timeout handler"); } /* Destroy the datas */ ret = pthread_cond_destroy(&td->cnd); if (ret != 0) { UNRESOLVED(ret, "Failed to destroy the condvar"); } ret = pthread_mutex_destroy(&td->mtx); if (ret != 0) { UNRESOLVED(ret, "Failed to destroy the mutex"); } } /* exit */ PASSED; }
static int run_test (clockid_t cl) { pthread_condattr_t condattr; pthread_cond_t cond; pthread_mutexattr_t mutattr; pthread_mutex_t mut; printf ("clock = %d\n", (int) cl); if (pthread_condattr_init (&condattr) != 0) { puts ("condattr_init failed"); return 1; } if (pthread_condattr_setclock (&condattr, cl) != 0) { puts ("condattr_setclock failed"); return 1; } clockid_t cl2; if (pthread_condattr_getclock (&condattr, &cl2) != 0) { puts ("condattr_getclock failed"); return 1; } if (cl != cl2) { printf ("condattr_getclock returned wrong value: %d, expected %d\n", (int) cl2, (int) cl); return 1; } if (pthread_cond_init (&cond, &condattr) != 0) { puts ("cond_init failed"); return 1; } if (pthread_condattr_destroy (&condattr) != 0) { puts ("condattr_destroy failed"); return 1; } if (pthread_mutexattr_init (&mutattr) != 0) { puts ("mutexattr_init failed"); return 1; } if (pthread_mutexattr_settype (&mutattr, PTHREAD_MUTEX_ERRORCHECK) != 0) { puts ("mutexattr_settype failed"); return 1; } if (pthread_mutex_init (&mut, &mutattr) != 0) { puts ("mutex_init failed"); return 1; } if (pthread_mutexattr_destroy (&mutattr) != 0) { puts ("mutexattr_destroy failed"); return 1; } if (pthread_mutex_lock (&mut) != 0) { puts ("mutex_lock failed"); return 1; } if (pthread_mutex_lock (&mut) != EDEADLK) { puts ("2nd mutex_lock did not return EDEADLK"); return 1; } struct timespec ts; if (clock_gettime (cl, &ts) != 0) { puts ("clock_gettime failed"); return 1; } /* Wait one second. */ ++ts.tv_sec; int e = pthread_cond_timedwait (&cond, &mut, &ts); if (e == 0) { puts ("cond_timedwait succeeded"); return 1; } else if (e != ETIMEDOUT) { puts ("cond_timedwait did not return ETIMEDOUT"); return 1; } struct timespec ts2; if (clock_gettime (cl, &ts2) != 0) { puts ("second clock_gettime failed"); return 1; } if (ts2.tv_sec < ts.tv_sec || (ts2.tv_sec == ts.tv_sec && ts2.tv_nsec < ts.tv_nsec)) { puts ("timeout too short"); return 1; } if (pthread_mutex_unlock (&mut) != 0) { puts ("mutex_unlock failed"); return 1; } if (pthread_mutex_destroy (&mut) != 0) { puts ("mutex_destroy failed"); return 1; } if (pthread_cond_destroy (&cond) != 0) { puts ("cond_destroy failed"); return 1; } return 0; }
int main(void) { int ret, j; unsigned int i; pthread_mutexattr_t ma; pthread_condattr_t ca; pthread_t th[NTHREADS]; int loc_started, loc_stopped; long altclk_ok, pshared_ok; struct { char altclk; /* Want to use alternative clock */ char pshared; /* Want to use process-shared primitives */ int type; /* mutex type */ char *descr; /* Description of the case */ } scenar[] = { { 0, 0, PTHREAD_MUTEX_RECURSIVE, "Recursive mutex" }, { 0, 0, PTHREAD_MUTEX_ERRORCHECK, "Errorcheck mutex" }, #ifdef USE_ALTCLK { 1, 0, PTHREAD_MUTEX_RECURSIVE, "Recursive mutex + altclock cond" }, { 1, 0, PTHREAD_MUTEX_ERRORCHECK, "Errorcheck mutex + altclock cond" }, { 1, 1, PTHREAD_MUTEX_RECURSIVE, "Recursive pshared mutex + altclock cond" }, { 1, 1, PTHREAD_MUTEX_ERRORCHECK, "Errorcheck pshared mutex + altclock cond" }, #endif { 0, 1, PTHREAD_MUTEX_RECURSIVE, "Recursive pshared mutex" }, { 0, 1, PTHREAD_MUTEX_ERRORCHECK, "Errorcheck pshared mutex" }, }; output_init(); /* Initialize the constants */ altclk_ok = sysconf(_SC_CLOCK_SELECTION); if (altclk_ok > 0) altclk_ok = sysconf(_SC_MONOTONIC_CLOCK); #ifndef USE_ALTCLK if (altclk_ok > 0) output("Implementation supports the MONOTONIC CLOCK " "but option is disabled in test.\n"); #endif pshared_ok = sysconf(_SC_THREAD_PROCESS_SHARED); #if VERBOSE > 0 output("Test starting\n"); output(" Process-shared primitive %s be tested\n", (pshared_ok > 0) ? "will" : "won't"); output(" Alternative clock for cond %s be tested\n", (altclk_ok > 0) ? "will" : "won't"); #endif for (i = 0; i < (sizeof(scenar) / sizeof(scenar[0])); i++) { #if VERBOSE > 1 output("Starting test for %s\n", scenar[i].descr); #endif /* Initialize the data structure */ ret = pthread_mutexattr_init(&ma); if (ret != 0) UNRESOLVED(ret, "Mutex attribute object init failed"); ret = pthread_mutexattr_settype(&ma, scenar[i].type); if (ret != 0) UNRESOLVED(ret, "Unable to set mutex type"); if ((pshared_ok > 0) && (scenar[i].pshared != 0)) { ret = pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED); if (ret != 0) UNRESOLVED(ret, "Unable to set mutex process-shared"); } ret = pthread_condattr_init(&ca); if (ret != 0) UNRESOLVED(ret, "Cond attribute object init failed"); if ((pshared_ok > 0) && (scenar[i].pshared != 0)) { ret = pthread_condattr_setpshared(&ca, PTHREAD_PROCESS_SHARED); if (ret != 0) UNRESOLVED(ret, "Unable to set cond process-shared"); } #ifdef USE_ALTCLK if ((altclk_ok > 0) && (scenar[i].altclk != 0)) { ret = pthread_condattr_setclock(&ca, CLOCK_MONOTONIC); if (ret != 0) UNRESOLVED(ret, "Unable to set alternative (monotonic) clock for cond"); } #endif ret = pthread_mutex_init(&(data.mtx1), &ma); if (ret != 0) UNRESOLVED(ret, "Unable to init mutex 1"); ret = pthread_mutex_init(&(data.mtx2), &ma); if (ret != 0) UNRESOLVED(ret, "Unable to init mutex 2"); ret = pthread_cond_init(&(data.cnd), &ca); if (ret != 0) UNRESOLVED(ret, "Unable to initialize condvar"); data.boolcnd = 0; ret = pthread_mutexattr_gettype(&ma, &(data.type)); if (ret != 0) UNRESOLVED(ret, "Unable to get type from mutex attr"); #ifdef USE_ALTCLK ret = pthread_condattr_getclock(&ca, &(data.cid)); if (ret != 0) UNRESOLVED(ret, "Unable to get clock ID from cond attr"); #else data.cid = CLOCK_REALTIME; #endif data.started = 0; data.stopped = 0; /* Start the threads */ #if VERBOSE > 1 output("Initialization OK, starting threads\n"); #endif for (j = 0; j < NTHREADS; j++) { ret = pthread_create(&th[j], NULL, threaded, (void *)(long)(j & 1)); if (ret != 0) UNRESOLVED(ret, "Thread creation failed"); } /* Wait for the threads to be started */ do { ret = pthread_mutex_lock(&(data.mtx1)); if (ret != 0) UNRESOLVED(ret, "Unable to lock m1 in parent"); loc_started = data.started; ret = pthread_mutex_unlock(&(data.mtx1)); if (ret != 0) UNRESOLVED(ret, "Unable to unlock m1 in parent"); } while (loc_started < NTHREADS); /* Broadcast the condition until all threads are terminated */ data.boolcnd = 1; do { ret = pthread_cond_broadcast(&(data.cnd)); if (ret != 0) UNRESOLVED(ret, "Unable to broadcast cnd"); sched_yield(); ret = pthread_mutex_lock(&(data.mtx2)); if (ret != 0) UNRESOLVED(ret, "Unable to lock m2 in parent"); loc_stopped = data.stopped; ret = pthread_mutex_unlock(&(data.mtx2)); if (ret != 0) UNRESOLVED(ret, "Unable to unlock m2 in parent"); } while (loc_stopped < NTHREADS); /* Join the threads */ for (j = 0; j < NTHREADS; j++) { ret = pthread_join(th[j], NULL); if (ret != 0) UNRESOLVED(ret, "Thread join failed"); } #if VERBOSE > 1 output("Test passed for %s\n", scenar[i].descr); #endif /* Destroy data */ ret = pthread_cond_destroy(&(data.cnd)); if (ret != 0) UNRESOLVED(ret, "Cond destroy failed"); ret = pthread_mutex_destroy(&(data.mtx1)); if (ret != 0) UNRESOLVED(ret, "Mutex 1 destroy failed"); ret = pthread_mutex_destroy(&(data.mtx2)); if (ret != 0) UNRESOLVED(ret, "Mutex 2 destroy failed"); ret = pthread_condattr_destroy(&ca); if (ret != 0) UNRESOLVED(ret, "Cond attribute destroy failed"); ret = pthread_mutexattr_destroy(&ma); if (ret != 0) UNRESOLVED(ret, "Mutex attr destroy failed"); } /* Proceed to next case */ PASSED; }
int main(int argc, char * argv[]) { int ret, i, j; struct sigaction sa; pthread_mutexattr_t ma; pthread_condattr_t ca; clockid_t cid = CLOCK_REALTIME; testdata_t * td; testdata_t alternativ; int do_fork; long pshared, monotonic, cs, mf; pthread_t th[NTOT]; output_init(); pshared = sysconf(_SC_THREAD_PROCESS_SHARED); cs = sysconf(_SC_CLOCK_SELECTION); monotonic = sysconf(_SC_MONOTONIC_CLOCK); mf =sysconf(_SC_MAPPED_FILES); #if VERBOSE > 0 output("Test starting\n"); output("System abilities:\n"); output(" TPS : %li\n", pshared); output(" CS : %li\n", cs); output(" MON : %li\n", monotonic); output(" MF : %li\n", mf); if ((mf < 0) || (pshared < 0)) output("Process-shared attributes won't be tested\n"); if ((cs < 0) || (monotonic < 0)) output("Alternative clock won't be tested\n"); #endif /* We are not interested in testing the clock if we have no other clock available.. */ if (monotonic < 0) cs = -1; #ifndef USE_ALTCLK if (cs > 0) output("Implementation supports the MONOTONIC CLOCK but option is disabled in test.\n"); #endif /********** * Allocate space for the testdata structure */ if (mf < 0) { /* Cannot mmap a file, we use an alternative method */ td = &alternativ; pshared = -1; /* We won't do this testing anyway */ #if VERBOSE > 0 output("Testdata allocated in the process memory.\n"); #endif } else { /* We will place the test data in a mmaped file */ char filename[] = "/tmp/cond_timedwait_st1-XXXXXX"; size_t sz, ps; void * mmaped; int fd; char * tmp; /* We now create the temp files */ fd = mkstemp(filename); if (fd == -1) { UNRESOLVED(errno, "Temporary file could not be created"); } /* and make sure the file will be deleted when closed */ unlink(filename); #if VERBOSE > 1 output("Temp file created (%s).\n", filename); #endif ps = (size_t)sysconf(_SC_PAGESIZE); sz= ((sizeof(testdata_t) / ps) + 1) * ps; /* # pages needed to store the testdata */ tmp = calloc(1 , sz); if (tmp == NULL) { UNRESOLVED(errno, "Memory allocation failed"); } /* Write the data to the file. */ if (write (fd, tmp, sz) != (ssize_t) sz) { UNRESOLVED(sz, "Writting to the file failed"); } free(tmp); /* Now we can map the file in memory */ mmaped = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mmaped == MAP_FAILED) { UNRESOLVED(errno, "mmap failed"); } td = (testdata_t *) mmaped; /* Our datatest structure is now in shared memory */ #if VERBOSE > 1 output("Testdata allocated in shared memory (%ib).\n", sizeof(testdata_t)); #endif } /* Init the signal handler variable */ pBoolean = &(td->boolean); /* Init the structure */ for (i=0; i< NSCENAR ; i++) { #if VERBOSE > 1 output("[parent] Preparing attributes for: %s\n", scenarii[i].descr); #ifdef WITHOUT_XOPEN output("[parent] Mutex attributes DISABLED -> not used\n"); #endif #endif /* set / reset everything */ do_fork=0; ret = pthread_mutexattr_init(&ma); if (ret != 0) { UNRESOLVED(ret, "[parent] Unable to initialize the mutex attribute object"); } ret = pthread_condattr_init(&ca); if (ret != 0) { UNRESOLVED(ret, "[parent] Unable to initialize the cond attribute object"); } #ifndef WITHOUT_XOPEN /* Set the mutex type */ ret = pthread_mutexattr_settype(&ma, scenarii[i].m_type); if (ret != 0) { UNRESOLVED(ret, "[parent] Unable to set mutex type"); } #if VERBOSE > 1 output("[parent] Mutex type : %i\n", scenarii[i].m_type); #endif #endif /* Set the pshared attributes, if supported */ if ((pshared > 0) && (scenarii[i].mc_pshared != 0)) { ret = pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED); if (ret != 0) { UNRESOLVED(ret, "[parent] Unable to set the mutex process-shared"); } ret = pthread_condattr_setpshared(&ca, PTHREAD_PROCESS_SHARED); if (ret != 0) { UNRESOLVED(ret, "[parent] Unable to set the cond var process-shared"); } #if VERBOSE > 1 output("[parent] Mutex & cond are process-shared\n"); #endif } #if VERBOSE > 1 else { output("[parent] Mutex & cond are process-private\n"); } #endif /* Set the alternative clock, if supported */ #ifdef USE_ALTCLK if ((cs > 0) && (scenarii[i].c_clock != 0)) { ret = pthread_condattr_setclock(&ca, CLOCK_MONOTONIC); if (ret != 0) { UNRESOLVED(ret, "[parent] Unable to set the monotonic clock for the cond"); } #if VERBOSE > 1 output("[parent] Cond uses the Monotonic clock\n"); #endif } #if VERBOSE > 1 else { output("[parent] Cond uses the default clock\n"); } #endif ret = pthread_condattr_getclock(&ca, &cid); if (ret != 0) { UNRESOLVED(ret, "Unable to get clock from cond attr"); } #endif /* Tell whether the test will be across processes */ if ((pshared > 0) && (scenarii[i].fork != 0)) { do_fork = 1; #if VERBOSE > 1 output("[parent] Child will be a new process\n"); #endif } #if VERBOSE > 1 else { output("[parent] Child will be a new thread\n"); } #endif /* Initialize all the mutex and condvars which uses those attributes */ for (j=0; j < SCALABILITY_FACTOR * NCHILDREN; j++) { #define CD (td->cd[i+(j*NSCENAR)]) CD.pBool = &(td->boolean); CD.fork = do_fork; CD.cid = cid; /* initialize the condvar */ ret = pthread_cond_init(&(CD.cnd), &ca); if (ret != 0) { UNRESOLVED(ret, "[parent] Cond init failed"); } /* initialize the mutex */ ret = pthread_mutex_init(&(CD.mtx), &ma); if (ret != 0) { UNRESOLVED(ret, "[parent] Mutex init failed"); } #undef CD } ret = pthread_condattr_destroy(&ca); if (ret != 0) { UNRESOLVED(ret, "Failed to destroy the cond var attribute object"); } ret = pthread_mutexattr_destroy(&ma); if (ret != 0) { UNRESOLVED(ret, "Failed to destroy the mutex attribute object"); } } #if VERBOSE > 1 output("[parent] All condvars & mutex are ready\n"); #endif ret = pthread_attr_init(&ta); if (ret != 0) { UNRESOLVED(ret, "[parent] Failed to initialize a thread attribute object"); } ret = pthread_attr_setstacksize(&ta, sysconf(_SC_THREAD_STACK_MIN)); if (ret != 0) { UNRESOLVED(ret, "[parent] Failed to set thread stack size"); } sigemptyset (&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = sighdl; if ((ret = sigaction (SIGUSR1, &sa, NULL))) { UNRESOLVED(ret, "Unable to register signal handler"); } if ((ret = sigaction (SIGALRM, &sa, NULL))) { UNRESOLVED(ret, "Unable to register signal handler"); } #if VERBOSE > 1 output("[parent] Signal handler registered\n"); #endif for (i=0; i<NTOT; i++) { ret = pthread_create(&th[i], &ta, threaded_A, &(td->cd[i])); /* In case of failure we can exit; the child processes will die after a while */ if (ret != 0) { UNRESOLVED(ret, "[Parent] Failed to create a thread"); } #if VERBOSE > 1 if ((i % 10) == 0) output("[parent] %i threads created...\n", i+1); #endif } #if VERBOSE > 1 output("[parent] All %i threads are running...\n", NTOT); #endif for (i=0; i<NTOT; i++) { ret = pthread_join(th[i], NULL); if (ret != 0) { UNRESOLVED(ret, "[Parent] Failed to join a thread"); } } /* Destroy everything */ for (i=0; i< NTOT ; i++) { /* destroy the condvar */ ret = pthread_cond_destroy(&(td->cd[i].cnd)); if (ret != 0) { UNRESOLVED(ret, "[parent] Cond destroy failed"); } /* destroy the mutex */ ret = pthread_mutex_init(&(td->cd[i].mtx), &ma); if (ret != 0) { UNRESOLVED(ret, "[parent] Mutex destroy failed"); } } #if VERBOSE > 0 output("Test passed\n"); #endif PASSED; }