CrystalSpace

Public API Reference

csutil/threading/win32_condition.h

00001 /*
00002   Copyright (C) 2006 by Marten Svanfeldt
00003 
00004   This library is free software; you can redistribute it and/or
00005   modify it under the terms of the GNU Lesser General Public
00006   License as published by the Free Software Foundation; either
00007   version 2 of the License, or (at your option) any later version.
00008 
00009   This library is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012   Library General Public License for more details.
00013 
00014   You should have received a copy of the GNU Library General Public
00015   License along with this library; if not, write to the Free
00016   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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         // Loop until notified
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     // Keep a list of waiting threads
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     // Guard our own state
00129     Mutex stateGate;
00130     typedef ScopedLock<Mutex> StateGateLock;
00131 
00132     WaitListEntry waitingList;
00133 
00134     // Helper-class to add/remove entries from waiting list
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         // Wake up thread
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__

Generated for Crystal Space 1.2.1 by doxygen 1.5.3