/*
	PIP - Platform Independent Primitives
	PIMutex, PIMutexLocker
	Ivan Pelipenko peri4ko@yandex.ru, Stephan Fomenko, Andrey Bychkov work.a.b@yandex.ru

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/** \class PIMutex
 * \brief Mutex
 * \details
 * \section PIMutex_sec0 Synopsis
 * %PIMutex provides synchronization blocks between several threads.
 * Using mutex guarantees execution of some code only one of threads.
 * Mutex contains logic state and functions to change it: \a lock(),
 * \a unlock() and \a tryLock().
 *
 * \section PIMutex_sec1 Usage
 * Block of code that should to be executed only one thread simultaniously
 * should to be started with \a lock() and ended with \a unlock().
 * \snippet pimutex.cpp main
 * "mutex" in this example is one for all threads.
 *
 * */

#include "pimutex.h"
#include "piincludes_p.h"
#ifdef WINDOWS
#  include <synchapi.h>
#else
#  include <pthread.h>
#endif



PRIVATE_DEFINITION_START(PIMutex)
#ifdef WINDOWS
	CRITICAL_SECTION
#else
	pthread_mutex_t
#endif
					mutex;
PRIVATE_DEFINITION_END(PIMutex)


PIMutex::PIMutex() {
	init();
}


PIMutex::~PIMutex() {
	destroy();
}


void PIMutex::lock() {
#ifdef WINDOWS
	EnterCriticalSection(&(PRIVATE->mutex));
#else
	pthread_mutex_lock(&(PRIVATE->mutex));
#endif
}


void PIMutex::unlock() {
#ifdef WINDOWS
	LeaveCriticalSection(&(PRIVATE->mutex));
#else
	pthread_mutex_unlock(&(PRIVATE->mutex));
#endif
}


bool PIMutex::tryLock() {
	bool ret =
#ifdef WINDOWS
			(TryEnterCriticalSection(&(PRIVATE->mutex)) != 0);
#else
			(pthread_mutex_trylock(&(PRIVATE->mutex)) == 0);
#endif
	return ret;
}


void *  PIMutex::handle() {
	return (void*)&(PRIVATE->mutex);
}


void PIMutex::init() {
#ifdef WINDOWS
	InitializeCriticalSection(&(PRIVATE->mutex));
#else
	pthread_mutexattr_t attr;
	memset(&attr, 0, sizeof(attr));
	pthread_mutexattr_init(&attr);
	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
	memset(&(PRIVATE->mutex), 0, sizeof(PRIVATE->mutex));
	pthread_mutex_init(&(PRIVATE->mutex), &attr);
	pthread_mutexattr_destroy(&attr);
#endif
}


void PIMutex::destroy() {
#ifdef WINDOWS
	DeleteCriticalSection(&(PRIVATE->mutex));
#else
	pthread_mutex_destroy(&(PRIVATE->mutex));
#endif
}
