bool ThreadCommandQueueImpl::PushCommand(const ThreadCommand& command) { ThreadCommand::NotifyEvent* completeEvent = 0; ThreadCommand::NotifyEvent* queueAvailableEvent = 0; // Repeat writing command into buffer until it is available. do { { // Lock Scope Lock::Locker lock(&QueueLock); if (queueAvailableEvent) { FreeNotifyEvent_NTS(queueAvailableEvent); queueAvailableEvent = 0; } // Don't allow any commands after PushExitCommand() is called. if (ExitEnqueued && !command.ExitFlag) return false; bool bufferWasEmpty = CommandBuffer.IsEmpty(); UByte* buffer = CommandBuffer.Write(command.GetSize()); if (buffer) { ThreadCommand* c = command.CopyConstruct(buffer); if (c->NeedsWait()) completeEvent = c->pEvent = AllocNotifyEvent_NTS(); // Signal-waker consumer when we add data to buffer. if (bufferWasEmpty) pQueue->OnPushNonEmpty_Locked(); break; } queueAvailableEvent = AllocNotifyEvent_NTS(); BlockedProducers.PushBack(queueAvailableEvent); } // Lock Scope queueAvailableEvent->Wait(); } while(1); // Command was enqueued, wait if necessary. if (completeEvent) { completeEvent->Wait(); Lock::Locker lock(&QueueLock); FreeNotifyEvent_NTS(completeEvent); } return true; }