/////////////////////////////////////////////////////////////////////////////////////
// This file is devoted to providing (potentially cross-platform) safe and easy
// mechanism to use synchronization primitives OS presents to the programmer
//
// CONTAINS implementation of the following synchronization primitives:
//  Critical Section
//  Mutex
//  Event (in the sense of Windows)
//
// The paradigm is to create primitives (like critical section) as objects that auto-
// construct and destruct the underlying OS-specific structures, and if pair operations
// (lock/unlock) need to be performed, then use other primitives (auto-lock) that need
// only be mentioned once in the code.
// 
// No operation must be smeared in the code -
// it must be atomic. E.g. when you want to lock something for some time, you should
// create an auto-lock object that will lock this something in constructor and unlock it
// (without your intervention) in the destructor. This had an additional advantage
// of unlocking your primitive when a C++ exception is thrown
//////////////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "Log.h"
#include "Synchronize.h"

namespace util
{

// creates a critical section primitive
CCritSection::CCritSection()
{
	InitializeCriticalSection (&csThis);
}

// destructs the critical section primitive
CCritSection::~CCritSection()
{
 	DeleteCriticalSection (&csThis);
}

// locks the critical section primitive
void CCritSection::Lock ()
{
	EnterCriticalSection(&csThis);
}

// unlocks the critical section primitive
void CCritSection::Unlock ()
{
	LeaveCriticalSection(&csThis);
}

// copying of critical section is not what we'd like to have in some cases, so disable it
// by declaring the constructor private
CCritSection::CCritSection (const CCritSection &)
{// we don't have the right to copy CritSection objects
	InitializeCriticalSection(&csThis);
}

CEvent::CEvent(DWORD dwFlags)
{
	hEvent = CreateEvent (NULL, dwFlags&nFlagManualReset? TRUE: FALSE, FALSE, NULL);
	if (!hEvent)
		Log ("*ERROR* Cannot create Event object. %s", FormatWinError(GetLastError()).c_str());
}


//////////////////////////////////////////////////////////////////////////////
// CMutex::CMutex
//
// TAKES   :
//     szName  - name (recognized inter-process) of the mutex
//     dwFlags - may have nFlagAllowAccessAll flag, in which case the mutex 
//               will be created with "Allow for Everyone" access rights
// RETURNS :     
//     
// ASSUMES :
//     
// NOTES   :
//     Creates (named) mutex possibly with given security rights
//////////////////////////////////////////////////////////////////////////////
CMutex::CMutex(const char* szName, DWORD dwFlags)
{
	LPSECURITY_ATTRIBUTES pSA = NULL; // pointer to the SD to pass to CreateEvent()
	SECURITY_ATTRIBUTES SA;
	SECURITY_DESCRIPTOR SD;
	if (dwFlags & nFlagAllowAccessAll)
	{
		InitializeSecurityDescriptor (&SD, SECURITY_DESCRIPTOR_REVISION);
		// Add a null DACL to the security descriptor. 
		SetSecurityDescriptorDacl (&SD, TRUE, (PACL) NULL, FALSE);
		SA.nLength = sizeof (SA);
		SA.lpSecurityDescriptor = &SD;
		SA.bInheritHandle = FALSE;
		pSA = &SA;
	}

	hMutex = CreateMutex(pSA, 0, szName);
}

CMutex::~CMutex()
{
	CloseHandle(hMutex);
} 

CMutex::CMutex(const CMutex&)
{
	// no rights to do that...
	hMutex = 0;
}

void CMutex::Lock()
{
	WaitForSingleObject(hMutex, INFINITE);
}

void CMutex::Unlock()
{
	ReleaseMutex(hMutex);
}

}
