/*
#  $Id$
# -----------------------------------------------------------------------------
#  The part of 'VideoNEXT MediaClient SDK'
# -----------------------------------------------------------------------------
#  Author: Petrov Maxim, 03/04/2009
#  Edited by:
#  QA by:
#  Copyright: videoNEXT LLC
# -----------------------------------------------------------------------------
*/
#include <assert.h>
#include "Mutex.h"

namespace videonext { namespace media {

Mutex::Mutex()
{
    init();
}
   
/*virtual*/ Mutex::~Mutex()
{
    destroy();
}
    
   
void Mutex::init()
{
#ifdef WIN32
    mutex = new CRITICAL_SECTION;
    InitializeCriticalSection(mutex); 
#else
    int ret;
    mutex = new pthread_mutex_t;
    pthread_mutexattr_t attr;
    ret = pthread_mutexattr_init(&attr);
    assert(ret != -1);
    ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    assert(ret != -1);
    ret = pthread_mutex_init(mutex, &attr);
    assert(ret != -1);
#endif
}
    
void Mutex::destroy()
{
#ifdef WIN32
    DeleteCriticalSection(mutex); 
    delete mutex;
#else
    pthread_mutex_destroy(mutex);
    delete mutex;
#endif
}
    
void Mutex::lock()
{ 
#ifdef WIN32
    EnterCriticalSection(mutex);
#else
    pthread_mutex_lock(mutex);
#endif
}
    
void Mutex::unlock()
{
#ifdef WIN32
    LeaveCriticalSection(mutex);
#else
    pthread_mutex_unlock(mutex);
#endif
}
    

//////////////////////////////////////
Cond::Cond() 
 : Mutex() 
{
#ifdef WIN32
    // Create an auto-reset event.
    event = CreateEvent (NULL,  // no security
                         FALSE, // auto-reset event
                         FALSE, // non-signaled initially
                         NULL); // unnamed
#else
    int ret = pthread_cond_init(&cond, NULL);
    assert(ret != -1);
#endif
}
    
/*virtual*/ Cond::~Cond()
{
#ifdef WIN32
    CloseHandle(event);
#else
    pthread_cond_destroy(&cond);
#endif
}
    
void Cond::signal()
{
#ifdef WIN32
    SetEvent(event);
#else
    pthread_cond_signal(&cond);
#endif
}
    
void Cond::wait()
{
#ifdef WIN32
    LeaveCriticalSection(mutex);
    WaitForSingleObject(event,
                        INFINITE); // Wait "forever"

    // Reacquire the mutex before returning.
    EnterCriticalSection (mutex);
    ResetEvent(event);
#else
    pthread_cond_wait(&cond, mutex);
#endif    
}


//////////////////////
MutexGuard::MutexGuard(Mutex &mutex) 
  : mutex_(mutex), locked_(false)
{
    acquire();
}

MutexGuard::~MutexGuard()
{
    release();
}


void MutexGuard::acquire()
{
    locked_ = true;
    mutex_.lock();
}

void MutexGuard::release()
{
    if (locked_)
    {
        locked_ = false;
        mutex_.unlock();
    }
}

}}
