Program Listing for File mutex_pos.hpp

Return to documentation for file (/tmp/ws/src/ecl_core/ecl_threads/include/ecl/threads/mutex_pos.hpp)

/*****************************************************************************
** Ifdefs
*****************************************************************************/

#ifndef ECL_THREADS_MUTEX_POS_HPP_
#define ECL_THREADS_MUTEX_POS_HPP_

/*****************************************************************************
** Platform Check
*****************************************************************************/

#include <ecl/config/ecl.hpp>
#if defined(ECL_IS_POSIX)

/*****************************************************************************
** Includes
*****************************************************************************/

#include <errno.h>
#include <cstring> // strerror function
#include <string>
#include <pthread.h>
#include <sstream>
#include <ecl/config/macros.hpp>
#include <ecl/exceptions/macros.hpp>
#include <ecl/exceptions/standard_exception.hpp>
#include <ecl/time/duration.hpp>


/*****************************************************************************
** Namespaces
*****************************************************************************/

namespace ecl {

/*****************************************************************************
** Typedefs
*****************************************************************************/

typedef pthread_mutex_t RawMutex;
/*****************************************************************************
** Class Mutex
*****************************************************************************/
class Mutex {
public:
    Mutex(const bool locked = false);
    virtual ~Mutex();

    void unlock();
    void lock();
    bool trylock(Duration &duration);
    bool trylock();
    unsigned int locks() { return number_locks; }

    RawMutex& rawType() { return mutex; }

private:
    RawMutex mutex;
    unsigned int number_locks;

};

} // namespace ecl

/*****************************************************************************
** Interface [Exceptions]
*****************************************************************************/

#if defined(ECL_HAS_EXCEPTIONS)
namespace ecl {
namespace threads {

/*****************************************************************************
** Interface [Mutex Exceptions]
*****************************************************************************/

inline StandardException ECL_LOCAL throwMutexAttrException(const char* loc, int error_result) {
    switch (error_result) {
        case ( EINVAL ) : return StandardException(loc, InvalidInputError, "The specified mutex attribute was invalid.");
        case ( ENOMEM ) : return StandardException(loc, MemoryError, "There is insufficient memory for initialisation of the mutex attribute.");
        default         :
        {
            std::ostringstream ostream;
            ostream << "Unknown posix error " << error_result << ": " << strerror(error_result) << ".";
            return StandardException(loc, UnknownError, ostream.str());
        }
    }
}
inline StandardException ECL_LOCAL throwMutexInitException(const char* loc, int error_result) {
    switch (error_result) {
        case ( EINVAL ) : return StandardException(loc, InvalidInputError, "The specified mutex was invalid.");
        case ( EBUSY )  : return StandardException(loc, InvalidInputError, "The mutex object has already been initialised and not yet destroyed.");
        case ( EAGAIN ) : return StandardException(loc, MemoryError, "The mutex object has already been initialised and not yet destroyed.");
        case ( ENOMEM ) : return StandardException(loc, MemoryError, "There is insufficient memory for initialisation of the mutex.");
        case ( EPERM )  : return StandardException(loc, PermissionsError, "The user does not have the privilege to perform the operation.");
        default         :
        {
            std::ostringstream ostream;
            ostream << "Unknown posix error " << error_result << ": " << strerror(error_result) << ".";
            return StandardException(loc, UnknownError, ostream.str());
        }
    }
}
inline StandardException ECL_LOCAL throwMutexDestroyException(const char* loc, int error_result) {
    switch (error_result) {
        case ( EINVAL ) : return StandardException(loc, DestructorError, "The specified mutex is invalid (for some reason or other).");
        case ( EBUSY )  : return StandardException(loc, DestructorError, "Attempted to destroy the mutex while it was locked.");
        default         : return StandardException(loc, UnknownError, "Unknown error.");
    }
}
inline StandardException ECL_LOCAL throwMutexTimedLockException(const char* loc, int error_result) {
    switch (error_result) {
        case ( EDEADLK ): return StandardException(loc, UsageError, "DEADLOCK! The current thread already owns the mutex.");
        // These aren't relevant to us (EBUSY is normal operation for trylock, EINVAL can't happen because of RAII, and EAGAIN because our mutex isn't RECURSIVE)
        case ( EINVAL ) : return StandardException(loc, UsageError, "The mutex is not initialised or it is priority protected and the calling thread's priority is higher than the mutex' current priority ceiling.");
        case ( EAGAIN ) : return StandardException(loc, OutOfRangeError, "The mutex could not be acquired because the maximum number of recursive locks for the mutex has been exceeded.");
        default         : return StandardException(loc, UnknownError, "Unknown error.");
    }
}
inline StandardException ECL_LOCAL throwMutexLockException(const char* loc, int error_result) {
    switch (error_result) {
        case ( EDEADLK ): return StandardException(loc, UsageError, "DEADLOCK! The mutex has already been locked by this thread, it now has to wait on itself.");
        // These aren't relevant to us (EBUSY is normal operation for trylock, EINVAL can't happen because of RAII, and EAGAIN because our mutex isn't RECURSIVE)
        case ( EBUSY )  : return StandardException(loc, ConfigurationError, "The try lock failed because it was already locked (normal operation really, not really an error).");
        case ( EINVAL ) : return StandardException(loc, InvalidInputError, "The mutex does not refer to an initialised mutex.");
        case ( EAGAIN ) : return StandardException(loc, OutOfRangeError, "The mutex could not be acquired because the maximum number of recursive locks for the mutex has been exceeded.");
        default         : return StandardException(loc, PosixError, "Unknown error.");
    }
}
inline StandardException ECL_LOCAL throwMutexUnLockException(const char* loc, int error_result) {
    switch (error_result) {
        case ( EINVAL ) : return StandardException(loc, InvalidInputError, "The mutex does not refer to an initialised mutex.");
        case ( EAGAIN ) : return StandardException(loc, OutOfRangeError, "The mutex could not be acquired because the maximum number of recursive locks for the mutex has been exceeded.");
        case ( EPERM )  : return StandardException(loc, PermissionsError, "The user does not have the privilege to perform the operation.");
        default         : return StandardException(loc, UnknownError, "Unknown error.");
    }
}


} // namespace threads
} // namespace ecl

#endif /* ECL_HAS_EXCEPTIONS */
#endif /* ECL_IS_POSIX */
#endif /* ECL_THREADS_MUTEX_POS_HPP_ */