diff options
Diffstat (limited to 'lib/libUPnP/Neptune/Source/System/Win32/NptWin32Queue.cpp')
-rw-r--r-- | lib/libUPnP/Neptune/Source/System/Win32/NptWin32Queue.cpp | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/lib/libUPnP/Neptune/Source/System/Win32/NptWin32Queue.cpp b/lib/libUPnP/Neptune/Source/System/Win32/NptWin32Queue.cpp new file mode 100644 index 0000000..33fa190 --- /dev/null +++ b/lib/libUPnP/Neptune/Source/System/Win32/NptWin32Queue.cpp @@ -0,0 +1,240 @@ +/***************************************************************** +| +| Neptune - Queue :: Win32 Implementation +| +| (c) 2001-2002 Gilles Boccon-Gibod +| Author: Gilles Boccon-Gibod (bok@bok.net) +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#if defined(_XBOX) +#include <xtl.h> +#else +#include <windows.h> +#endif + +#include "NptConfig.h" +#include "NptTypes.h" +#include "NptQueue.h" +#include "NptThreads.h" +#include "NptList.h" +#include "NptDebug.h" +#include "NptLogging.h" + +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP || defined(TARGET_WINDOWS_STORE) +// for XBox, Windows 7 Desktop or earlier +#include "NptWin32Threads.h" +#elif WINAPI_FAMILY == WINAPI_FAMILY_APP +// for WinRT Apps +#include "NptWinRtThreads.h" +#endif + +/*---------------------------------------------------------------------- +| logging ++---------------------------------------------------------------------*/ +//NPT_SET_LOCAL_LOGGER("neptune.queue.win32") + +/*---------------------------------------------------------------------- +| NPT_Win32Queue ++---------------------------------------------------------------------*/ +class NPT_Win32Queue : public NPT_GenericQueue +{ +public: + // methods + NPT_Win32Queue(NPT_Cardinal max_items); + ~NPT_Win32Queue(); + 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; + +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP || defined(TARGET_WINDOWS_STORE) + // for XBox, Windows 7 Desktop or earlier + NPT_Win32CriticalSection m_Mutex; + NPT_Win32Event* m_CanPushCondition; + NPT_Win32Event* m_CanPopCondition; +#elif WINAPI_FAMILY == WINAPI_FAMILY_APP + // for WinRT Apps + NPT_WinRtCriticalSection m_Mutex; + NPT_WinRtEvent* m_CanPushCondition; + NPT_WinRtEvent* m_CanPopCondition; +#endif + + NPT_List<NPT_QueueItem*> m_Items; // should be volatile ? +}; + +/*---------------------------------------------------------------------- +| NPT_Win32Queue::NPT_Win32Queue ++---------------------------------------------------------------------*/ +NPT_Win32Queue::NPT_Win32Queue(NPT_Cardinal max_items) : + m_MaxItems(max_items) +{ +#if !defined(WINAPI_FAMILY) || WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP || defined(TARGET_WINDOWS_STORE) + // for XBox, Windows 7 Desktop or earlier + m_CanPushCondition = new NPT_Win32Event(true, true); + m_CanPopCondition = new NPT_Win32Event(true, false); +#elif WINAPI_FAMILY == WINAPI_FAMILY_APP + // for WinRT Apps + m_CanPushCondition = new NPT_WinRtEvent(true, true); + m_CanPopCondition = new NPT_WinRtEvent(true, false); +#endif +} + +/*---------------------------------------------------------------------- +| NPT_Win32Queue::~NPT_Win32Queue() ++---------------------------------------------------------------------*/ +NPT_Win32Queue::~NPT_Win32Queue() +{ + // destroy resources + delete m_CanPushCondition; + delete m_CanPopCondition; +} + +/*---------------------------------------------------------------------- +| NPT_Win32Queue::Push ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Win32Queue::Push(NPT_QueueItem* item, NPT_Timeout timeout) +{ + // lock the mutex that protects the list + NPT_CHECK(m_Mutex.Lock()); + + // check that we have not exceeded the max + if (m_MaxItems) { + while (m_Items.GetItemCount() >= m_MaxItems) { + // we must wait until some items have been removed + + // reset the condition to indicate that the queue is full + m_CanPushCondition->Reset(); + + // unlock the mutex so that another thread can pop + m_Mutex.Unlock(); + + // wait for the condition to signal that we can push + NPT_Result result = m_CanPushCondition->Wait(timeout); + if (NPT_FAILED(result)) return result; + + // relock the mutex so that we can check the list again + NPT_CHECK(m_Mutex.Lock()); + } + } + + // add the item to the list + m_Items.Add(item); + + // wake up the threads waiting to pop + m_CanPopCondition->Signal(); + + // unlock the mutex + m_Mutex.Unlock(); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Win32Queue::Pop ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Win32Queue::Pop(NPT_QueueItem*& item, NPT_Timeout timeout) +{ + // default value + item = NULL; + + // lock the mutex that protects the list + NPT_CHECK(m_Mutex.Lock()); + + NPT_Result result; + if (timeout) { + while ((result = m_Items.PopHead(item)) == NPT_ERROR_LIST_EMPTY) { + // no item in the list, wait for one + + // reset the condition to indicate that the queue is empty + m_CanPopCondition->Reset(); + + // unlock the mutex so that another thread can push + m_Mutex.Unlock(); + + // wait for the condition to signal that we can pop + result = m_CanPopCondition->Wait(timeout); + if (NPT_FAILED(result)) return result; + + // relock the mutex so that we can check the list again + NPT_CHECK(m_Mutex.Lock()); + } + } else { + result = m_Items.PopHead(item); + } + + if (m_MaxItems && (result == NPT_SUCCESS)) { + // wake up the threads waiting to push + m_CanPushCondition->Signal(); + } + + // unlock the mutex + m_Mutex.Unlock(); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_Win32Queue::Peek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_Win32Queue::Peek(NPT_QueueItem*& item, NPT_Timeout timeout) +{ + // default value + item = NULL; + + // lock the mutex that protects the list + NPT_CHECK(m_Mutex.Lock()); + + 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 + + // reset the condition to indicate that the queue is empty + m_CanPopCondition->Reset(); + + // unlock the mutex so that another thread can push + m_Mutex.Unlock(); + + // wait for the condition to signal that we can pop + result = m_CanPopCondition->Wait(timeout); + if (NPT_FAILED(result)) return result; + + // relock the mutex so that we can check the list again + NPT_CHECK(m_Mutex.Lock()); + + // try again + head = m_Items.GetFirstItem(); + } + } else { + if (!head) result = NPT_ERROR_LIST_EMPTY; + } + + if (head) item = *head; + + // unlock the mutex + m_Mutex.Unlock(); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_GenericQueue::CreateInstance ++---------------------------------------------------------------------*/ +NPT_GenericQueue* +NPT_GenericQueue::CreateInstance(NPT_Cardinal max_items) +{ + return new NPT_Win32Queue(max_items); +} + |