1 /*
2 *
3 * C++ Portable Types Library (PTypes)
4 * Version 2.1.1 Released 27-Jun-2007
5 *
6 * Copyright (C) 2001-2007 Hovik Melikyan
7 *
8 * http://www.melikyan.com/ptypes/
9 *
10 */
11
12 #ifdef WIN32
13 # include <process.h>
14 #else
15 # include <pthread.h>
16 #endif
17
18 #include "pasync.h"
19
20
21 PTYPES_BEGIN
22
23
thread(bool iautofree)24 thread::thread(bool iautofree)
25 :
26 #ifdef WIN32
27 id(0),
28 #endif
29 handle(0), autofree(iautofree),
30 running(0), signaled(0), finished(0), freed(0),
31 reserved(0), relaxsem(0)
32 {
33 }
34
35
~thread()36 thread::~thread()
37 {
38 if (pexchange(&freed, 1) != 0)
39 return;
40 #ifdef WIN32
41 if (autofree)
42 // MSDN states this is not necessary, however, without closing
43 // the handle debuggers show an obvious handle leak here
44 CloseHandle(handle);
45 #else
46 // though we require non-autofree threads to always call waitfor(),
47 // the statement below is provided to cleanup thread resources even
48 // if waitfor() was not called.
49 if (!autofree && running)
50 pthread_detach(handle);
51 #endif
52 }
53
54
signal()55 void thread::signal()
56 {
57 if (pexchange(&signaled, 1) == 0)
58 relaxsem.post();
59 }
60
61
waitfor()62 void thread::waitfor()
63 {
64 if (pexchange(&freed, 1) != 0)
65 return;
66 if (pthrequal(get_id()))
67 fatal(CRIT_FIRST + 47, "Can not waitfor() on myself");
68 if (autofree)
69 fatal(CRIT_FIRST + 48, "Can not waitfor() on an autofree thread");
70 #ifdef WIN32
71 WaitForSingleObject(handle, INFINITE);
72 CloseHandle(handle);
73 #else
74 pthread_join(handle, nil);
75 // detaching after 'join' is not required (or even do harm on some systems)
76 // except for HPUX. we don't support HPUX yet.
77 // pthread_detach(handle);
78 #endif
79 handle = 0;
80 }
81
82
83 #ifdef WIN32
_threadproc(void * arg)84 unsigned _stdcall _threadproc(void* arg)
85 {
86 #else
87 void* _threadproc(void* arg)
88 {
89 #endif
90 thread* thr = (thread*)arg;
91 #ifndef WIN32
92 if (thr->autofree)
93 // start() does not assign the handle for autofree threads
94 thr->handle = pthread_self();
95 #endif
96 try
97 {
98 thr->execute();
99 }
100 catch(exception*)
101 {
102 _threadepilog(thr);
103 throw;
104 }
105 _threadepilog(thr);
106 return 0;
107 }
108
109
110 void _threadepilog(thread* thr)
111 {
112 try
113 {
114 thr->cleanup();
115 }
116 catch(exception* e)
117 {
118 delete e;
119 }
120 pexchange(&thr->finished, 1);
121 if (thr->autofree)
122 delete thr;
123 }
124
125
126 void thread::start()
127 {
128 if (pexchange(&running, 1) == 0)
129 {
130 #ifdef WIN32
131 handle = (HANDLE)_beginthreadex(nil, 0, _threadproc, this, 0, &id);
132 if (handle == 0)
133 fatal(CRIT_FIRST + 40, "CreateThread() failed");
134 #else
135 pthread_t temp_handle;
136 pthread_attr_t attr;
137 pthread_attr_init(&attr);
138 pthread_attr_setdetachstate(&attr,
139 autofree ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE);
140 if (pthread_create(autofree ? &temp_handle : &handle,
141 &attr, _threadproc, this) != 0)
142 fatal(CRIT_FIRST + 40, "pthread_create() failed");
143 pthread_attr_destroy(&attr);
144 #endif
145 }
146 }
147
148
149 void thread::cleanup()
150 {
151 }
152
153
154 PTYPES_END
155