/** \file
 *
 *  Contains the Mutex, ThreadCondition, and MutexLocker class implementations.
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#include "Mutex.h"

#include <cstdio>
#include <cstring>

pthread_mutexattr_t Mutex::MutexAttr_;
bool Mutex::MutexAttrInitialized_( false );

Mutex::Mutex()
{
    if( !MutexAttrInitialized_ )
    {
        MutexAttrInitialized_ = true;
        pthread_mutexattr_init( &MutexAttr_ );
#if !defined(__APPLE_CC__) && !defined(__CYGWIN__)
        pthread_mutexattr_settype( &MutexAttr_, PTHREAD_MUTEX_ERRORCHECK_NP );
#endif
    }
    int type = -1;
    pthread_mutexattr_gettype( &MutexAttr_, &type );
    //printf( "Type of mutexattr is %d\n", type );
    pthread_mutex_init( &mutex_, &MutexAttr_ );
}

/// Lock the mutex.
int Mutex::lock()
{
    //printf( "Thread Locking mutex(0x%08zX)\n", (size_t)this );fflush(stdout);
    int errnum = pthread_mutex_lock( &mutex_ );
    if( errnum )
    {
        printf( "!!Thread locked mutex(0x%08zX) with code (%d) %s\n", ( size_t )this, errnum, strerror( errnum ) );
        fflush( stdout );
    }
    else
    {
        //printf( "Thread Locked mutex(0x%08zX)\n", (size_t)this );fflush(stdout);
    }
    return errnum;
}

/// Unlock the mutex
int Mutex::unlock()
{
    //printf( "Thread Unlocking mutex(0x%08zX)\n", (size_t)this );fflush(stdout);
    int errnum = pthread_mutex_unlock( &mutex_ );
    if( errnum )
    {
        printf( "!!Thread unlocked mutex(0x%08zX) with code (%d) %s\n", ( size_t )this, errnum, strerror( errnum ) );
    }
    else
    {
        //printf( "Thread Unlocked mutex(0x%08zX)\n", (size_t)this );fflush(stdout);
    }
    return errnum;
}

/// Returns true if mutex if sucessfully locked. Otherwise return false.
bool Mutex::tryLock()
{
    int errnum = pthread_mutex_trylock( &mutex_ );
    if( errnum )
    {
        return false;
    }
    return true;
}


ThreadCondition::ThreadCondition( Mutex& mutex )
    : mutex_( mutex )
{
    pthread_cond_init( &condition_, NULL );
}

int ThreadCondition::wait()
{
    return pthread_cond_wait( &condition_, &( mutex_.mutex_ ) );
}

int ThreadCondition::timedWait( const Timespan& waitFor )
{
    struct timespec ts;
    waitFor.toTimespec( &ts );
    return pthread_cond_timedwait( &condition_, &( mutex_.mutex_ ), &ts );
}

int ThreadCondition::signal()
{
    return pthread_cond_signal( &condition_ );
}

int ThreadCondition::broadcast()
{
    return pthread_cond_broadcast( &condition_ );
}

/// Constructor "creates" a lock on the mutex
MutexLocker::MutexLocker( Mutex& mutex )
    : mutex_( mutex )
{
    mutex_.lock();
}

/// Destructor "destroys" the lock on the mutex
MutexLocker::~MutexLocker()
{
    mutex_.unlock();
}
