00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifndef __CS_CSUTIL_THREADING_WIN32_CONDITION_H__
00020 #define __CS_CSUTIL_THREADING_WIN32_CONDITION_H__
00021
00022 #if !defined(CS_PLATFORM_WIN32)
00023 #error "This file is only for Windows and requires you to include csysdefs.h before"
00024 #else
00025
00026 #include "csutil/threading/atomicops.h"
00027 #include "csutil/threading/mutex.h"
00028 #include "csutil/threading//win32_apifuncs.h"
00029 #include "csutil/noncopyable.h"
00030
00031 namespace CS
00032 {
00033 namespace Threading
00034 {
00035 namespace Implementation
00036 {
00037
00038 static void __stdcall NotifyFunc (Implementation::ulong_ptr)
00039 {
00040 }
00041
00042 class ConditionBase
00043 {
00044 public:
00045 ConditionBase ()
00046 {
00047 waitingList.next = &waitingList;
00048 waitingList.prev = &waitingList;
00049 }
00050
00051 void NotifyOne ()
00052 {
00053 StateGateLock lock (stateGate);
00054
00055 if (waitingList.prev != &waitingList)
00056 {
00057 WaitListEntry* const entry = waitingList.prev;
00058 entry->Unlink ();
00059 NotifyEntry (entry);
00060 }
00061 }
00062
00063 void NotifyAll ()
00064 {
00065 StateGateLock lock (stateGate);
00066
00067 WaitListEntry* head = waitingList.prev;
00068 waitingList.prev = &waitingList;
00069 waitingList.next = &waitingList;
00070
00071 while (head != &waitingList)
00072 {
00073 WaitListEntry* const prev = head->prev;
00074 NotifyEntry (head);
00075 head = prev;
00076 }
00077 }
00078
00079 template<typename LockType>
00080 bool Wait (LockType& lock, csTicks timeout)
00081 {
00082 WaitListEntry waitEntry;
00083
00084 void* const currentProcess = Implementation::GetCurrentProcess ();
00085 void* const currentThread = Implementation::GetCurrentThread ();
00086
00087 Implementation::DuplicateHandle (currentProcess, currentThread, currentProcess,
00088 &waitEntry.waitingThreadHandle, 0, false, DUPLICATE_SAME_ACCESS);
00089
00090 {
00091 AddEntryHelper<LockType> entryGuard (this, waitEntry, lock);
00092
00093 DWORD r;
00094
00095 while (!AtomicOperations::Read (&waitEntry.notified) &&
00096 (r = Implementation::SleepEx (timeout == 0 ? INFINITE : timeout,
00097 true)) == WAIT_IO_COMPLETION)
00098 ;
00099 return r != 0;
00100 }
00101 }
00102
00103
00104 protected:
00105
00106
00107 struct WaitListEntry
00108 {
00109 void* waitingThreadHandle;
00110 int32 notified;
00111 WaitListEntry* next;
00112 WaitListEntry* prev;
00113
00114 WaitListEntry ()
00115 : waitingThreadHandle (0), notified (0), next (0), prev (0)
00116 {
00117 }
00118
00119 void Unlink ()
00120 {
00121 next->prev = prev;
00122 prev->next = next;
00123 next = this;
00124 prev = this;
00125 }
00126 };
00127
00128
00129 Mutex stateGate;
00130 typedef ScopedLock<Mutex> StateGateLock;
00131
00132 WaitListEntry waitingList;
00133
00134
00135 template<typename LockType>
00136 struct AddEntryHelper
00137 {
00138 ConditionBase* owner;
00139 WaitListEntry& entry;
00140 LockType& lock;
00141
00142 AddEntryHelper (ConditionBase* owner, WaitListEntry& entry, LockType& lock)
00143 : owner (owner), entry (entry), lock (lock)
00144 {
00145 entry.prev = &owner->waitingList;
00146 StateGateLock locks (owner->stateGate);
00147
00148 entry.next = owner->waitingList.next;
00149 owner->waitingList.next = &entry;
00150 entry.next->prev = &entry;
00151
00152 lock.Unlock ();
00153 }
00154
00155 ~AddEntryHelper ()
00156 {
00157 if (!entry.notified)
00158 {
00159 StateGateLock locks (owner->stateGate);
00160 if (!entry.notified)
00161 {
00162 entry.Unlink ();
00163 }
00164 }
00165
00166 Implementation::CloseHandle ((HANDLE)entry.waitingThreadHandle);
00167 lock.Lock ();
00168 }
00169 };
00170 template<typename LockType> friend struct AddEntryHelper;
00171
00172 void NotifyEntry (WaitListEntry* entry)
00173 {
00174 AtomicOperations::Set (&entry->notified, 1);
00175 if (entry->waitingThreadHandle)
00176 {
00177
00178 Implementation::QueueUserAPC (NotifyFunc, entry->waitingThreadHandle, 0);
00179 }
00180 }
00181 };
00182
00183 }
00184 }
00185 }
00186
00187 #endif // !defined(CS_PLATFORM_WIN32)
00188
00189 #endif // __CS_CSUTIL_THREADING_WIN32_CONDITION_H__