//===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
//
// Purpose: Thread tools
//
// $Workfile: $
// $NoKeywords: $
//===========================================================================//

#include "tier0/threadtools.h"

#define INIT_SEM_COUNT 0
#define MAX_SEM_COUNT 1

int CThreadFastMutex::Lock(void)
{
	DWORD threadId = GetCurrentThreadId();
	LONG result = ThreadInterlockedCompareExchange((volatile LONG*)&m_lAddend, 0, 1);

	if (result)
	{
		if (m_nOwnerID == threadId)
		{
			result = m_nDepth + 1;
			m_nDepth = result;

			return result;
		}

		LONG cycle = 1;
		LONG64 delay;

		while (true)
		{
			delay = (10 * cycle);
			if (delay)
			{
				do
				{
					ThreadPause();
					--delay;
				} while (delay);
			}

			result = ThreadInterlockedCompareExchange((volatile LONG*)&m_lAddend, 0, 1);

			if (result)
				break;

			if (++cycle > 5)
			{
				if (_InterlockedIncrement((volatile LONG*)&m_lAddend) != 1)
				{
					if (!m_hSemaphore)
					{
						HANDLE hSemaphore = CreateSemaphoreA(
							NULL, INIT_SEM_COUNT, MAX_SEM_COUNT, NULL);

						if (ThreadInterlockedCompareExchange64(
							(volatile LONG64*)&m_hSemaphore, NULL, (LONG64)hSemaphore))
							CloseHandle(hSemaphore);
					}
					WaitForSingleObject(m_hSemaphore, INFINITE);
				}
				m_nOwnerID = threadId;
				m_nDepth = 1;

				return m_nDepth;
			}
		}
	}

	m_nDepth = 1;
	m_nOwnerID = threadId;

	return result;
}

int CThreadFastMutex::Unlock()
{
	LONG result; // eax
	HANDLE SemaphoreA; // rcx

	result = m_nDepth - 1;
	m_nDepth = result;

	if (!result)
	{
		m_nOwnerID = 0;
		result = _InterlockedExchangeAdd((volatile LONG*)&m_lAddend, 0xFFFFFFFF);

		if (result != 1)
		{
			if (!m_hSemaphore)
			{
				SemaphoreA = CreateSemaphoreA(NULL, INIT_SEM_COUNT, MAX_SEM_COUNT, NULL);

				if (ThreadInterlockedAssignIf64(
					(volatile LONG64*)&m_hSemaphore, NULL, (LONG64)SemaphoreA))
					CloseHandle(SemaphoreA);
			}
			return ReleaseSemaphore(m_hSemaphore, 1, NULL);
		}
	}
	return result;
}