Mercurial > projects > hoofbaby
diff deps/Platinum/ThirdParty/Neptune/Source/System/Posix/NptPosixQueue.cpp @ 0:3425707ddbf6
Initial import (hopefully this mercurial stuff works...)
author | fraserofthenight |
---|---|
date | Mon, 06 Jul 2009 08:06:28 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/deps/Platinum/ThirdParty/Neptune/Source/System/Posix/NptPosixQueue.cpp Mon Jul 06 08:06:28 2009 -0700 @@ -0,0 +1,295 @@ +/***************************************************************** +| +| Neptune - Queue :: Posix Implementation +| +| (c) 2001-2002 Gilles Boccon-Gibod +| Author: Gilles Boccon-Gibod (bok@bok.net) +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#if defined(__SYMBIAN32__) +#include <stdio.h> +#endif +#include <pthread.h> +#include <time.h> +#include <sys/time.h> +#if defined(__SYMBIAN32__) +#include <errno.h> +#else +#include <cerrno> +#endif + +#include "NptConfig.h" +#include "NptTypes.h" +#include "NptQueue.h" +#include "NptThreads.h" +#include "NptList.h" +#include "NptLogging.h" + +/*---------------------------------------------------------------------- +| logging ++---------------------------------------------------------------------*/ +NPT_SET_LOCAL_LOGGER("neptune.queue.posix") + +/*---------------------------------------------------------------------- +| NPT_PosixQueue ++---------------------------------------------------------------------*/ +class NPT_PosixQueue : public NPT_GenericQueue +{ +public: + // methods + NPT_PosixQueue(NPT_Cardinal max_items); + ~NPT_PosixQueue(); + NPT_Result Push(NPT_QueueItem* item, NPT_Timeout timeout); + NPT_Result Pop(NPT_QueueItem*& item, NPT_Timeout timeout); + NPT_Result Peek(NPT_QueueItem*& item, NPT_Timeout timeout); + +private: + // members + NPT_Cardinal m_MaxItems; + pthread_mutex_t m_Mutex; + pthread_cond_t m_CanPushCondition; + pthread_cond_t m_CanPopCondition; + NPT_Cardinal m_PushersWaitingCount; + NPT_Cardinal m_PoppersWaitingCount; + NPT_List<NPT_QueueItem*> m_Items; +}; + +/*---------------------------------------------------------------------- +| NPT_PosixQueue::NPT_PosixQueue ++---------------------------------------------------------------------*/ +NPT_PosixQueue::NPT_PosixQueue(NPT_Cardinal max_items) : + m_MaxItems(max_items), + m_PushersWaitingCount(0), + m_PoppersWaitingCount(0) +{ + NPT_LOG_FINER("NPT_PosixQueue::NPT_PosixQueue"); + + pthread_mutex_init(&m_Mutex, NULL); + pthread_cond_init(&m_CanPushCondition, NULL); + pthread_cond_init(&m_CanPopCondition, NULL); +} + +/*---------------------------------------------------------------------- +| NPT_PosixQueue::~NPT_PosixQueue() ++---------------------------------------------------------------------*/ +NPT_PosixQueue::~NPT_PosixQueue() +{ + // destroy resources + pthread_cond_destroy(&m_CanPushCondition); + pthread_cond_destroy(&m_CanPopCondition); + pthread_mutex_destroy(&m_Mutex); +} + +/*---------------------------------------------------------------------- +| NPT_PosixQueue::Push ++---------------------------------------------------------------------*/ +NPT_Result +NPT_PosixQueue::Push(NPT_QueueItem* item, NPT_Timeout timeout) +{ + struct timespec timed; + if (timeout != NPT_TIMEOUT_INFINITE) { + // get current time from system + struct timeval now; + if (gettimeofday(&now, NULL)) { + return NPT_FAILURE; + } + + now.tv_usec += timeout * 1000; + if (now.tv_usec >= 1000000) { + now.tv_sec += now.tv_usec / 1000000; + now.tv_usec = now.tv_usec % 1000000; + } + + // setup timeout + timed.tv_sec = now.tv_sec; + timed.tv_nsec = now.tv_usec * 1000; + } + + // lock the mutex that protects the list + if (pthread_mutex_lock(&m_Mutex)) { + return NPT_FAILURE; + } + + NPT_Result result = NPT_SUCCESS; + // check that we have not exceeded the max + if (m_MaxItems) { + while (m_Items.GetItemCount() >= m_MaxItems) { + // wait until we can push + ++m_PushersWaitingCount; + if (timeout == NPT_TIMEOUT_INFINITE) { + pthread_cond_wait(&m_CanPushCondition, &m_Mutex); + --m_PushersWaitingCount; + } else { + int wait_res = pthread_cond_timedwait(&m_CanPushCondition, + &m_Mutex, + &timed); + --m_PushersWaitingCount; + if (wait_res == ETIMEDOUT) { + result = NPT_ERROR_TIMEOUT; + break; + } + } + } + } + + // add the item to the list + if (result == NPT_SUCCESS) { + m_Items.Add(item); + + // wake up any thread that may be waiting to pop + if (m_PoppersWaitingCount) { + pthread_cond_signal(&m_CanPopCondition); + } + } + + // unlock the mutex + pthread_mutex_unlock(&m_Mutex); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_PosixQueue::Pop ++---------------------------------------------------------------------*/ +NPT_Result +NPT_PosixQueue::Pop(NPT_QueueItem*& item, NPT_Timeout timeout) +{ + struct timespec timed; + if (timeout != NPT_TIMEOUT_INFINITE) { + // get current time from system + struct timeval now; + if (gettimeofday(&now, NULL)) { + return NPT_FAILURE; + } + + now.tv_usec += timeout * 1000; + if (now.tv_usec >= 1000000) { + now.tv_sec += now.tv_usec / 1000000; + now.tv_usec = now.tv_usec % 1000000; + } + + // setup timeout + timed.tv_sec = now.tv_sec; + timed.tv_nsec = now.tv_usec * 1000; + } + + // lock the mutex that protects the list + if (pthread_mutex_lock(&m_Mutex)) { + return NPT_FAILURE; + } + + NPT_Result result; + if (timeout) { + while ((result = m_Items.PopHead(item)) == NPT_ERROR_LIST_EMPTY) { + // no item in the list, wait for one + ++m_PoppersWaitingCount; + if (timeout == NPT_TIMEOUT_INFINITE) { + pthread_cond_wait(&m_CanPopCondition, &m_Mutex); + --m_PoppersWaitingCount; + } else { + int wait_res = pthread_cond_timedwait(&m_CanPopCondition, + &m_Mutex, + &timed); + --m_PoppersWaitingCount; + if (wait_res == ETIMEDOUT) { + result = NPT_ERROR_TIMEOUT; + break; + } + } + } + } else { + result = m_Items.PopHead(item); + } + + // wake up any thread that my be waiting to push + if (m_MaxItems && (result == NPT_SUCCESS) && m_PushersWaitingCount) { + pthread_cond_signal(&m_CanPushCondition); + } + + // unlock the mutex + pthread_mutex_unlock(&m_Mutex); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_PosixQueue::Peek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_PosixQueue::Peek(NPT_QueueItem*& item, NPT_Timeout timeout) +{ + struct timespec timed; + if (timeout != NPT_TIMEOUT_INFINITE) { + // get current time from system + struct timeval now; + if (gettimeofday(&now, NULL)) { + return NPT_FAILURE; + } + + now.tv_usec += timeout * 1000; + if (now.tv_usec >= 1000000) { + now.tv_sec += now.tv_usec / 1000000; + now.tv_usec = now.tv_usec % 1000000; + } + + // setup timeout + timed.tv_sec = now.tv_sec; + timed.tv_nsec = now.tv_usec * 1000; + } + + // lock the mutex that protects the list + if (pthread_mutex_lock(&m_Mutex)) { + return NPT_FAILURE; + } + + NPT_Result result = NPT_SUCCESS; + NPT_List<NPT_QueueItem*>::Iterator head = m_Items.GetFirstItem(); + if (timeout) { + while (!head) { + // no item in the list, wait for one + ++m_PoppersWaitingCount; + if (timeout == NPT_TIMEOUT_INFINITE) { + pthread_cond_wait(&m_CanPopCondition, &m_Mutex); + --m_PoppersWaitingCount; + } else { + int wait_res = pthread_cond_timedwait(&m_CanPopCondition, + &m_Mutex, + &timed); + --m_PoppersWaitingCount; + if (wait_res == ETIMEDOUT) { + result = NPT_ERROR_TIMEOUT; + break; + } + } + + head = m_Items.GetFirstItem(); + } + } else { + if (!head) result = NPT_ERROR_LIST_EMPTY; + } + + item = head?*head:NULL; + + // unlock the mutex + pthread_mutex_unlock(&m_Mutex); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_GenericQueue::CreateInstance ++---------------------------------------------------------------------*/ +NPT_GenericQueue* +NPT_GenericQueue::CreateInstance(NPT_Cardinal max_items) +{ + NPT_LOG_FINER_1("NPT_GenericQueue::CreateInstance - queue max_items = %ld", max_items); + return new NPT_PosixQueue(max_items); +} + + + +