blob: 9a0b65fc3fa8511a7b4417e6b114963a0b6bee5f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <decaf/util/concurrent/Mutex.h>
#include <apr_errno.h>
#include <apr_time.h>
using namespace decaf;
using namespace decaf::util;
using namespace decaf::util::concurrent;
////////////////////////////////////////////////////////////////////////////////
Mutex::Mutex() {
apr_pool_create( &pool, NULL );
apr_thread_mutex_create( &mutex, APR_THREAD_MUTEX_NESTED, pool );
this->lock_owner = 0;
this->lock_count = 0;
}
////////////////////////////////////////////////////////////////////////////////
Mutex::~Mutex() {
// Unlock the mutex.
unlock();
apr_thread_mutex_destroy( mutex );
apr_pool_destroy( pool );
}
////////////////////////////////////////////////////////////////////////////////
void Mutex::lock() throw( lang::Exception ) {
unsigned long threadId = lang::Thread::getId();
if( threadId == lock_owner ) {
lock_count++;
} else {
apr_thread_mutex_lock( mutex );
lock_owner = threadId;
lock_count = 1;
}
}
////////////////////////////////////////////////////////////////////////////////
void Mutex::unlock() throw( lang::Exception ) {
if( lock_owner == 0 ) {
return;
}
if( !isLockOwner() ) {
throw lang::Exception(
__FILE__, __LINE__,
"Mutex::unlock - Failed, not Lock Owner!" );
}
lock_count--;
if(lock_count == 0) {
lock_owner = 0;
apr_thread_mutex_unlock( mutex );
}
}
////////////////////////////////////////////////////////////////////////////////
void Mutex::wait() throw( lang::Exception )
{
// Delegate to the timed version
wait( WAIT_INFINITE );
}
////////////////////////////////////////////////////////////////////////////////
void Mutex::wait( unsigned long millisecs )
throw( lang::Exception )
{
if( !isLockOwner() ) {
throw lang::Exception(
__FILE__, __LINE__,
"Mutex::wait - Failed, not Lock Owner!");
}
// Save the current owner as we are going to unlock and release for
// someone else to lock on potentially. When we come back and
// re-lock we want to restore to the state we were in before.
unsigned long lock_owner = this->lock_owner;
unsigned long lock_count = this->lock_count;
this->lock_owner = 0;
this->lock_count = 0;
// Create this threads wait event
apr_thread_cond_t* waitEvent = NULL;
apr_thread_cond_create( &waitEvent, pool );
// Store the event in the queue so that a notify can
// call it and wake up the thread.
eventQ.push_back( waitEvent );
if( millisecs != WAIT_INFINITE ) {
apr_interval_time_t wait = millisecs * 1000;
apr_thread_cond_timedwait( waitEvent, mutex, wait );
} else {
apr_thread_cond_wait( waitEvent, mutex );
}
// Be Sure that the event is now removed
eventQ.remove( waitEvent );
// Destroy our wait event now, the notify method will have removed it
// from the event queue.
apr_thread_cond_destroy( waitEvent );
// restore the owner
this->lock_owner = lock_owner;
this->lock_count = lock_count;
}
////////////////////////////////////////////////////////////////////////////////
void Mutex::notify() throw( lang::Exception )
{
if( !isLockOwner() ) {
throw lang::Exception(
__FILE__, __LINE__,
"Mutex::Notify - Failed, not Lock Owner!" );
}
if( !eventQ.empty() ) {
apr_thread_cond_t* event = eventQ.front();
eventQ.remove( event );
apr_thread_cond_signal( event );
}
}
////////////////////////////////////////////////////////////////////////////////
void Mutex::notifyAll() throw( lang::Exception )
{
if( !isLockOwner() ) {
throw lang::Exception(
__FILE__, __LINE__,
"Mutex::NotifyAll - Failed, not Lock Owner!" );
}
while( !eventQ.empty() ) {
apr_thread_cond_t* event = eventQ.front();
eventQ.remove( event );
apr_thread_cond_signal( event );
}
}