ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/gclib/gclib/GThreads.cpp
Revision: 156
Committed: Fri Jan 27 18:29:55 2012 UTC (12 years, 7 months ago) by gpertea
File size: 8998 byte(s)
Log Message:
adding refactored TinyThread++ code

Line File contents
1 /*
2 Copyright (c) 2010 Marcus Geelnard
3 (with minor modifications by Geo Pertea)
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19
20 3. This notice may not be removed or altered from any source
21 distribution.
22 */
23
24 #include "GThreads.h"
25
26 #if defined(_GTHREADS_POSIX_)
27 #include <unistd.h>
28 // #include <map>
29 #elif defined(_GTHREADS_WIN32_)
30 #include <process.h>
31 #endif
32
33
34 //namespace tthread {
35
36 //------------------------------------------------------------------------------
37 // condition_variable
38 //------------------------------------------------------------------------------
39 // NOTE 1: The Win32 implementation of the condition_variable class is based on
40 // the corresponding implementation in GLFW, which in turn is based on a
41 // description by Douglas C. Schmidt and Irfan Pyarali:
42 // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
43 //
44 // NOTE 2: Windows Vista actually has native support for condition variables
45 // (InitializeConditionVariable, WakeConditionVariable, etc), but we want to
46 // be portable with pre-Vista Windows versions, so TinyThread++ does not use
47 // Vista condition variables.
48 //------------------------------------------------------------------------------
49
50 #if defined(_GTHREADS_WIN32_)
51 #define _CONDITION_EVENT_ONE 0
52 #define _CONDITION_EVENT_ALL 1
53 #endif
54
55
56 int GThread::tcounter=0;
57 int GThread::num_created=0;
58
59 #if defined(_GTHREADS_WIN32_)
60 GConditionVar::GConditionVar() : mWaitersCount(0)
61 {
62 mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL);
63 mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL);
64 InitializeCriticalSection(&mWaitersCountLock);
65 }
66 #endif
67
68 #if defined(_GTHREADS_WIN32_)
69 GConditionVar::~GConditionVar()
70 {
71 CloseHandle(mEvents[_CONDITION_EVENT_ONE]);
72 CloseHandle(mEvents[_CONDITION_EVENT_ALL]);
73 DeleteCriticalSection(&mWaitersCountLock);
74 }
75 #endif
76
77 #if defined(_GTHREADS_WIN32_)
78 void GConditionVar::_wait()
79 {
80 // Wait for either event to become signaled due to notify_one() or
81 // notify_all() being called
82 int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE);
83
84 // Check if we are the last waiter
85 EnterCriticalSection(&mWaitersCountLock);
86 -- mWaitersCount;
87 bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) &&
88 (mWaitersCount == 0);
89 LeaveCriticalSection(&mWaitersCountLock);
90
91 // If we are the last waiter to be notified to stop waiting, reset the event
92 if(lastWaiter)
93 ResetEvent(mEvents[_CONDITION_EVENT_ALL]);
94 }
95 #endif
96
97 #if defined(_GTHREADS_WIN32_)
98 void GConditionVar::notify_one()
99 {
100 // Are there any waiters?
101 EnterCriticalSection(&mWaitersCountLock);
102 bool haveWaiters = (mWaitersCount > 0);
103 LeaveCriticalSection(&mWaitersCountLock);
104
105 // If we have any waiting threads, send them a signal
106 if(haveWaiters)
107 SetEvent(mEvents[_CONDITION_EVENT_ONE]);
108 }
109 #endif
110
111 #if defined(_GTHREADS_WIN32_)
112 void GConditionVar::notify_all()
113 {
114 // Are there any waiters?
115 EnterCriticalSection(&mWaitersCountLock);
116 bool haveWaiters = (mWaitersCount > 0);
117 LeaveCriticalSection(&mWaitersCountLock);
118
119 // If we have any waiting threads, send them a signal
120 if(haveWaiters)
121 SetEvent(mEvents[_CONDITION_EVENT_ALL]);
122 }
123 #endif
124
125
126 //------------------------------------------------------------------------------
127 // POSIX pthread_t to unique thread::id mapping logic.
128 // Note: Here we use a global thread safe std::map to convert instances of
129 // pthread_t to small thread identifier numbers (unique within one process).
130 // This method should be portable across different POSIX implementations.
131 //------------------------------------------------------------------------------
132 /*
133
134 #if defined(_GTHREADS_POSIX_)
135 static thread::id _pthread_t_to_ID(const pthread_t &aHandle)
136 {
137 static mutex idMapLock;
138 static std::map<pthread_t, unsigned long int> idMap;
139 static unsigned long int idCount(1);
140
141 lock_guard<mutex> guard(idMapLock);
142 if(idMap.find(aHandle) == idMap.end())
143 idMap[aHandle] = idCount ++;
144 return thread::id(idMap[aHandle]);
145 }
146 #endif // _GTHREADS_POSIX_
147 */
148
149 void GThread::update_counter(int inc, GThread* t_update) {
150 static GMutex counterLock;
151 GLockGuard<GMutex> guard(counterLock);
152 if (inc==1) { //joinable thread creation
153 GThread::num_created++;
154 t_update->mId = GThread::num_created;
155 }
156 GThread::tcounter+=inc;
157 if (t_update!=NULL && inc<0)
158 t_update->mId=0; // thread terminated
159
160 }
161
162
163 //------------------------------------------------------------------------------
164 // thread
165 //------------------------------------------------------------------------------
166
167 /// Information to pass to the new thread (what to run).
168 struct _thread_start_info {
169 void (*mFunction)(void *, GThread*); ///< Pointer to the function to be executed.
170 void * mArg; ///< Function argument for the thread function.
171 GThread * mThread; ///< Pointer to the thread object.
172 };
173
174 // Thread wrapper function.
175 #if defined(_GTHREADS_WIN32_)
176 unsigned WINAPI GThread::wrapper_function(void * aArg)
177 #elif defined(_GTHREADS_POSIX_)
178 void * GThread::wrapper_function(void * aArg)
179 #endif
180 {
181 // Get thread startup information
182 _thread_start_info * ti = (_thread_start_info *) aArg;
183
184 /*
185 try
186 {
187 // Call the actual client thread function
188 ti->mFunction(ti->mArg, ti->mThread);
189 }
190 catch(...)
191 {
192 // Uncaught exceptions will terminate the application (default behavior
193 // according to the C++0x draft)
194 std::terminate();
195 }
196 */
197 ti->mFunction(ti->mArg, ti->mThread);
198
199 // The thread is no longer executing
200 GLockGuard<GMutex> guard(ti->mThread->mDataMutex);
201 ti->mThread->mNotAThread = true;
202 GThread::update_counter(-1, ti->mThread);
203 // The thread is responsible for freeing the startup information
204 delete ti;
205
206 return 0;
207 }
208
209 GThread::GThread(void (*aFunction)(void *, GThread*), void * aArg)
210 {
211 // Serialize access to this thread structure
212 GLockGuard<GMutex> guard(mDataMutex);
213
214 // Fill out the thread startup information (passed to the thread wrapper,
215 // which will eventually free it)
216 _thread_start_info * ti = new _thread_start_info;
217 ti->mFunction = aFunction;
218 ti->mArg = aArg;
219 ti->mThread = this;
220
221 // The thread is now alive
222 mNotAThread = false;
223
224 // Create the thread
225 #if defined(_GTHREADS_WIN32_)
226 mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID);
227 #elif defined(_GTHREADS_POSIX_)
228 if(pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0)
229 mHandle = 0;
230 #endif
231
232 // Did we fail to create the thread?
233 if(!mHandle)
234 {
235 mNotAThread = true;
236 delete ti;
237 }
238 else GThread::update_counter(1, this);
239 }
240
241 GThread::~GThread()
242 {
243 if(joinable()) {
244 //std::terminate();
245 GThread::update_counter(-1, this);
246 }
247 }
248
249 void GThread::join()
250 {
251 if(joinable())
252 {
253 #if defined(_GTHREADS_WIN32_)
254 WaitForSingleObject(mHandle, INFINITE);
255 #elif defined(_GTHREADS_POSIX_)
256 pthread_join(mHandle, NULL);
257 #endif
258 }
259 }
260
261 void GThread::wait_all() {
262 while (GThread::num_running()>0)
263 this_thread::sleep_for(chrono::milliseconds(2));
264 }
265
266
267 bool GThread::joinable() const
268 {
269 mDataMutex.lock();
270 bool result = !mNotAThread;
271 mDataMutex.unlock();
272 return result;
273 }
274
275 int GThread::get_id() const
276 {
277 if(!joinable())
278 //return id();
279 return 0; //FIXME
280 else
281 return mId;
282 /*
283 #if defined(_GTHREADS_WIN32_)
284 return id((unsigned long int) mWin32ThreadID);
285 #elif defined(_GTHREADS_POSIX_)
286 return _pthread_t_to_ID(mHandle);
287 #endif
288 */
289 }
290
291 unsigned GThread::hardware_concurrency()
292 {
293 #if defined(_GTHREADS_WIN32_)
294 SYSTEM_INFO si;
295 GetSystemInfo(&si);
296 return (int) si.dwNumberOfProcessors;
297 #elif defined(_SC_NPROCESSORS_ONLN)
298 return (int) sysconf(_SC_NPROCESSORS_ONLN);
299 #elif defined(_SC_NPROC_ONLN)
300 return (int) sysconf(_SC_NPROC_ONLN);
301 #else
302 // The standard requires this function to return zero if the number of
303 // hardware cores could not be determined.
304 return 0;
305 #endif
306 }
307
308
309 //------------------------------------------------------------------------------
310 // this_thread
311 //------------------------------------------------------------------------------
312 /*
313 int this_thread::get_id()
314 {
315 #if defined(_GTHREADS_WIN32_)
316 return thread::id((unsigned long int) GetCurrentThreadId());
317 #elif defined(_GTHREADS_POSIX_)
318 return _pthread_t_to_ID(pthread_self());
319 #endif
320 }
321 */