You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							507 lines
						
					
					
						
							9.8 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							507 lines
						
					
					
						
							9.8 KiB
						
					
					
				
								// -*- C++ -*-
							 | 
						|
								//  Copyright (C) 2009-2010, Vaclav Haisman. All rights reserved.
							 | 
						|
								//
							 | 
						|
								//  Redistribution and use in source and binary forms, with or without modifica-
							 | 
						|
								//  tion, are permitted provided that the following conditions are met:
							 | 
						|
								//
							 | 
						|
								//  1. Redistributions of  source code must  retain the above copyright  notice,
							 | 
						|
								//     this list of conditions and the following disclaimer.
							 | 
						|
								//
							 | 
						|
								//  2. Redistributions in binary form must reproduce the above copyright notice,
							 | 
						|
								//     this list of conditions and the following disclaimer in the documentation
							 | 
						|
								//     and/or other materials provided with the distribution.
							 | 
						|
								//
							 | 
						|
								//  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
							 | 
						|
								//  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
							 | 
						|
								//  FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
							 | 
						|
								//  APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
							 | 
						|
								//  INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
							 | 
						|
								//  DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
							 | 
						|
								//  OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
							 | 
						|
								//  ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
							 | 
						|
								//  (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
							 | 
						|
								//  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
							 | 
						|
								
							 | 
						|
								//! @file
							 | 
						|
								//! This file contains implementations of synchronization
							 | 
						|
								//! primitives using the POSIX threads. It does not contain any
							 | 
						|
								//! include guards because it is only a fragment to be included by
							 | 
						|
								//! syncprims.h.
							 | 
						|
								
							 | 
						|
								#include "log4cplus/thread/threads.h"
							 | 
						|
								#include <limits>
							 | 
						|
								#include <algorithm>
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								namespace log4cplus { namespace thread { namespace impl {
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								struct PthreadMutexAttr
							 | 
						|
								{
							 | 
						|
								    PthreadMutexAttr ()
							 | 
						|
								    {
							 | 
						|
								        int ret = pthread_mutexattr_init (&attr);
							 | 
						|
								        if (ret != 0)
							 | 
						|
								            LOG4CPLUS_THROW_RTE ("PthreadMutexAttr::PthreadMutexAttr");
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    ~PthreadMutexAttr ()
							 | 
						|
								    {
							 | 
						|
								        try
							 | 
						|
								        {
							 | 
						|
								            int ret = pthread_mutexattr_destroy (&attr);
							 | 
						|
								            if (ret != 0)
							 | 
						|
								                LOG4CPLUS_THROW_RTE ("PthreadMutexAttr::~PthreadMutexAttr");
							 | 
						|
								        }
							 | 
						|
								        catch (...)
							 | 
						|
								        { }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    void
							 | 
						|
								    set_type (log4cplus::thread::Mutex::Type t)
							 | 
						|
								    {
							 | 
						|
								        int mutex_type;
							 | 
						|
								        switch (t)
							 | 
						|
								        {
							 | 
						|
								        case log4cplus::thread::Mutex::RECURSIVE:
							 | 
						|
								            mutex_type = PTHREAD_MUTEX_RECURSIVE;
							 | 
						|
								            break;
							 | 
						|
								
							 | 
						|
								        default:
							 | 
						|
								            mutex_type = PTHREAD_MUTEX_DEFAULT;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        int ret = pthread_mutexattr_settype (&attr, mutex_type);
							 | 
						|
								        if (ret != 0)
							 | 
						|
								            LOG4CPLUS_THROW_RTE ("PthreadMutexAttr::set_type");
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    pthread_mutexattr_t attr;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								//
							 | 
						|
								//
							 | 
						|
								//
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								Mutex::Mutex (log4cplus::thread::Mutex::Type t)
							 | 
						|
								{
							 | 
						|
								    PthreadMutexAttr attr;
							 | 
						|
								    attr.set_type (t);
							 | 
						|
								
							 | 
						|
								    int ret = pthread_mutex_init (&mtx, &attr.attr);
							 | 
						|
								    if (ret != 0)
							 | 
						|
								        LOG4CPLUS_THROW_RTE ("Mutex::Mutex");
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								Mutex::~Mutex ()
							 | 
						|
								{
							 | 
						|
								    try
							 | 
						|
								    {
							 | 
						|
								        int ret = pthread_mutex_destroy (&mtx);
							 | 
						|
								        if (ret != 0)
							 | 
						|
								            LOG4CPLUS_THROW_RTE ("Mutex::~Mutex");
							 | 
						|
								    }
							 | 
						|
								    catch (...)
							 | 
						|
								    { }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								void
							 | 
						|
								Mutex::lock () const
							 | 
						|
								{
							 | 
						|
								    int ret = pthread_mutex_lock (&mtx);
							 | 
						|
								    if (ret != 0)
							 | 
						|
								        LOG4CPLUS_THROW_RTE ("Mutex::lock");
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								void
							 | 
						|
								Mutex::unlock () const
							 | 
						|
								{
							 | 
						|
								    int ret = pthread_mutex_unlock (&mtx);
							 | 
						|
								    if (ret != 0)
							 | 
						|
								        LOG4CPLUS_THROW_RTE ("Mutex::unlock");
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								//
							 | 
						|
								//
							 | 
						|
								//
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								Semaphore::Semaphore (unsigned max, unsigned initial)
							 | 
						|
								{
							 | 
						|
								    unsigned const sem_value_max =
							 | 
						|
								#if defined (SEM_VALUE_MAX)
							 | 
						|
								        SEM_VALUE_MAX
							 | 
						|
								#else
							 | 
						|
								        (std::numeric_limits<int>::max) ()
							 | 
						|
								#endif
							 | 
						|
								        ;
							 | 
						|
								
							 | 
						|
								    unsigned const limited_max = (std::min) (max, sem_value_max);
							 | 
						|
								    unsigned const limited_initial = (std::min) (initial, limited_max);
							 | 
						|
								    int ret = 0;
							 | 
						|
								
							 | 
						|
								#if defined (LOG4CPLUS_USE_NAMED_POSIX_SEMAPHORE)
							 | 
						|
								    std::ostringstream oss;
							 | 
						|
								    char size_check[2 * (static_cast<int>(sizeof (std::ptrdiff_t))
							 | 
						|
								                         - static_cast<int>(sizeof (this))) + 1];
							 | 
						|
								    (void)size_check;
							 | 
						|
								    oss << getpid () << "-" << reinterpret_cast<std::ptrdiff_t>(this);
							 | 
						|
								    std::string name (oss.str ());
							 | 
						|
								
							 | 
						|
								    sem = sem_open (name.c_str (), O_CREAT, S_IRWXU | S_IRWXG, limited_max);
							 | 
						|
								    ret = sem == SEM_FAILED;
							 | 
						|
								    if (ret != 0)
							 | 
						|
								        LOG4CPLUS_THROW_RTE ("Semaphore::Semaphore");
							 | 
						|
								
							 | 
						|
								    try
							 | 
						|
								    {
							 | 
						|
								        // Unlink the semaphore early to simulate anonymous semaphore.
							 | 
						|
								        ret = sem_unlink (name.c_str ());
							 | 
						|
								        if (ret != 0)
							 | 
						|
								            LOG4CPLUS_THROW_RTE ("Semaphore::Semaphore");
							 | 
						|
								    }
							 | 
						|
								    catch (std::runtime_error const &)
							 | 
						|
								    {
							 | 
						|
								        ret = sem_close (sem);
							 | 
						|
								        if (ret != 0)
							 | 
						|
								            LOG4CPLUS_THROW_RTE ("Semaphore::~Semaphore");
							 | 
						|
								
							 | 
						|
								        throw;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								#else
							 | 
						|
								    ret = sem_init (&sem, 0, limited_max);
							 | 
						|
								    if (ret != 0)
							 | 
						|
								        LOG4CPLUS_THROW_RTE ("Semaphore::Semaphore");
							 | 
						|
								
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    try
							 | 
						|
								    {
							 | 
						|
								        for (unsigned i = limited_initial; i < limited_max; ++i)
							 | 
						|
								            lock ();
							 | 
						|
								    }
							 | 
						|
								    catch (std::runtime_error const &)
							 | 
						|
								    {
							 | 
						|
								#if defined (LOG4CPLUS_USE_NAMED_POSIX_SEMAPHORE)
							 | 
						|
								        ret = sem_close (sem);
							 | 
						|
								#else
							 | 
						|
								        ret = sem_destroy (&sem);
							 | 
						|
								#endif
							 | 
						|
								        if (ret != 0)
							 | 
						|
								            LOG4CPLUS_THROW_RTE ("Semaphore::~Semaphore");
							 | 
						|
								
							 | 
						|
								        throw;
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								Semaphore::~Semaphore ()
							 | 
						|
								{
							 | 
						|
								    try
							 | 
						|
								    {
							 | 
						|
								        int ret = 0;
							 | 
						|
								#if defined (LOG4CPLUS_USE_NAMED_POSIX_SEMAPHORE)
							 | 
						|
								        ret = sem_close (sem);
							 | 
						|
								#else
							 | 
						|
								        ret = sem_destroy (&sem);
							 | 
						|
								#endif
							 | 
						|
								        if (ret != 0)
							 | 
						|
								            LOG4CPLUS_THROW_RTE ("Semaphore::~Semaphore");
							 | 
						|
								    }
							 | 
						|
								    catch (...)
							 | 
						|
								    { }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								void
							 | 
						|
								Semaphore::unlock () const
							 | 
						|
								{
							 | 
						|
								#if defined (LOG4CPLUS_USE_NAMED_POSIX_SEMAPHORE)
							 | 
						|
								    int ret = sem_post (sem);
							 | 
						|
								#else
							 | 
						|
								    int ret = sem_post (&sem);
							 | 
						|
								#endif
							 | 
						|
								    if (ret != 0)
							 | 
						|
								        LOG4CPLUS_THROW_RTE ("Semaphore::unlock");
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								void
							 | 
						|
								Semaphore::lock () const
							 | 
						|
								{
							 | 
						|
								#if defined (LOG4CPLUS_USE_NAMED_POSIX_SEMAPHORE)
							 | 
						|
								    int ret = sem_wait (sem);
							 | 
						|
								#else
							 | 
						|
								    int ret = sem_wait (&sem);
							 | 
						|
								#endif
							 | 
						|
								    if (ret != 0)
							 | 
						|
								        LOG4CPLUS_THROW_RTE ("Semaphore::lock");
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								//
							 | 
						|
								//
							 | 
						|
								//
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								FairMutex::FairMutex ()
							 | 
						|
								    : sem (1, 1)
							 | 
						|
								{ }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								FairMutex::~FairMutex ()
							 | 
						|
								{ }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								void
							 | 
						|
								FairMutex::lock () const
							 | 
						|
								{
							 | 
						|
								    sem.lock ();
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								void
							 | 
						|
								FairMutex::unlock () const
							 | 
						|
								{
							 | 
						|
								    sem.unlock ();
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								//
							 | 
						|
								//
							 | 
						|
								//
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								ManualResetEvent::ManualResetEvent (bool sig)
							 | 
						|
								    : mtx (log4cplus::thread::Mutex::DEFAULT)
							 | 
						|
								    , sigcount (0)
							 | 
						|
								    , signaled (sig)
							 | 
						|
								{
							 | 
						|
								    int ret = pthread_cond_init (&cv, 0);
							 | 
						|
								    if (ret != 0)
							 | 
						|
								        LOG4CPLUS_THROW_RTE ("ManualResetEvent::ManualResetEvent");
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								ManualResetEvent::~ManualResetEvent ()
							 | 
						|
								{
							 | 
						|
								    try
							 | 
						|
								    {
							 | 
						|
								        int ret = pthread_cond_destroy (&cv);
							 | 
						|
								        if (ret != 0)
							 | 
						|
								            LOG4CPLUS_THROW_RTE ("ManualResetEvent::~ManualResetEvent");
							 | 
						|
								    }
							 | 
						|
								    catch (...)
							 | 
						|
								    { }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								void
							 | 
						|
								ManualResetEvent::signal () const
							 | 
						|
								{
							 | 
						|
								    MutexGuard mguard (mtx);
							 | 
						|
								
							 | 
						|
								    signaled = true;
							 | 
						|
								    sigcount += 1;
							 | 
						|
								    int ret = pthread_cond_broadcast (&cv);
							 | 
						|
								    if (ret != 0)
							 | 
						|
								        LOG4CPLUS_THROW_RTE ("ManualResetEVent::signal");
							 | 
						|
								
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								void
							 | 
						|
								ManualResetEvent::wait () const
							 | 
						|
								{
							 | 
						|
								    MutexGuard mguard (mtx);
							 | 
						|
								
							 | 
						|
								    if (! signaled)
							 | 
						|
								    {
							 | 
						|
								        unsigned prev_count = sigcount;
							 | 
						|
								        do
							 | 
						|
								        {
							 | 
						|
								            int ret = pthread_cond_wait (&cv, &mtx.mtx);
							 | 
						|
								            if (ret != 0)
							 | 
						|
								            {
							 | 
						|
								                mguard.unlock ();
							 | 
						|
								                mguard.detach ();
							 | 
						|
								                LOG4CPLUS_THROW_RTE ("ManualResetEvent::wait");
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								        while (prev_count == sigcount);
							 | 
						|
								    }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								bool
							 | 
						|
								ManualResetEvent::timed_wait (unsigned long msec) const
							 | 
						|
								{
							 | 
						|
								    MutexGuard mguard (mtx);
							 | 
						|
								
							 | 
						|
								    if (! signaled)
							 | 
						|
								    {
							 | 
						|
								        helpers::Time const wakeup_time (helpers::Time::gettimeofday ()
							 | 
						|
								            + helpers::Time (msec / 1000, (msec % 1000) * 1000));
							 | 
						|
								        struct timespec const ts = {wakeup_time.sec (),
							 | 
						|
								            wakeup_time.usec () * 1000};
							 | 
						|
								        unsigned prev_count = sigcount;
							 | 
						|
								        do
							 | 
						|
								        {
							 | 
						|
								            int ret = pthread_cond_timedwait (&cv, &mtx.mtx, &ts);
							 | 
						|
								            switch (ret)
							 | 
						|
								            {
							 | 
						|
								            case 0:
							 | 
						|
								                break;
							 | 
						|
								
							 | 
						|
								            case ETIMEDOUT:
							 | 
						|
								                return false;
							 | 
						|
								
							 | 
						|
								            default:
							 | 
						|
								                mguard.unlock ();
							 | 
						|
								                mguard.detach ();
							 | 
						|
								                LOG4CPLUS_THROW_RTE ("ManualResetEvent::timed_wait");
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								        while (prev_count == sigcount);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return true;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								void
							 | 
						|
								ManualResetEvent::reset () const
							 | 
						|
								{
							 | 
						|
								    MutexGuard mguard (mtx);
							 | 
						|
								
							 | 
						|
								    signaled = false;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								//
							 | 
						|
								//
							 | 
						|
								//
							 | 
						|
								
							 | 
						|
								#if defined (LOG4CPLUS_POOR_MANS_SHAREDMUTEX)
							 | 
						|
								#include "log4cplus/thread/impl/syncprims-pmsm.h"
							 | 
						|
								
							 | 
						|
								#else
							 | 
						|
								inline
							 | 
						|
								SharedMutex::SharedMutex ()
							 | 
						|
								{
							 | 
						|
								    int ret = pthread_rwlock_init (&rwl, 0);
							 | 
						|
								    if (ret != 0)
							 | 
						|
								        LOG4CPLUS_THROW_RTE ("SharedMutex::SharedMutex");
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								SharedMutex::~SharedMutex ()
							 | 
						|
								{
							 | 
						|
								    try
							 | 
						|
								    {
							 | 
						|
								        int ret = pthread_rwlock_destroy (&rwl);
							 | 
						|
								        if (ret != 0)
							 | 
						|
								            LOG4CPLUS_THROW_RTE ("SharedMutex::~SharedMutex");
							 | 
						|
								    }
							 | 
						|
								    catch (...)
							 | 
						|
								    { }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								void
							 | 
						|
								SharedMutex::rdlock () const
							 | 
						|
								{
							 | 
						|
								    int ret;
							 | 
						|
								
							 | 
						|
								    do
							 | 
						|
								    {
							 | 
						|
								        ret = pthread_rwlock_rdlock (&rwl);
							 | 
						|
								        switch (ret)
							 | 
						|
								        {
							 | 
						|
								        case EAGAIN:
							 | 
						|
								            // The read lock could not be acquired because the maximum
							 | 
						|
								            // number of read locks for rwlock has been exceeded.
							 | 
						|
								
							 | 
						|
								            log4cplus::thread::yield ();
							 | 
						|
								            // Fall through.
							 | 
						|
								
							 | 
						|
								        case 0:
							 | 
						|
								            break;
							 | 
						|
								
							 | 
						|
								        default:
							 | 
						|
								            LOG4CPLUS_THROW_RTE ("SharedMutex::rdlock");
							 | 
						|
								
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								    while (ret != 0);
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								void
							 | 
						|
								SharedMutex::rdunlock () const
							 | 
						|
								{
							 | 
						|
								    unlock ();
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								void
							 | 
						|
								SharedMutex::wrlock () const
							 | 
						|
								{
							 | 
						|
								    int ret = pthread_rwlock_wrlock (&rwl);
							 | 
						|
								    if (ret != 0)
							 | 
						|
								        LOG4CPLUS_THROW_RTE ("SharedMutex::wrlock");
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								void
							 | 
						|
								SharedMutex::wrunlock () const
							 | 
						|
								{
							 | 
						|
								    unlock ();
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								inline
							 | 
						|
								void
							 | 
						|
								SharedMutex::unlock () const
							 | 
						|
								{
							 | 
						|
								    int ret = pthread_rwlock_unlock (&rwl);
							 | 
						|
								    if (ret != 0)
							 | 
						|
								        LOG4CPLUS_THROW_RTE ("SharedMutex::unlock");
							 | 
						|
								
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								} } } // namespace log4cplus { namespace thread { namespace impl {
							 |