OWLNext    7.0
Borland's Object Windows Library for the modern age
Loading...
Searching...
No Matches
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.