/*---------------------------------------------------------------------- | NPT_Win32SharedVariable::WaitWhileOrUntilEquals +---------------------------------------------------------------------*/ NPT_Result NPT_Win32SharedVariable::WaitWhileOrUntilEquals(int value, NPT_Timeout timeout, bool until) { do { m_Lock.Lock(); if (until) { if (m_Value == value) break; } else { if (m_Value != value) break; } ++m_Waiters; m_Lock.Unlock(); NPT_Result result = m_Event.Wait(timeout); bool last_waiter = true; m_Lock.Lock(); if (--m_Waiters == 0) { m_Event.Reset(); } else { last_waiter = false; } m_Lock.Unlock(); if (NPT_FAILED(result)) return result; // FIXME: this is suboptimal, but we need it to ensure we don't busy-loop if (!last_waiter) { Sleep(10); } } while (true); m_Lock.Unlock(); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | 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 NPT_Result 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_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 NPT_Result 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::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; }