#include "ReadWriteLock.hpp"

namespace nbody {
	ReadWriteLock::ReadWriteLock() {
		pthread_mutex_init(&this->mutex, NULL);
		pthread_rwlock_init(&this->rwlock, NULL);
		this->owner = NULL;
	}

	ReadWriteLock::~ReadWriteLock() {
		pthread_mutex_destroy(&this->mutex);
		pthread_rwlock_destroy(&this->rwlock);
	}

	bool ReadWriteLock::readLock(pthread_t* myThread) {
		bool result;

		pthread_mutex_lock(&this->mutex);
		result = (pthread_rwlock_tryrdlock(&this->rwlock) == 0);
		if (result) {
			this->owner = myThread;
		}
		pthread_mutex_unlock(&this->mutex);
		return result;
	}

	bool ReadWriteLock::writeLock(pthread_t* myThread) {
		bool result;

		pthread_mutex_lock(&this->mutex);
		result = (pthread_rwlock_trywrlock(&this->rwlock) == 0);
		if (result) {
			this->owner = myThread;
		}
		pthread_mutex_unlock(&this->mutex);
		return result;
	}

	bool ReadWriteLock::upgradeToWriteLock(pthread_t* myThread) {
		bool result = false;

		pthread_mutex_lock(&this->mutex);
		if (this->owner == myThread) {
			pthread_rwlock_unlock(&this->rwlock);
			pthread_rwlock_wrlock(&this->rwlock);
			result = true;
		}
		pthread_mutex_unlock(&this->mutex);
		return result;
	}

	bool ReadWriteLock::downgradeToReadLock(pthread_t* myThread) {
		bool result = false;

		pthread_mutex_lock(&this->mutex);
		if (this->owner == myThread) {
			pthread_rwlock_unlock(&this->rwlock);
			pthread_rwlock_rdlock(&this->rwlock);
			result = true;
		}
		pthread_mutex_unlock(&this->mutex);
		return result;
	}

	bool ReadWriteLock::unLock(pthread_t* myThread) {
		bool result = false;

		pthread_mutex_lock(&this->mutex);
		if (this->owner == myThread) {
			pthread_rwlock_unlock(&this->rwlock);
			this->owner = NULL;
			result = true;
		}
		pthread_mutex_unlock(&this->mutex);
		return result;
	}
}
