cond_stress.c   [plain text]


#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>

typedef struct _ConditionLock {
	pthread_mutex_t _mutex;
	pthread_cond_t _condition;
	int _owner;
	int _last_owner;
	volatile int _state;
} ConditionLock;

typedef struct _log {
	int thread;
	const char * op;
} log_t;

static int initConditionLockWithCondition(ConditionLock *, int);
static int lockConditionLock(ConditionLock *, int);
static int lockConditionLockWhenCondition(ConditionLock *, int, int);
static int unlockConditionLockWithCondition(ConditionLock *, int, int);
static int destroyConditionLock(ConditionLock *);
static void * testThread(void *);
static void log(int, const char *, ConditionLock *);

static ConditionLock * lock;
static volatile int count    = 0;
static volatile int logcount = 0;
static log_t * tracelog;
#define TRACE_MAX_COUNT (4 * 1024 * 1024)
long iterations = 999000L;

static void
log(int self, const char * op, ConditionLock * cl)
{
	tracelog[logcount].thread = self;
	tracelog[logcount++].op = op;
	if (logcount == TRACE_MAX_COUNT)
		logcount = 0;
}

int
main(int argc, char * argv[])
{
	pthread_t thread[4];

	lock = (ConditionLock *)calloc(sizeof(ConditionLock), 1);
	if (initConditionLockWithCondition(lock, 0))
		abort();
	tracelog = (log_t *)calloc(sizeof(log_t), TRACE_MAX_COUNT);

	pthread_create(&thread[0], NULL, testThread, (void *)1);
	pthread_create(&thread[1], NULL, testThread, (void *)2);
	pthread_create(&thread[2], NULL, testThread, (void *)3);
	pthread_create(&thread[3], NULL, testThread, (void *)4);

	while (iterations > -100) {
		if (lockConditionLock(lock, 0))
			abort();
		count = 1;
		iterations--;
		if (unlockConditionLockWithCondition(lock, 1, 0))
			abort();
	}

	destroyConditionLock(lock);
	free(lock);
	free(tracelog);

	return 0;
}

static void *
testThread(void * arg)
{
	int self = (int)arg;
	while (iterations > 0) {
		if (lockConditionLockWhenCondition(lock, 1, self))
			abort();
		count = 0;
		if (unlockConditionLockWithCondition(lock, 0, self))
			abort();
	}
	return arg;
}

static int
initConditionLockWithCondition(ConditionLock * cl, int condition)
{
	int rc;

	if ((rc = pthread_mutex_init(&cl->_mutex, NULL))) {
		fprintf(stderr, "pthread_mutex_init returned %d, %s\n", rc, strerror(rc));
		return 1;
	}

	if ((rc = pthread_cond_init(&cl->_condition, NULL))) {
		fprintf(stderr, "pthread_cond_init returned %d, %s\n", rc, strerror(rc));
		return 1;
	}

	cl->_state = condition;

	return 0;
}

static int
destroyConditionLock(ConditionLock * cl)
{
	int rc;

	if ((rc = pthread_mutex_destroy(&cl->_mutex))) {
		fprintf(stderr, "pthread_mutex_destroy returned %d, %s\n", rc, strerror(rc));
		return 1;
	}
	if ((rc = pthread_cond_destroy(&cl->_condition))) {
		fprintf(stderr, "pthread_cond_destroy returned %d, %s\n", rc, strerror(rc));
		return 1;
	}
	return 0;
}

static int
lockConditionLock(ConditionLock * cl, int self)
{
	int rc;

	if ((rc = pthread_mutex_lock(&cl->_mutex))) {
		fprintf(stderr, "pthread_mutex_lock() returned %d, %s\n", rc, strerror(rc));
		return 1;
	}
	cl->_owner = self;
	log(self, "Got lock", cl);
	return 0;
}

static int
lockConditionLockWhenCondition(ConditionLock * cl, int condition, int self)
{
	int rc;

	if ((rc = pthread_mutex_lock(&cl->_mutex))) {
		fprintf(stderr, "pthread_mutex_lock() returned %d, %s\n", rc, strerror(rc));
		return 1;
	}
	log(self, "Waiting for condition", cl);
	while (cl->_state != condition) {
		if ((rc = pthread_cond_wait(&cl->_condition, &cl->_mutex))) {
			fprintf(stderr, "pthread_cond_wait() returned %d, %s\n", rc, strerror(rc));
			return 1;
		}
		if (cl->_state != condition) {
			log(self, "condition lock wakeup with wrong condition", cl);
		}
	}
	cl->_owner = self;
	log(self, "Got condition", cl);
	return 0;
}

static int
unlockConditionLockWithCondition(ConditionLock * cl, int condition, int self)
{
	int rc;

	if (cl->_owner != self) {
		fprintf(stderr, "%d: trying to unlock a lock owned by %d\n", self, cl->_owner);
		abort();
	}
	log(self, condition ? "Unlocking with condition set" : "Unlocking with condition cleared", cl);
	cl->_last_owner = cl->_owner;
	cl->_owner      = 0;
	cl->_state = condition;
	if ((rc = pthread_cond_signal(&cl->_condition))) {
		fprintf(stderr, "pthread_cond_broadcast() returned %d, %s\n", rc, strerror(rc));
		return 1;
	}
	log(self, "Sent broadcast", cl);
	if ((rc = pthread_mutex_unlock(&cl->_mutex))) {
		fprintf(stderr, "pthread_mutex_unlock() returned %d, %s\n", rc, strerror(rc));
		return 1;
	}
	return 0;
}