#include <errno.h>
#include <libkern/OSAtomic.h>
+#include "darwintest_defaults.h"
+#include <darwintest_utils.h>
+
struct context {
pthread_cond_t cond;
pthread_mutex_t mutex;
+ pthread_cond_t ready_cond;
long waiters;
long count;
+ bool ready;
+ char _padding[7];
};
-void *wait_thread(void *ptr) {
- int res;
+
+static void *wait_thread(void *ptr) {
struct context *context = ptr;
- int i = 0;
- char *str;
+ // tell producer thread that we are ready
+ T_QUIET;
+ T_ASSERT_POSIX_ZERO(pthread_mutex_lock(&context->mutex), "pthread_mutex_lock");
+ context->ready = true;
+ T_QUIET;
+ T_ASSERT_POSIX_ZERO(pthread_cond_signal(&context->ready_cond), "pthread_cond_signal");
bool loop = true;
while (loop) {
- res = pthread_mutex_lock(&context->mutex);
- if (res) {
- fprintf(stderr, "[%ld] pthread_mutex_lock: %s\n", context->count, strerror(res));
- abort();
- }
-
+
if (context->count > 0) {
++context->waiters;
- res = pthread_cond_wait(&context->cond, &context->mutex);
- if (res) {
- fprintf(stderr, "[%ld] pthread_rwlock_unlock: %s\n", context->count, strerror(res));
- abort();
- }
+ T_QUIET;
+ T_ASSERT_POSIX_ZERO(pthread_cond_wait(&context->cond, &context->mutex), "[%ld] pthread_rwlock_unlock", context->count);
--context->waiters;
--context->count;
} else {
loop = false;
}
-
- res = pthread_mutex_unlock(&context->mutex);
- if (res) {
- fprintf(stderr, "[%ld] pthread_mutex_unlock: %s\n", context->count, strerror(res));
- abort();
- }
+
}
+ T_QUIET;
+ T_ASSERT_POSIX_ZERO(pthread_mutex_unlock(&context->mutex), "[%ld] pthread_mutex_unlock", context->count);
+
return NULL;
}
-int main(int argc, char *argv[])
+T_DECL(cond, "pthread_cond",
+ T_META_ALL_VALID_ARCHS(YES), T_META_TIMEOUT(120), T_META_CHECK_LEAKS(NO))
{
struct context context = {
.cond = PTHREAD_COND_INITIALIZER,
.mutex = PTHREAD_MUTEX_INITIALIZER,
+ .ready_cond = PTHREAD_COND_INITIALIZER,
.waiters = 0,
- .count = 500000,
+ .count = 50000 * dt_ncpu(),
+ .ready = false,
};
int i;
int res;
int threads = 2;
pthread_t p[threads];
for (i = 0; i < threads; ++i) {
- res = pthread_create(&p[i], NULL, wait_thread, &context);
- assert(res == 0);
+ T_QUIET;
+ T_ASSERT_POSIX_ZERO(pthread_mutex_lock(&context.mutex), "pthread_mutex_lock");
+
+ context.ready = false;
+
+ T_QUIET;
+ T_ASSERT_POSIX_ZERO(pthread_create(&p[i], NULL, wait_thread, &context), "pthread_create");
+
+ do {
+ // mutex will be dropped and allow consumer thread to acquire
+ T_QUIET;
+ T_ASSERT_POSIX_ZERO(pthread_cond_wait(&context.ready_cond, &context.mutex), "pthread_cond_wait");
+ } while (context.ready == false);
+
+ T_QUIET;
+ T_ASSERT_POSIX_ZERO(pthread_mutex_unlock(&context.mutex), "pthread_mutex_lock");
+
+ T_LOG("Thread %d ready.", i);
}
+ T_LOG("All threads ready.");
+
long half = context.count / 2;
bool loop = true;
while (loop) {
- res = pthread_mutex_lock(&context.mutex);
- if (res) {
- fprintf(stderr, "[%ld] pthread_mutex_lock: %s\n", context.count, strerror(res));
- abort();
- }
+ T_QUIET;
+ T_ASSERT_POSIX_ZERO(pthread_mutex_lock(&context.mutex), "[%ld] pthread_mutex_lock", context.count);
if (context.waiters) {
char *str;
if (context.count > half) {
str = "pthread_cond_signal";
res = pthread_cond_signal(&context.cond);
}
- if (res != 0) {
- fprintf(stderr, "[%ld] %s: %s\n", context.count, str, strerror(res));
- abort();
- }
+ T_QUIET;
+ T_ASSERT_POSIX_ZERO(res, "[%ld] %s", context.count, str);
}
if (context.count <= 0) {
loop = false;
+ T_PASS("Completed stres test successfully.");
}
-
- res = pthread_mutex_unlock(&context.mutex);
- if (res) {
- fprintf(stderr, "[%ld] pthread_mutex_unlock: %s\n", context.count, strerror(res));
- abort();
- }
+
+ T_QUIET;
+ T_ASSERT_POSIX_ZERO(pthread_mutex_unlock(&context.mutex),
+ "[%ld] pthread_mutex_unlock", context.count);
}
-
-
+
for (i = 0; i < threads; ++i) {
- res = pthread_join(p[i], NULL);
- assert(res == 0);
+ T_ASSERT_POSIX_ZERO(pthread_join(p[i], NULL), NULL);
}
-
- return 0;
}