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 (7 years, 4 months ago) by gpertea
File size: 8998 byte(s)
Log Message:
adding refactored TinyThread++ code

Line User Rev File contents
1 gpertea 156 /*
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     */