csutil/threading/win32_condition.h Source File (Crystal Space 2.0 Public API Reference)

| ## Public API Reference

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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__