| /* |
| * 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 <activemq/concurrent/Mutex.h> |
| |
| using namespace activemq; |
| using namespace activemq::concurrent; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| Mutex::Mutex() |
| { |
| #ifdef HAVE_PTHREAD_H |
| pthread_mutexattr_t attr; |
| pthread_mutexattr_init( &attr ); |
| pthread_mutex_init( &mutex, &attr ); |
| pthread_mutexattr_destroy( &attr ); |
| #else |
| InitializeCriticalSection( &mutex ); |
| #endif |
| |
| lock_owner = 0; |
| lock_count = 0; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| Mutex::~Mutex() |
| { |
| // Unlock the mutex. |
| unlock(); |
| |
| #ifdef HAVE_PTHREAD_H |
| pthread_mutex_destroy( &mutex ); |
| #else |
| DeleteCriticalSection( &mutex ); |
| #endif |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| void Mutex::lock() throw( exceptions::ActiveMQException ) |
| { |
| unsigned long threadId = Thread::getId(); |
| |
| if( threadId == lock_owner ) { |
| lock_count++; |
| } else { |
| |
| #ifdef HAVE_PTHREAD_H |
| pthread_mutex_lock( &mutex ); |
| #else |
| EnterCriticalSection( &mutex ); |
| #endif |
| |
| lock_owner = threadId; |
| lock_count = 1; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| void Mutex::unlock() throw( exceptions::ActiveMQException ) |
| { |
| if( lock_owner == 0 ) { |
| return; |
| } |
| |
| if( !isLockOwner() ) { |
| throw exceptions::ActiveMQException( |
| __FILE__, __LINE__, |
| "Mutex::unlock - Failed, not Lock Owner!" ); |
| } |
| |
| lock_count--; |
| |
| if(lock_count == 0) { |
| lock_owner = 0; |
| |
| #ifdef HAVE_PTHREAD_H |
| pthread_mutex_unlock( &mutex ); |
| #else |
| LeaveCriticalSection( &mutex ); |
| #endif |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| void Mutex::wait() throw( exceptions::ActiveMQException ) |
| { |
| // Delegate to the timed version |
| wait( WAIT_INFINITE ); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| void Mutex::wait( unsigned long millisecs ) |
| throw( exceptions::ActiveMQException ) |
| { |
| if( !isLockOwner() ) { |
| throw exceptions::ActiveMQException( |
| __FILE__, __LINE__, |
| "Mutex::wait - Failed, not Lock Owner!"); |
| } |
| |
| // Save the current owner and Lock count 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; |
| int lock_count = this->lock_count; |
| |
| this->lock_count = 0; |
| this->lock_owner = 0; |
| |
| #ifdef HAVE_PTHREAD_H |
| |
| // Create this threads wait event |
| pthread_cond_t waitEvent; |
| pthread_cond_init( &waitEvent, NULL ); |
| |
| // Store the event in the queue so that a notify can |
| // call it and wake up the thread. |
| eventQ.push_back( &waitEvent ); |
| |
| int returnValue = 0; |
| if( millisecs != WAIT_INFINITE ) { |
| timeval now = {0,0}; |
| gettimeofday( &now, NULL ); |
| |
| timespec wait = {0,0}; |
| wait.tv_sec = now.tv_sec + (millisecs / 1000); |
| wait.tv_nsec = (now.tv_usec * 1000) + ((millisecs % 1000) * 1000000); |
| |
| if( wait.tv_nsec > 1000000000 ) { |
| wait.tv_sec++; |
| wait.tv_nsec -= 1000000000; |
| } |
| |
| returnValue = pthread_cond_timedwait( &waitEvent, &mutex, &wait ); |
| } else { |
| returnValue = pthread_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. |
| pthread_cond_destroy( &waitEvent ); |
| |
| #else // !defined(HAVE_PTHREAD_H) |
| |
| // Create the event to wait on |
| HANDLE waitEvent = CreateEvent( NULL, false, false, NULL ); |
| |
| if( waitEvent == NULL ) { |
| throw exceptions::ActiveMQException( |
| __FILE__, __LINE__, |
| "Mutex::wait - Failed Creating Event." ); |
| } |
| |
| eventQ.push_back( waitEvent ); |
| |
| // Release the Lock |
| LeaveCriticalSection( &mutex ); |
| |
| // Wait for a signal |
| if( WaitForSingleObject( waitEvent, millisecs ) != WAIT_OBJECT_0 && millisecs == WAIT_INFINITE ) { |
| throw exceptions::ActiveMQException( |
| __FILE__, __LINE__, |
| "Mutex::wait - Infinite wait aborted for unknown reason." ); |
| } |
| |
| // Reaquire the Lock |
| EnterCriticalSection( &mutex ); |
| |
| // Remove the event no matter what |
| eventQ.remove( waitEvent ); |
| |
| // Clean up the event, the notif methods will have |
| // already poped it from the queue. |
| CloseHandle( waitEvent ); |
| |
| #endif // !defined(HAVE_PTHREAD_H) |
| |
| // restore the owner |
| this->lock_owner = lock_owner; |
| this->lock_count = lock_count; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| void Mutex::notify() throw( exceptions::ActiveMQException ) |
| { |
| if( !isLockOwner() ) { |
| throw exceptions::ActiveMQException( |
| __FILE__, __LINE__, |
| "Mutex::Notify - Failed, not Lock Owner!" ); |
| } |
| |
| if( !eventQ.empty() ) { |
| #ifdef HAVE_PTHREAD_H |
| pthread_cond_t* event = eventQ.front(); |
| eventQ.remove( event ); |
| pthread_cond_signal( event ); |
| #else |
| HANDLE event = eventQ.front(); |
| eventQ.remove( event ); |
| SetEvent( event ); |
| #endif |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| void Mutex::notifyAll() throw( exceptions::ActiveMQException ) |
| { |
| if( !isLockOwner() ) { |
| throw exceptions::ActiveMQException( |
| __FILE__, __LINE__, |
| "Mutex::NotifyAll - Failed, not Lock Owner!" ); |
| } |
| |
| |
| while( !eventQ.empty() ) { |
| #ifdef HAVE_PTHREAD_H |
| pthread_cond_t* event = eventQ.front(); |
| eventQ.remove( event ); |
| pthread_cond_signal( event ); |
| #else |
| HANDLE event = eventQ.front(); |
| eventQ.remove( event ); |
| SetEvent( event ); |
| #endif |
| } |
| } |
| |