OWLNext    7.0
Borland's Object Windows Library for the modern age
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
thread.h
Go to the documentation of this file.
1//----------------------------------------------------------------------------
2// Borland Class Library
3// Copyright (c) 1993, 1996 by Borland International, All Rights Reserved
4// Copyright (c) 1998 by Yura Bidus, All Rights Reserved
5//
6/// \file
7/// - Defines the class TSemaphore and its nested class TLock.
8/// - Defines the derived semaphore class TMutex
9/// - Defines the derived semaphore class TCountedSemaphore
10/// - Defines the derived semaphore class TEventSemaphore
11/// - Defines the derived semaphore class TWaitableTimer
12/// - Defined the semaphore set class TSemaphoreSet and its nested class TLock.
13/// - Defines the class TCriticalSection and its nested class TLock.
14/// - Defines the class TMRSWSection and its nested class TLock.
15/// - Defines the class TSync and its nested class TLock.
16/// - Defines the template TStaticSync and its nested class TLock.
17/// - Defines the class TThread.
18/// - Defines the class TTlsAllocator
19/// - Defines the class TLocalObject
20/// - Defines the class TLocalData
21/// - Defines the class TTlsDataManager
22/// - Defines the class TLocalObject
23//----------------------------------------------------------------------------
24
25#if !defined(OWL_THREAD_H)
26#define OWL_THREAD_H
27
28#include <owl/private/defs.h>
29#if defined(BI_HAS_PRAGMA_ONCE)
30# pragma once
31#endif
32
33#include <owl/defs.h>
34
35#if !defined(BI_MULTI_THREAD)
36#error Thread classes require multi-threaded operating system.
37#endif
38
39#include <owl/private/wsysinc.h>
40#include <owl/wsyscls.h>
41#include <owl/exbase.h>
42
43#if defined(BI_MULTI_THREAD_RTL)
44# include <owl/template.h>
45# include <vector>
46# include <algorithm>
47#endif
48
49namespace owl {
50
52
53#include <owl/preclass.h>
54
55/// \addtogroup utility
56/// @{
57
58//
59/// \class TSemaphore
60// ~~~~~ ~~~~~~~~~~
61/// Base class for handle-based thread synchronization classes, TMutex,
62/// TCountedSemaphore and TEventSemaphore. Defines some types & constants, as
63/// well as holding the system object handle for Win32.
64//
66 public:
67 virtual ~TSemaphore();
68
69 enum { NoWait = 0, NoLimit = INFINITE };
70 typedef HANDLE THandle;
71 operator THandle() const;
72
73
74 class TLock {
75 public:
76 TLock(const TSemaphore&, ulong timeOut = NoLimit, bool alertable = false);
77 ~TLock();
78
79 bool WasAquired() const; ///< See if really aquired, or just timed-out
80
81 /// Release lock early & relinquish, i.e. before destructor. Or, just
82 /// drop the lock count on an exiting semaphore & keep locked 'til dtor
83 //
84 void Release(bool relinquish = false);
85
86 private:
87 const TSemaphore* Sem;
88 };
89 friend class TLock;
91
92 protected:
93 virtual void Release() = 0; ///< Derived class must provide release
94
95 THandle Handle; ///< Derived class must initialize
96};
97
98//
99/// \class TMutex
100// ~~~~~ ~~~~~~
101/// Mutual-exclusive semaphore
102//
103/// TMutex provides a system-independent interface to critical sections in
104/// threads. With suitable underlying implementations the same code can be used
105/// under OS/2 and Windows NT.
106//
107/// An object of type TMutex can be used in conjunction with objects of type
108/// TMutex::TLock (inherited from TSemaphore) to guarantee that only one thread
109/// can be executing any of the code sections protected by the lock at any
110/// given time.
111//
112/// The differences between the classes TCriticalSection and TMutex are that a
113/// timeout can be specified when creating a Lock on a TMutex object, and that
114/// a TMutex object has a HANDLE which can be used outside the class. This
115/// mirrors the distinction made in Windows NT between a CRITICALSECTION and a
116/// Mutex. Under NT a TCriticalSection object is much faster than a TMutex
117/// object. Under operating systems that don't make this distinction a
118/// TCriticalSection object can use the same underlying implementation as a
119/// TMutex, losing the speed advantage that it has under NT.
120//
122 public:
123 TMutex(LPCTSTR name = nullptr, LPSECURITY_ATTRIBUTES sa = nullptr);
124 TMutex(const tstring& name, LPSECURITY_ATTRIBUTES sa = nullptr);
128
129 typedef TLock Lock; ///< For compatibility with old T-less typename
130
131 /// If another mutex with the same name existed when this mutex
132 /// was created, then another handle to the object exists and
133 /// someone else may be using it too.
134 //
135 bool IsShared();
136
137 private:
138 TMutex(const TMutex&);
139 const TMutex& operator =(const TMutex&);
140
141 virtual void Release(); ///< Release this mutex semaphore
142
143 bool Shared;
144
145};
146
147//
148/// \class TCountedSemaphore
149// ~~~~~ ~~~~~~~~~~~~~~~~~
150/// Counted semaphore. Currently Win32 only
151//
153 public:
155 LPSECURITY_ATTRIBUTES sa = nullptr);
161
162 private:
165
166 virtual void Release(); ///< Release this counted semaphore
167};
168
169//
170/// \class TEventSemaphore
171// ~~~~~ ~~~~~~~~~~~~~~~
172//
174 public:
175 TEventSemaphore(bool manualReset=false, bool initialState=false,
176 LPCTSTR name = nullptr, LPSECURITY_ATTRIBUTES sa = nullptr);
182
183 void Set();
184 void Reset();
185 void Pulse();
186
187
188 private:
189 TEventSemaphore(const TMutex&);
191
192 virtual void Release(); ///< Release this event semaphore
193
194};
195
196//
197/// \class TWaitableTimer
198// ~~~~~ ~~~~~~~~~~~~~~
199/// Encapsulation of Waitable Timer over Borland Classlib TSemaphore hierarchy
200//
201// Created by Marco Savegnago (msave) email: msave@tin.it
202//
203// additional typedef for old headers
204#if !defined(CreateWaitableTimer)
206#endif
207
208
210 public:
211 TWaitableTimer(bool manualReset=false, LPCTSTR name = nullptr, LPSECURITY_ATTRIBUTES sa = nullptr);
216 virtual ~TWaitableTimer();
217
218 bool Set(const TFileTime& duetime, int32 period=0,PTIMERAPCROUTINE compFunc=nullptr,
219 void* param=nullptr, bool resume=false);
220
221 bool Cancel();
222 virtual void Release();
223
224 private:
227};
228
229
230//
231/// \class TSemaphoreSet
232// ~~~~~ ~~~~~~~~~~~~~
233/// Semaphore object aggregator. Used to combine a set of semaphore objects so
234/// that they can be waited upon (locked) as a group. The lock can wait for any
235/// one, or all of them. The semaphore objects to be aggregated MUST live at
236/// least as long as this TSemaphoreSet, as it maintains pointers to them.
237//
239 public:
240 /// sems is initial array of sem ptrs, may be 0 to add sems later,
241 /// size is maximum sems to hold, -1 means count the 0-terminated array
242 /// Passing (0,-1) is not valid
243 //
244 TSemaphoreSet(const TSemaphore* sems[], int size = -1);
246
247 void Add(const TSemaphore& sem);
248 void Remove(const TSemaphore& sem);
249 int GetCount() const;
250 const TSemaphore* operator [](int index) const;
251
252 enum TWaitWhat { WaitAny = false, WaitAll = true };
253 enum { NoWait = 0, NoLimit = INFINITE };
254
256 public:
257 /// Assumes that set is not modified while locked
258 //
259 TLock(const TSemaphoreSet& set, TWaitWhat wait,
260 ulong timeOut = NoLimit, bool alertable = false);
262 ulong timeOut = NoLimit);
263 ~TLock();
264
265 bool WasAquired() const; ///< See if one or more was aquired
266 enum {
267 AllAquired = -1, ///< All semaphores were aquired
268 TimedOut = -2, ///< None aquired: timed out
269 IoComplete = -3, ///< IO complate alert
270 MsgWaiting = -4, ///< Msg waiting
271 };
272 int WhichAquired() const; ///< See which was aquired >=0, or enum
273
274 void Release(bool relinquish = false);
275
276 protected:
277 bool InitLock(int count, TWaitWhat wait, int index);
278
279 private:
280 const TSemaphoreSet* Set;
281 int Locked; ///< Which one got locked, or wait code
282 };
283 friend class TLock;
284
285 private:
286 void Release(int index = -1);
287
288 typedef TSemaphore* TSemaphorePtr;
289 typedef HANDLE THandle;
290
291 const TSemaphore** Sems; ///< Array of ptrs to semaphores, packed at head
292
293 int Size; ///< Size of array, i.e. maximum object count
294 int Count; ///< Count of objects currently in array
295};
296
297//
298/// \class TCriticalSection
299// ~~~~~ ~~~~~~~~~~~~~~~~
300/// Lightweight intra-process thread synchronization. Can only be used with
301/// other critical sections, and only within the same process.
302//
303/// TCriticalSection provides a system-independent interface to critical sections in
304/// threads. TCriticalSection objects can be used in conjunction with
305/// TCriticalSection::Lock objects to guarantee that only one thread can be
306/// executing any of the code sections protected by the lock at any given time.
307//
309 public:
312
313/// This nested class handles locking and unlocking critical sections.
314///
315/// Only one thread of execution will be allowed to execute the critical code inside
316/// function f at any one time.
317/// \code
318/// TCriticalSection LockF;
319/// void f()
320/// {
321/// TCriticalSection::Lock(LockF);
322///
323/// // critical processing here
324/// }
325/// \endcode
326 class TLock {
327 public:
328 TLock(const TCriticalSection&);
329 ~TLock();
330 private:
331 const TCriticalSection& CritSecObj;
332 };
333 friend class TLock;
334 typedef TLock Lock; ///< For compatibility with old T-less typename
335
336 private:
337 CRITICAL_SECTION CritSec;
338
341};
342
343//
344/// \class TMRSWSection
345/// Multiple Read, Single Write section
346//
348{
349public:
350
351 TMRSWSection();
353
355 {
356 public:
357
358 //
359 /// shared == true; allows multiple (read) access to the section.
360 /// shared == false; allows only exclusive (write) access to the section.
361 /// wait == false; will throw an exception if the lock can not be acquired immediately.
362 ///
363 /// TXLockFailure is thrown on failure.
364 //
365 TLock(TMRSWSection&, bool shared, bool wait = true);
366 ~TLock();
367
368 private:
369
371
372 TLock(const TLock&); ///< prohibited
373 const TLock& operator =(const TLock&); ///< prohibited
374 };
375
377
379 : public TXBase
380 {
381 public:
382
383 explicit TXLockFailure(const tstring& msg);
384 };
385
386 //
387 /// Dumps the current state of the section to the debugger output.
388 //
389 void Dump();
390
391private:
392
393 struct TPimpl;
394 TPimpl* Pimpl;
395
396 TMRSWSection(const TMRSWSection&); ///< prohibited
397 const TMRSWSection& operator =(const TMRSWSection&); ///< prohibited
398};
399
400//
401// class TSync::TLock
402// ~~~~~ ~~~~~~~~~~~
403/// \class TSync
404/// TSync provides a system-independent interface to build classes that act like
405/// monitors, i.e., classes in which only one member can execute on a particular
406/// instance at any one time. TSync uses TCriticalSection, so it is portable to
407/// all platforms that TCriticalSection has been ported to.
408///
409/// Example
410/// \code
411/// class ThreadSafe : private TSync
412/// {
413/// public:
414/// void f();
415/// void g();
416/// private:
417/// int i;
418/// };
419///
420/// void ThreadSafe::f()
421/// {
422/// TLock lock(this);
423/// if (i == 2)
424/// i = 3;
425/// }
426///
427/// void ThreadSafe::g()
428/// {
429/// TLock lock(this);
430/// if (i == 3)
431/// i = 2;
432/// }
433/// \endcode
434//
435class TSync
436{
437 protected:
438 TSync();
439 TSync(const TSync&);
440 const TSync& operator =(const TSync&);
441
442/// This nested class handles locking and unlocking critical sections.
444 {
445 public:
446 TLock(const TSync*);
447 private:
448 static const TCriticalSection& GetRef(const TSync*);
449 };
450 friend class TLock;
451 typedef TLock Lock; ///< For compatibility with old T-less typename
452
453 private:
454 TCriticalSection CritSec;
455};
456
457//
458/// \class TStaticSync
459// template <class T> class TStaticSync
460// template <class T> class TStaticSync::TLock
461// ~~~~~~~~ ~~~~~~~~~ ~~~~~ ~~~~~~~~~~~~~~~~~
462/// TStaticSync provides a system-independent interface to build sets of classes
463/// that act somewhat like monitors, i.e., classes in which only one member
464/// function can execute at any one time regardless of which instance it is
465/// being called on. TStaticSync uses TCriticalSection, so it is portable to all
466/// platforms that TCriticalSection has been ported to.
467//
468// TStaticSync Public Interface
469// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
470// None. TStaticSync can only be a base class.
471//
472// TStaticSync Protected Interface
473// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
474// TStaticSync<T>(const TStaticSync<T>&);
475// Copy constructor. Does not copy the
476// TCriticalSection object.
477//
478// const TStaticSync<T>& operator =(const TStaticSync<T>&);
479// Assignment operator. Does not copy the
480// TCriticalSection object.
481//
482// class TLock; Handles locking and unlocking of member
483// functions.
484//
485/// Example
486// ~~~~~~~
487/// \code
488/// class ThreadSafe : private TStaticSync<ThreadSafe>
489/// {
490/// public:
491/// void f();
492/// void g();
493/// private:
494/// static int i;
495/// };
496///
497/// void ThreadSafe::f()
498/// {
499/// TLock lock;
500/// if (i == 2)
501/// i = 3;
502/// }
503///
504/// void ThreadSafe::g()
505/// {
506/// TLock lock;
507/// if (i == 3)
508/// i = 2;
509/// }
510/// \endcode
511//
512template <class T> class TStaticSync{
513 protected:
514 TStaticSync();
517 ~TStaticSync();
518
520 {
521 public:
523 };
524 friend class TLock;
525 typedef TLock Lock; ///< For compatibility with old T-less typename
526
527 private:
528 static TCriticalSection* CritSec;
529 static ulong Count;
530};
531
532//
533/// \class TThread
534// ~~~~~ ~~~~~~~
535/// TThread provides a system-independent interface to threads. With
536/// suitable underlying implementations the same code can be used under
537/// OS/2 and Win32.
538///
539/// Example
540/// \code
541/// class TimerThread : public TThread
542/// {
543/// public:
544/// TimerThread() : Count(0) {}
545/// private:
546/// int Run();
547/// int Count;
548/// };
549///
550/// int TimerThread::Run()
551/// {
552/// // loop 10 times
553/// while (Count++ < 10) {
554/// Sleep(1000); // delay 1 second
555/// cout << "Iteration " << Count << endl;
556/// }
557/// return 0;
558/// }
559///
560/// int main()
561/// {
562/// TimerThread timer;
563/// timer.Start();
564/// Sleep(20000); // delay 20 seconds
565/// return 0;
566/// }
567/// \endcode
568///
569/// Internal States
570/// - Created: the object has been created but its thread has not been
571/// started. The only valid transition from this state is
572/// to Running, which happens on a call to Start(). In
573/// particular, a call to Suspend() or Resume() when the
574/// object is in this state is an error and will throw an
575/// exception.
576///
577/// - Running: the thread has been started successfully. There are two
578/// transitions from this state:
579///
580/// When the user calls Suspend() the object moves into
581/// the Suspended state.
582///
583/// When the thread exits the object moves into the
584/// Finished state.
585///
586/// Calling Resume() on an object that is in the Running
587/// state is an error and will throw an exception.
588///
589/// - Suspended: the thread has been suspended by the user. Subsequent
590/// calls to Suspend() nest, so there must be as many calls
591/// to Resume() as there were to Suspend() before the thread
592/// actually resumes execution.
593///
594/// - Finished: the thread has finished executing. There are no valid
595/// transitions out of this state. This is the only state
596/// from which it is legal to invoke the destructor for the
597/// object. Invoking the destructor when the object is in
598/// any other state is an error and will throw an exception.
599//
601{
602 public:
603 enum { NoLimit = INFINITE };
605
606 // Attach to the current running (often primary) thread
607 //
608 enum TCurrent {Current};
609 TThread(TCurrent);
610
611 /// Identifies the states that the class can be in.
613 {
614 Created, ///< The class has been created but the thread has not been started.
615 Running, ///< The thread is running.
616 Suspended, ///< The thread has been suspended.
617 Finished, ///< The thread has finished execution.
618 Invalid ///< The object is invalid. Currently this happens only when the operating system is unable to start the thread.
619 };
620
621 THandle Start();
622 ulong Suspend();
623 ulong Resume();
624 bool Sleep(long timeMS, bool alertable = false);
625
626 virtual void Terminate();
627 ulong WaitForExit(ulong timeout = NoLimit);
628 ulong TerminateAndWait(ulong timeout = NoLimit);
629
630 TStatus GetStatus() const;
631 uint32 GetExitCode() const;
632
634 Idle = THREAD_PRIORITY_IDLE, ///< -15
635 Lowest = THREAD_PRIORITY_LOWEST, ///< -2
636 BelowNormal = THREAD_PRIORITY_BELOW_NORMAL, ///< -1
637 Normal = THREAD_PRIORITY_NORMAL, ///< 0
638 AboveNormal = THREAD_PRIORITY_ABOVE_NORMAL, ///< 1
639 Highest = THREAD_PRIORITY_HIGHEST, ///< 2
640 TimeCritical = THREAD_PRIORITY_TIME_CRITICAL, ///< 15
641 };
642
643 int GetPriority() const;
644 int SetPriority(int); ///< Can pass a TPriority for simplicity
645
646 /// The error class that defines the objects that are thrown when an error occurs.
647 class TThreadError : public TXBase {
648 public:
649 /// Identifies the type of error that occurred.
651 SuspendBeforeRun, ///< The user called Suspend() on an object before calling Start().
652 ResumeBeforeRun, ///< The user called Resume() on an object before calling Start().
653 ResumeDuringRun, ///< The user called Resume() on a thread that was not Suspended.
654 SuspendAfterExit, ///< The user called Suspend() on an object whose thread had already exited.
655 ResumeAfterExit, ///< The user called Resume() on an object whose thread had already exited.
656 CreationFailure, ///< The operating system was unable to create the thread.
657 DestroyBeforeExit, ///< The object's destructor was invoked its thread had exited.
658 AssignError, ///< An attempt was made to assign to an object that was not in either the Created or the Finished state.
659 NoMTRuntime, ///< This usually results when you attempt to execute a multithread
660 ///< application which includes a module that has not been properly
661 ///< compiled with the appropriate multithread options.
662
663 };
665 TErrorType GetErrorType() const;
666
667 private:
669 static tstring MakeString(ErrorType type);
670 TErrorType Type;
671 friend class _OWLCLASS TThread;
672 };
673
674 typedef TStatus Status; ///< For compatibility with old T-less typenames
676
677 protected:
678 TThread(); ///< Create a thread. Derived class overrides Run()
679
680 // Copying a thread puts the target into the Created state
681 //
682 TThread(const TThread&);
683 const TThread& operator =(const TThread&);
684
685 virtual ~TThread();
686
687 bool ShouldTerminate() const;
688 void Exit(ulong code); ///< Alternative to returning from Run()
689
690 private:
691 virtual int Run();
692
693 TStatus CheckStatus() const;
694
695#if defined(BI_MULTI_THREAD_RTL)
696 static uint __stdcall Execute(void* thread);
697#else
698 static DWORD WINAPI Execute(void* thread);
699#endif
700
701 DWORD ThreadId;
702 THandle Handle;
703 mutable TStatus Stat;
704 bool TerminationRequested;
705 bool Attached;
706};
707
708#if defined(BI_MULTI_THREAD_RTL)
709
710//
711/// All classes used in local/tls process data have to be derived from here.
712//
713class TLocalObject : public TStandardAllocator {
714 public:
715 TLocalObject(){}
716 virtual ~TLocalObject(){}
717};
718
719//
720/// Exception class for TTlsContainer
721//
722class TXTlsContainer : public TXBase
723{
724public:
725
726 TXTlsContainer(const tstring& msg)
727 : TXBase(msg)
728 {}
729};
730
731//
732/// Thread-local storage container
733/// Wraps a used-defined type, and provides separate instances of this type to each client thread.
734/// The wrapped type must be default-constructible.
735///
736/// This class is normally used as a singleton.
737/// Note that the construction of a singleton of this class must be synchronized (serialized execution).
738/// A simple way to ensure this is to initialize it at program startup (single-threaded execution).
739///
740/// Usage:
741///
742/// \code
743/// TFoo& GetFoo() // Meyers Singleton ensures global-initialization-order independency.
744/// {
745/// static TTlsContainer<TFoo> c;
746/// return c.GetData(); // OWL5_COMPAT: return c; // implicit conversion
747/// }
748///
749/// TFoo& init = GetFoo(); // Ensures initialization during start-up (i.e. single-threaded and safe).
750/// \endcode
751//
752template <class T>
753class TTlsContainer
754{
755public:
756
758 : Index(::TlsAlloc())
759 {
760 TRACEX(OwlThread, 1, "Initializing " << TraceId(this));
761 if (Index == TLS_OUT_OF_INDEXES)
762 throw TXTlsContainer(_T("TLS_OUT_OF_INDEXES"));
763 }
764
765 //
766 /// Deallocates all the thread-level data created by the container.
767 //
769 {
770 TRACEX(OwlThread, 1, "Destructing " << TraceId(this));
771 ::TlsFree(Index);
772 TCriticalSection::TLock lock(GarbageSection);
773 std::for_each(Garbage.begin(), Garbage.end(), &Delete);
774 }
775
776 //
777 /// Returns 0 if data for the calling thread has not yet been allocated,
778 /// otherwise a pointer to previously initialized data is returned.
779 /// If the function returns 0, you can call Get to create an instance.
780 /// Can safely be called by many threads simultaneously without synchronization.
781 //
782 T* Query()
783 {return static_cast<T*>(::TlsGetValue(Index));}
784
785 //
786 /// Returns the thread-local instance of the data.
787 /// Can safely be called by many threads simultaneously without synchronization.
788 //
789 T& Get()
790 {
791 T* p = Query();
792 return p ? *p : Create();
793 }
794
795 //
796 /// Const overload
797 //
798 const T* Query() const
799 {return const_cast<TTlsContainer*>(this)->Query();}
800
801 //
802 /// Const overload
803 //
804 const T& Get() const
805 {return const_cast<TTlsContainer*>(this)->Get();}
806
807 // Old interface for backwards compatibility:
808
809#if defined(OWL5_COMPAT)
810
811 T* QueryData()
812 {return Query();}
813
814 T* GetData()
815 {return &Get();}
816
817 operator T*()
818 {return &Get();}
819
820 operator T&()
821 {return Get();}
822
823 T* operator->()
824 {return &Get();}
825
826#endif
827
828protected:
829
830 const DWORD Index;
831 TCriticalSection GarbageSection;
832 std::vector<T*> Garbage;
833
834 T& Create()
835 {
836 T* p = new T(); CHECK(p);
837 bool r = ::TlsSetValue(Index, p); CHECK(r); InUse(r);
838 TRACEX(OwlThread, 1, TraceId(this) << " created " << TraceId(p) << " for thread " << GetCurrentThreadId());
839
840 // Store the pointer for garbage collection later.
841 //
842 TCriticalSection::TLock lock(GarbageSection);
843 Garbage.push_back(p);
844 return *p;
845 }
846
847 static void Delete(T* p)
848 {
849 delete p;
850 TRACEX(OwlThread, 1, TraceType<TTlsContainer>() << " deleted " << TraceId(p));
851 }
852
853private:
854
855 TTlsContainer(const TTlsContainer&); // prohibit
856 TTlsContainer& operator =(const TTlsContainer&); // prohibit
857
858};
859
860//
861// The following TLS support classes are only available in OWL 5 compatibility mode.
862//
863
864#if defined(OWL5_COMPAT)
865
866//
867// Created by Yura Bidus
868// Multithread OWL internal support
869//
870
871class TLocalData: public TLocalObject {
873 public:
874 TLocalData(){}
875 virtual ~TLocalData(){}
876
877 TLocalObject* GetData(int index)
878 {
879 return index < (int)Data.Size() ? Data[index] : 0;
880 }
881
882 void SetData(int index, TLocalObject* obj);
883
884 int AddData(TLocalObject* data) { return Data.Add(data); }
885
886 protected:
888};
889
890class TTlsAllocator {
891 public:
892 TTlsAllocator() { index = ::TlsAlloc();}
893 ~TTlsAllocator() { ::TlsFree(index); }
894
895 bool IsOk() { return index != 0xFFFFFFFF; }
896 bool SetValue(void* value) { return ::TlsSetValue(index, value); }
897 void* GetValue() { return ::TlsGetValue(index); }
898
899 private:
900 uint32 index;
901};
902
903class TTlsDataManager : public TLocalObject {
905 public:
907 {
908 CHECK(Allocator.IsOk());
909 }
910 virtual ~TTlsDataManager()
911 {
912 TMRSWSection::TLock __lock(Lock,false,true);
913 Data.Flush(true);
914 }
915
916 TLocalObject* GetData(int index)
917 {
918 TLocalData* data = (TLocalData*)Allocator.GetValue();
919 return (data ? data : CreateData())->GetData(index);
920 }
921 void SetData(int index, TLocalObject* obj)
922 {
923 TLocalData* data = (TLocalData*)Allocator.GetValue();
924 (data ? data : CreateData())->SetData(index, obj);
925 }
927 {
928 TLocalData* data = (TLocalData*)Allocator.GetValue();
929 return (data ? data : CreateData())->AddData(obj);
930 }
931 protected:
933 {
934 TMRSWSection::TLock __lock(Lock,false,true);
935 TLocalData* data = new TLocalData();
936 Data.Add(data);
937 Allocator.SetValue(data);
938 return data;
939 }
940
941 protected: // global static data
943 TLocalDataArray Data;
944 TMRSWSection Lock;
945};
946
947template <class T> class TProcessContainer: public TLocalObject{
948 public:
949 TProcessContainer():Object(0){}
950 virtual ~TProcessContainer(){ delete Object;}
951
952 inline T* GetData()
953 {
954 if(!Object) // throw bad_alloc if error ??
955 Object = new T;
956 // check that T derived from TLocalObject
957 CHECK(dynamic_cast<TLocalObject*>(Object));
958 return Object;
959 }
960 inline T* QueryData() { return Object; }
961 inline operator T*() { return GetData(); }
962 inline operator T&() { return *GetData();}
963 inline T* operator->(){ return GetData(); }
964
965 protected:
966 T* Object;
967};
968
969#endif
970
971#endif
972
973/// @}
974
975#include <owl/posclass.h>
976
977//----------------------------------------------------------------------------
978// Inline implementation
979//
980
981
982//----------------------------------------
983// TSemaphore Win32
984
985//
990
991//
992inline TSemaphore::operator TSemaphore::THandle() const
993{
994 return Handle;
995}
996
997//
999:
1000 Sem(nullptr)
1001{
1003 Sem = &sem;
1004}
1005
1006//
1008{
1009 Release();
1010}
1011
1012//
1014{
1015 return Sem != nullptr;
1016}
1017
1018//
1019// Release but hang on to the semaphore
1020//
1022{
1023 if (Sem) {
1024 CONST_CAST(TSemaphore*,Sem)->Release();
1025 if (relinquish)
1026 Sem = nullptr;
1027 }
1028}
1029
1030//----------------------------------------
1031// TMutex Win32
1032
1033//
1034
1035/// Constructs a TMutex instance encapsulating a newly created named or unnamed
1036/// mutex object. The name parameter points to a null-terminated string specifying
1037/// the name of the mutex object. The sa parameter points to a SECURITY_ATTRIBUTES
1038/// structure that specifies the security attributes of the mutex object.
1039/// \note The mutex object is not owned.
1041 : Shared(false)
1042{
1043 Handle = ::CreateMutex(sa, false, name); // don't aquire now
1044 if (Handle && (GetLastError() == ERROR_ALREADY_EXISTS))
1045 Shared = true;
1046}
1047
1048//
1049/// String-aware overload
1050//
1052 : Shared(false)
1053{
1054 Handle = ::CreateMutex(sa, false, name.c_str()); // don't aquire now
1055 if (Handle && (GetLastError() == ERROR_ALREADY_EXISTS))
1056 Shared = true;
1057}
1058
1059//
1060/// Open an existing mutex. Fails if not there.
1061//
1062/// This form of the constructor instantiates a TMutex object that encapsulates an
1063/// existing named mutex object. The name parameter points to a null-terminated
1064/// string that names the mutex to be opened.
1066 : Shared(false)
1067{
1069 if (Handle)
1070 Shared = true;
1071}
1072
1073//
1074/// String-aware overlaod
1075//
1077 : Shared(false)
1078{
1079 Handle = ::OpenMutex(access, inherit, name.c_str());
1080 if (Handle)
1081 Shared = true;
1082}
1083
1084//
1085/// Constructs a Tmutex instance encapsulating a handle obtained by duplicating the
1086/// specified handle. The handle parameter is the source mutex object to be
1087/// duplicated.
1088/// \note The duplicated handle has the same access attributes as the source handle.
1089//
1091 : Shared(false)
1092{
1095 0, false, DUPLICATE_SAME_ACCESS))
1096 {
1097 Shared = true;
1098 }
1099}
1100
1101//
1102//
1103//
1104inline bool TMutex::IsShared()
1105{
1106 return Shared;
1107}
1108
1109//----------------------------------------
1110// TCountedSemaphore Win32
1111
1112//
1119
1120//
1121// String-aware overload
1122//
1127
1128//
1134
1135//
1136// String-aware overload
1137//
1142
1143//
1150
1151//----------------------------------------
1152// TEventSemaphore Win32
1153
1160
1161//
1162// String-aware overload
1163//
1168
1169//
1175
1176//
1177// String-aware overload
1178//
1183
1184//
1191
1193{
1194 ::SetEvent(*this);
1195}
1196
1198{
1199 ::ResetEvent(*this);
1200}
1201
1203{
1204 ::PulseEvent(*this);
1205}
1206
1207//----------------------------------------
1208// TWaitableTimer Win NT or Win98
1214
1219//----------------------------------------
1220// TSemaphoreSet Win32
1221
1222inline int TSemaphoreSet::GetCount() const
1223{
1224 return Count;
1225}
1226
1227inline const TSemaphore* TSemaphoreSet::operator [](int index) const
1228{
1229 return (index >= 0 && index < Count) ? Sems[index] : nullptr;
1230}
1231
1232//
1234{
1235 return Set != nullptr;
1236}
1237
1238//
1239/// Which one was locked, all locked code, or lock fail code
1240//
1242{
1243 return Locked;
1244}
1245
1246
1247//----------------------------------------------------------------------------
1248// TCriticalSection Win32
1249//
1250
1251//
1252/// Use system call to initialize the CRITICAL_SECTION object.
1253//
1258
1259//
1260/// Use system call to destroy the CRITICAL_SECTION object.
1261//
1266
1267//
1268/// Use system call to lock the CRITICAL_SECTION object.
1269//
1270/// Requests a lock on the TCriticalSection object. If no other Lock object holds a
1271/// lock on that TCriticalSection object, the lock is allowed and execution
1272/// continues. If another Lock object holds a lock on that object, the requesting
1273/// thread is blocked until the lock is released.
1274//
1276:
1277 CritSecObj(sec)
1278{
1279 ::EnterCriticalSection(CONST_CAST(CRITICAL_SECTION*,&CritSecObj.CritSec));
1280}
1281
1282//
1283/// Use system call to unlock the CRITICAL_SECTION object.
1284//
1289
1290//
1291// TCriticalSection OS2
1292//
1293
1294
1295//----------------------------------------------------------------------------
1296
1297//
1298/// Default constructor.
1300{
1301}
1302
1303//
1304/// Copy constructor does not copy the TCriticalSection object,
1305/// since the new object is not being used in any of its own
1306/// member functions. This means that the new object must start
1307/// in an unlocked state.
1308//
1309inline TSync::TSync(const TSync&)
1310{
1311}
1312
1313//
1314/// Does not copy the TCriticalSection object, since the new object is not
1315/// being used in any of its own member functions.
1316/// This means that the new object must start in an unlocked state.
1317//
1318inline const TSync& TSync::operator =(const TSync&)
1319{
1320 return *this;
1321}
1322
1323//
1324/// Locks the TCriticalSection object in the TSync object.
1325//
1326/// Requests a lock on the critical section of the TSync object pointed to by s. If
1327/// no other Lock object holds a lock on that TCriticalSection object, the lock is
1328/// allowed and execution continues. If another Lock object holds a lock on that
1329/// object, the requesting thread is blocked until the lock is released.
1330inline TSync::TLock::TLock(const TSync* sync)
1331:
1332 TCriticalSection::TLock(GetRef(sync))
1333{
1334}
1335
1336//
1337// Returns a reference to the TCriticalSection object contained in the TSync
1338// object.
1339//
1340// In the diagnostic version, checks for a null pointer.
1341//
1342inline const TCriticalSection& TSync::TLock::GetRef(const TSync* sync)
1343{
1344 CHECK(sync != 0);
1345 return sync->CritSec;
1346}
1347
1348//----------------------------------------------------------------------------
1349
1350//
1351// Instantiate the data members.
1352//
1353template <class T> TCriticalSection* TStaticSync<T>::CritSec;
1354template <class T> ulong TStaticSync<T>::Count;
1355
1356//
1357// If this is the first TStaticSync<T> object to be constructed, create the
1358// semaphore.
1359//
1360// The copy constructor only has to increment the count, since there will
1361// already be at least one TStaticSync<T> object, namely, the one being copied.
1362//
1363template <class T> inline TStaticSync<T>::TStaticSync()
1364{
1365 if (Count++ == 0)
1366 CritSec = new TCriticalSection;
1367}
1368
1369template <class T> inline TStaticSync<T>::TStaticSync(const TStaticSync<T>&)
1370{
1371 Count++;
1372}
1373
1374//
1375// TStaticSync<T> assignment operator
1376//
1377template <class T>
1379{
1380 return *this;
1381}
1382
1383//
1384// If this is the only remaining TStaticSync<T> object, destroy the semaphore.
1385//
1386template <class T> inline TStaticSync<T>::~TStaticSync()
1387{
1388 if (--Count == 0)
1389 delete CritSec;
1390}
1391
1392//----------------------------------------------------------------------------
1393
1394//
1395/// Suspends execution of the current thread for the number of milliseconds
1396/// specified by the timeMS parameter. If the alertable parameter is set to true,
1397/// the function resumes execution upon I/O completion.
1398///
1399/// The function returns true if its wakeup is due to I/O completion.
1400//
1401inline bool TThread::Sleep(long timeMS, bool alertable)
1402{
1403 return ::SleepEx(timeMS, alertable) == WAIT_IO_COMPLETION;
1404}
1405
1406//
1407/// Gets the current status of the thread.
1408//
1409/// If the thread is marked as Running it may have terminated without our
1410/// knowing it, so we have to check.
1411//
1413{
1414 if (Stat == Running)
1415 Stat = CheckStatus();
1416 return Stat;
1417}
1418
1419//
1421{
1422 uint32 code;
1423 ::GetExitCodeThread(Handle, static_cast<DWORD*>(&code));
1424 return code;
1425}
1426
1427//
1428/// Gets the thread priority. Under Win32, this is a direct call to the operating
1429/// system. See the description of TPriority for possible values.
1430//
1431inline int TThread::GetPriority() const
1432{
1433 return ::GetThreadPriority(Handle);
1434}
1435
1436//
1437/// Returns a bool value to indicate that Terminate() or TerminateAndWait()
1438/// has been called. If this capability is being used, the thread should call
1439/// ShouldTerminate() regularly, and if it returns a non-zero value the thread
1440/// finish its processing and exit.
1441//
1442inline bool TThread::ShouldTerminate() const
1443{
1444 return TerminationRequested;
1445}
1446
1447/// Returns a code indicating the type of error that occurred.
1452
1453} // OWL namespace
1454
1455#endif // OWL_THREAD_H
#define CHECK(condition)
Definition checks.h:239
#define DIAG_DECLARE_GROUP(group)
Definition checks.h:404
#define TRACEX(group, level, message)
Definition checks.h:263
Counted semaphore. Currently Win32 only.
Definition thread.h:152
TCountedSemaphore(int initialCount, int maxCount, LPCTSTR name=nullptr, LPSECURITY_ATTRIBUTES sa=nullptr)
Definition thread.h:1113
This nested class handles locking and unlocking critical sections.
Definition thread.h:326
TLock(const TCriticalSection &)
Use system call to lock the CRITICAL_SECTION object.
Definition thread.h:1275
~TLock()
Use system call to unlock the CRITICAL_SECTION object.
Definition thread.h:1285
Lightweight intra-process thread synchronization.
Definition thread.h:308
TCriticalSection()
Use system call to initialize the CRITICAL_SECTION object.
Definition thread.h:1254
TLock Lock
For compatibility with old T-less typename.
Definition thread.h:334
friend class TLock
Definition thread.h:333
~TCriticalSection()
Use system call to destroy the CRITICAL_SECTION object.
Definition thread.h:1262
TEventSemaphore(bool manualReset=false, bool initialState=false, LPCTSTR name=nullptr, LPSECURITY_ATTRIBUTES sa=nullptr)
Definition thread.h:1154
TFileTime is a class derived from the structure FILETIME.
Definition wsyscls.h:362
Multiple Read, Single Write section.
Definition thread.h:348
Mutual-exclusive semaphore.
Definition thread.h:121
TMutex(LPCTSTR name=nullptr, LPSECURITY_ATTRIBUTES sa=nullptr)
Constructs a TMutex instance encapsulating a newly created named or unnamed mutex object.
Definition thread.h:1040
TLock Lock
For compatibility with old T-less typename.
Definition thread.h:129
bool IsShared()
If another mutex with the same name existed when this mutex was created, then another handle to the o...
Definition thread.h:1104
TLock(const TSemaphore &, ulong timeOut=NoLimit, bool alertable=false)
Definition thread.h:998
void Release(bool relinquish=false)
Release lock early & relinquish, i.e.
Definition thread.h:1021
bool WasAquired() const
See if really aquired, or just timed-out.
Definition thread.h:1013
Base class for handle-based thread synchronization classes, TMutex, TCountedSemaphore and TEventSemap...
Definition thread.h:65
THandle Handle
Derived class must initialize.
Definition thread.h:95
HANDLE THandle
Definition thread.h:70
virtual void Release()=0
Derived class must provide release.
virtual ~TSemaphore()
Definition thread.h:986
int WhichAquired() const
See which was aquired >=0, or enum.
Definition thread.h:1241
bool WasAquired() const
See if one or more was aquired.
Definition thread.h:1233
Semaphore object aggregator.
Definition thread.h:238
int GetCount() const
Definition thread.h:1222
const TSemaphore * operator[](int index) const
Definition thread.h:1227
Provides class-specific operator new and operator delete that simply call the global operator new and...
Definition template.h:37
TStaticSync provides a system-independent interface to build sets of classes that act somewhat like m...
Definition thread.h:512
const TStaticSync< T > & operator=(const TStaticSync< T > &)
Definition thread.h:1378
TLock Lock
For compatibility with old T-less typename.
Definition thread.h:525
This nested class handles locking and unlocking critical sections.
Definition thread.h:444
TLock(const TSync *)
Locks the TCriticalSection object in the TSync object.
Definition thread.h:1330
TSync provides a system-independent interface to build classes that act like monitors,...
Definition thread.h:436
const TSync & operator=(const TSync &)
Does not copy the TCriticalSection object, since the new object is not being used in any of its own m...
Definition thread.h:1318
TSync()
Default constructor.
Definition thread.h:1299
TLock Lock
For compatibility with old T-less typename.
Definition thread.h:451
friend class TLock
Definition thread.h:450
The error class that defines the objects that are thrown when an error occurs.
Definition thread.h:647
TErrorType
Identifies the type of error that occurred.
Definition thread.h:650
@ SuspendBeforeRun
The user called Suspend() on an object before calling Start().
Definition thread.h:651
@ AssignError
An attempt was made to assign to an object that was not in either the Created or the Finished state.
Definition thread.h:658
@ ResumeBeforeRun
The user called Resume() on an object before calling Start().
Definition thread.h:652
@ DestroyBeforeExit
The object's destructor was invoked its thread had exited.
Definition thread.h:657
@ ResumeDuringRun
The user called Resume() on a thread that was not Suspended.
Definition thread.h:653
@ SuspendAfterExit
The user called Suspend() on an object whose thread had already exited.
Definition thread.h:654
@ CreationFailure
The operating system was unable to create the thread.
Definition thread.h:656
@ ResumeAfterExit
The user called Resume() on an object whose thread had already exited.
Definition thread.h:655
TErrorType GetErrorType() const
Returns a code indicating the type of error that occurred.
Definition thread.h:1448
TThread provides a system-independent interface to threads.
Definition thread.h:601
uint32 GetExitCode() const
Definition thread.h:1420
TThreadError ThreadError
Definition thread.h:675
TStatus GetStatus() const
Gets the current status of the thread.
Definition thread.h:1412
int GetPriority() const
Gets the thread priority.
Definition thread.h:1431
TStatus Status
For compatibility with old T-less typenames.
Definition thread.h:674
bool ShouldTerminate() const
Returns a bool value to indicate that Terminate() or TerminateAndWait() has been called.
Definition thread.h:1442
HANDLE THandle
Definition thread.h:604
bool Sleep(long timeMS, bool alertable=false)
Suspends execution of the current thread for the number of milliseconds specified by the timeMS param...
Definition thread.h:1401
TStatus
Identifies the states that the class can be in.
Definition thread.h:613
@ Created
The class has been created but the thread has not been started.
Definition thread.h:614
@ Finished
The thread has finished execution.
Definition thread.h:617
@ Suspended
The thread has been suspended.
Definition thread.h:616
@ Running
The thread is running.
Definition thread.h:615
virtual ~TWaitableTimer()
Definition thread.h:1215
TWaitableTimer(bool manualReset=false, LPCTSTR name=nullptr, LPSECURITY_ATTRIBUTES sa=nullptr)
Definition thread.cpp:64
Derived from xmsg, TXBase is the base class for ObjectWindows and ObjectComponents exception-handling...
Definition exbase.h:41
#define _T(x)
Definition cygwin.h:51
Base exception support for framework exceptions.
VOID(APIENTRY * PTIMERAPCROUTINE)(LPVOID lpArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue)
Encapsulation of Waitable Timer over Borland Classlib TSemaphore hierarchy.
Definition thread.h:205
Object Windows Library (OWLNext Core)
Definition animctrl.h:22
signed long int32
Definition number.h:30
unsigned long ulong
Definition number.h:26
const tchar * Section
Definition rcntfile.cpp:45
unsigned long uint32
Definition number.h:34
void InUse(const T &arg)
Handy utility to avoid compiler warnings about unused parameters.
Definition defs.h:299
std::string tstring
Definition defs.h:79
General definitions used by all ObjectWindows programs.
#define CONST_CAST(targetType, object)
Definition defs.h:273
#define _OWLCLASS
Definition defs.h:338
Definition of container classes used and made available by OWL.
Classes for window system structure and type encapsulation.