#include "stdafx.h"
#include "Lock.h"

namespace util {

#ifdef WINDOWS
	// Default spin count. This is what the heap manager uses internally according to MSDN. We
	// typically have fairly short critical sections here, so this should work well for us as well.
	static const DWORD spinCount = 4000;

	Lock::Lock() {
		InitializeCriticalSectionAndSpinCount(&cs, spinCount);
	}

	Lock::~Lock() {
		DeleteCriticalSection(&cs);
	}

	Lock::L::L(Lock &l) : l(&l) {
		EnterCriticalSection(&l.cs);
	}

	Lock::L::L(Lock *l) : l(l) {
		if (l)
			EnterCriticalSection(&l->cs);
	}

	Lock::L::~L() {
		if (l)
			LeaveCriticalSection(&l->cs);
	}

	void Lock::lock() {
		EnterCriticalSection(&cs);
	}

	void Lock::unlock() {
		LeaveCriticalSection(&cs);
	}

#endif

#ifdef POSIX
	Lock::Lock() {
		pthread_mutexattr_t attr;
		pthread_mutexattr_init(&attr);
		pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
		pthread_mutex_init(&cs, &attr);
		pthread_mutexattr_destroy(&attr);
	}

	Lock::~Lock() {
		pthread_mutex_destroy(&cs);
	}

	Lock::L::L(Lock &l) : l(&l) {
		// According to the man pages, we do not need to consider EINTR from locking a mutex.
		pthread_mutex_lock(&l.cs);
	}

	Lock::L::L(Lock *l) : l(l) {
		// According to the man pages, we do not need to consider EINTR from locking a mutex.
		if (l)
			pthread_mutex_lock(&l->cs);
	}

	Lock::L::~L() {
		if (l)
			pthread_mutex_unlock(&l->cs);
	}

	void Lock::lock() {
		pthread_mutex_lock(&cs);
	}

	void Lock::unlock() {
		pthread_mutex_unlock(&cs);
	}

#endif

}
