pthread_dependency.c   [plain text]


#include "darwintest_defaults.h"
#include <darwintest_utils.h>
#include <pthread/dependency_private.h>

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

static struct job {
	pthread_dependency_t *req;
	useconds_t usleep;
	int done;
} job;

static void *
do_test(void *__unused arg)
{
	pthread_mutex_lock(&mutex);

	while (!job.done) {
		while (job.req == 0) {
			pthread_cond_wait(&cond, &mutex);
		}
		if (job.usleep) usleep(job.usleep);
		pthread_dependency_fulfill_np(job.req, job.req);
		job.req = NULL;
	}

	pthread_mutex_unlock(&mutex);
	return NULL;
}

static void
post_req(pthread_dependency_t *req, useconds_t delay, bool done)
{
	pthread_mutex_lock(&mutex);
	job.req = req;
	job.usleep = delay;
	job.done = done;
	pthread_cond_signal(&cond);
	pthread_mutex_unlock(&mutex);
}

T_DECL(dependency, "dependency", T_META_ALL_VALID_ARCHS(YES))
{
	pthread_dependency_t req;
	pthread_t pth;
	void *v;
	int ret;

	T_ASSERT_POSIX_ZERO(pthread_create(&pth, NULL, do_test, NULL), NULL);

	T_LOG("Waiting on a pdependency that takes some time");

	pthread_dependency_init_np(&req, pth, NULL);
	post_req(&req, 100000, false);
	v = pthread_dependency_wait_np(&req);
	T_EXPECT_EQ(v, &req, "pthread_dependency_wait worked");

	T_LOG("Waiting on a pdependency that is already fulfilled");

	pthread_dependency_init_np(&req, pth, NULL);
	post_req(&req, 0, false);
	usleep(100000);
	v = pthread_dependency_wait_np(&req);
	T_EXPECT_EQ(v, &req, "pthread_dependency_wait worked");

	T_LOG("Waiting on a fulfilled pdependency with the other thread exiting");

	pthread_dependency_init_np(&req, pth, NULL);
	post_req(&req, 0, true);
	ret = pthread_join(pth, NULL);
	T_EXPECT_POSIX_ZERO(ret, "pthread_join");

	v = pthread_dependency_wait_np(&req);
	T_EXPECT_EQ(v, &req, "pthread_dependency_wait worked");

	T_END;
}