#include "ReadWriteLock.hpp"

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

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

	bool ReadWriteLock::readLock() {
		bool result;

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

	bool ReadWriteLock::writeLock() {
		bool result;

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

	bool ReadWriteLock::upgradeToWriteLock() {
		bool result = false;

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

	bool ReadWriteLock::downgradeToReadLock() {
		bool result = false;

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

	bool ReadWriteLock::unLock() {
		bool result = false;

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