Release of synfigstudio 0.61.09 version. *****
[synfig.git] / ETL / tags / stable / ETL / _thread.h
1 /*! ========================================================================
2 ** Extended Template and Library
3 ** Thread Abstraction Class Implementation
4 ** $Id$
5 **
6 ** Copyright (c) 2002 Robert B. Quattlebaum Jr.
7 **
8 ** This package is free software; you can redistribute it and/or
9 ** modify it under the terms of the GNU General Public License as
10 ** published by the Free Software Foundation; either version 2 of
11 ** the License, or (at your option) any later version.
12 **
13 ** This package is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 ** General Public License for more details.
17 **
18 ** === N O T E S ===========================================================
19 **
20 ** This is an internal header file, included by other ETL headers.
21 ** You should not attempt to use it directly.
22 **
23 ** ========================================================================= */
24
25 /* === S T A R T =========================================================== */
26
27 #ifndef __ETL__THREAD_H_
28 #define __ETL__THREAD_H_
29
30 /* === H E A D E R S ======================================================= */
31
32 #define __USE_GNU
33
34 #ifdef HAVE_PTHREAD_H
35 # include <pthread.h>
36 #endif
37
38 #ifdef HAVE_SCHED_H
39 # include <sched.h>
40 #endif
41
42 #ifdef HAVE_CREATETHREAD
43 # include <windows.h>
44 #endif
45
46 /* === M A C R O S ========================================================= */
47
48 #if ( defined (HAVE_PTHREAD_CREATE) || defined (HAVE_CLONE) || defined (HAVE_CREATETHREAD) ) && !defined (NO_THREADS)
49 # define CALLISTO_THREADS
50 #endif
51
52 #define THREAD_ENTRYPOINT
53
54 /* === C L A S S E S & S T R U C T S ======================================= */
55
56 #if defined(CALLISTO_THREADS) && defined(HAVE_PTHREAD_CREATE)
57 static inline void Yield(void)
58 {
59         sched_yield();
60         pthread_testcancel();
61 }
62 #else
63 #ifdef Yield
64         #undef Yield
65 #endif
66 inline void Yield(void) { }
67 #endif
68
69 #ifdef CALLISTO_THREADS
70
71 #ifdef HAVE_PTHREAD_CREATE
72
73 class Thread
74 {
75 public:
76         typedef void* entrypoint_return;
77 private:
78
79         pthread_t thread;
80         int *references;
81         entrypoint_return (*entrypoint)(void *);
82         void *context;
83 public:
84         Thread(void *(*ep)(void *)=NULL,void *context=NULL):
85                 references(NULL),entrypoint(ep),context(context) { }
86         Thread(const Thread &t)
87         {
88                 thread=t.thread;
89                 references=t.references;
90                 entrypoint=t.entrypoint;
91                 context=t.context;
92                 if(references)
93                         (*references)++;
94         }
95         const Thread &operator=(const Thread &rhs)
96         {
97                 if(references)
98                 {
99                         (*references)--;
100                         if(*references==0)
101                                 stop();
102                 }
103                 thread=rhs.thread;
104                 references=rhs.references;
105                 entrypoint=rhs.entrypoint;
106                 context=rhs.context;
107                 if(references)
108                         (*references)++;
109                 return *this;
110         }
111
112         void start(void)
113         {
114                 references = new int;
115                 *references = 1;
116                 pthread_create(&thread,NULL,entrypoint,context);
117 //              pthread_detach(thread);
118         }
119
120         void stop(void)
121         {
122                 delete references;
123                 references=NULL;
124                 void *exit_status;
125                 pthread_cancel(thread);
126                 pthread_join(thread,&exit_status);
127         }
128
129         static void TestStop()
130         {
131                 pthread_testcancel();
132         }
133
134         static void SyncStop()
135         {
136                 int i;
137                 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,&i);
138         }
139
140         static void AsyncStop()
141         {
142                 int i;
143                 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,&i);
144         }
145
146         ~Thread()
147         {
148                 if(references)
149                 {
150                         (*references)--;
151                         if(*references==0)
152                                 stop();
153                 }
154         }
155 };
156
157 class Mutex
158 {
159         pthread_mutex_t mutex;
160         pthread_t locker;
161         int depth;
162 public:
163
164         Mutex()
165         {
166                 pthread_mutexattr_t attr;
167                 pthread_mutexattr_init(&attr);
168                 //#ifdef PTHREAD_PRIO_INHERIT
169                 //pthread_mutexattr_setprioceiling(&attr,PTHREAD_PRIO_INHERIT);
170                 //#endif
171                 #ifdef PTHREAD_MUTEX_RECURSIVE
172                 pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
173                 #endif
174                 pthread_mutex_init(&mutex,&attr);
175                 pthread_mutexattr_destroy(&attr);
176                 locker=0;
177                 depth=0;
178         }
179
180         ~Mutex()
181         { pthread_mutex_destroy(&mutex); }
182
183         void Lock(void)
184         {
185                 if(!locker || locker!=pthread_self())
186                 {
187                         pthread_mutex_lock(&mutex);
188                         locker=pthread_self();
189                         depth=0;
190                         return;
191                 }
192                 depth++;
193         }
194
195         bool TryLock(void)
196         { return !(bool) pthread_mutex_trylock(&mutex); }
197
198         void UnLock(void)
199         {
200                 if(depth)
201                 {
202                         depth--;
203                         return;
204                 }
205                 pthread_mutex_unlock(&mutex);
206                 locker=0;
207         }
208 };
209
210 #ifdef HAVE_PTHREAD_RW_LOCK_INIT
211 class ReadWriteLock
212 {
213         pthread_rwlock_t rwlock;
214 public:
215
216         ReadWriteLock()
217         { pthread_rwlock_init(&rwlock,NULL); }
218
219         ~ReadWriteLock()
220         { pthread_rwlock_destroy(&rwlock); }
221
222         void LockRead(void)
223         { pthread_rwlock_rdlock(&rwlock); }
224
225         void LockWrite(void)
226         { pthread_rwlock_wrlock(&rwlock); }
227
228         bool TryLockRead(void)
229         { return !(bool)pthread_rwlock_tryrdlock(&rwlock); }
230
231         bool TryLockWrite(void)
232         { return !(bool)pthread_rwlock_trywrlock(&rwlock); }
233
234         void UnLockWrite(void)
235         { pthread_rwlock_unlock(&rwlock); }
236
237         void UnLockRead(void)
238         { pthread_rwlock_unlock(&rwlock); }
239 };
240 #else
241 //*
242 class ReadWriteLock : public Mutex
243 {
244 public:
245
246         ReadWriteLock()
247         {  }
248
249         ~ReadWriteLock()
250         {  }
251
252         void LockRead(void)
253         { Lock(); }
254
255         void LockWrite(void)
256         { Lock(); }
257
258         bool TryLockRead(void)
259         { return TryLock(); }
260
261         bool TryLockWrite(void)
262         { return TryLock(); }
263
264         void UnLockWrite(void)
265         { UnLock(); }
266
267         void UnLockRead(void)
268         { UnLock(); }
269 };
270 #endif
271
272 /*
273 class Condition
274 {
275         pthread_cond_t cond;
276         pthread_mutex_t mutex;
277 public:
278         Condition()
279         { pthread_cond_init(&cond,NULL); pthread_mutex_init(&mutex,NULL); }
280         ~Condition()
281         { pthread_cond_destroy(&cond); pthread_mutex_destroy(&mutex);}
282         void operator()(void)
283         { pthread_cond_signal(&cond); }
284         void Wait(void)
285         {
286                 pthread_mutex_lock(&mutex);
287                 pthread_cond_wait(&cond,&mutex);
288                 pthread_mutex_unlock(&mutex);
289         }
290 };
291 */
292
293 #else // if defined HAVE_PTHREAD
294 #ifdef HAVE_CREATETHREAD
295
296
297 #ifdef THREAD_ENTRYPOINT
298 #undef THREAD_ENTRYPOINT
299 #endif
300 #define THREAD_ENTRYPOINT       __stdcall
301 class Thread
302 {
303 public:
304         typedef unsigned long entrypoint_return;
305 private:
306
307         unsigned long thread;
308         HANDLE handle;
309         int *references;
310
311         entrypoint_return  (THREAD_ENTRYPOINT *entrypoint)(void *);
312
313         void *context;
314
315         HDC hdc;
316         HGLRC hglrc;
317
318         static entrypoint_return THREAD_ENTRYPOINT thread_prefix(void*data)
319         {
320                 Thread *thread=(Thread *)data;
321
322                 if(thread->hglrc)
323                         wglMakeCurrent(thread->hdc, thread->hglrc);
324
325                 return thread->entrypoint(thread->context);
326         }
327
328 public:
329         Thread(entrypoint_return  (THREAD_ENTRYPOINT *ep)(void *)=NULL,void *context=NULL):
330                 references(NULL),entrypoint(ep),context(context) { }
331         Thread(const Thread &t)
332         {
333                 thread=t.thread;
334                 handle=t.handle;
335                 references=t.references;
336                 entrypoint=t.entrypoint;
337                 context=t.context;
338                 handle=NULL;
339                 if(references)
340                         (*references)++;
341         }
342         const Thread &operator=(const Thread &rhs)
343         {
344                 if(references)
345                 {
346                         (*references)--;
347                         if(*references==0)
348                                 stop();
349                 }
350                 thread=rhs.thread;
351                 handle=rhs.handle;
352                 references=rhs.references;
353                 entrypoint=rhs.entrypoint;
354                 context=rhs.context;
355                 if(references)
356                         (*references)++;
357                 return *this;
358         }
359
360         void start(void)
361         {
362                 references = new int;
363                 *references = 1;
364
365                 hglrc=wglGetCurrentContext();
366                 hdc=wglGetCurrentDC();
367
368                 handle=CreateThread(
369                         NULL,           // Security stuff
370                         0,      // STACK
371                         thread_prefix,    // thread function
372                         (void*)this,                       // thread argument
373                         0,                    // creation option
374                         &thread                        // thread identifier
375                 );
376         }
377
378         void stop(void)
379         {
380                 delete references;
381                 references=NULL;
382
383                 TerminateThread(handle, FALSE);
384         }
385
386         int wait(void)
387         {
388                 if(handle)
389                 {
390                         WaitForSingleObject(handle, INFINITE);
391                         CloseHandle(handle);
392                 }
393                 return 0;
394         }
395
396         static void TestStop()
397         {
398         }
399
400         static void SyncStop()
401         {
402         }
403
404         static void AsyncStop()
405         {
406         }
407
408         ~Thread()
409         {
410                 if(references)
411                 {
412                         (*references)--;
413                         if(*references==0)
414                                 stop();
415                 }
416         }
417 };
418
419 class Mutex
420 {
421         HANDLE handle;
422 public:
423
424         Mutex()
425         {
426                 handle = CreateMutex(NULL, FALSE, NULL);
427         }
428
429         ~Mutex()
430         {
431                 CloseHandle(handle);
432         }
433
434         void Lock(void)
435         {
436                 WaitForSingleObject(handle, INFINITE);
437         }
438
439         bool TryLock(void)
440         {
441                 return WaitForSingleObject(handle, INFINITE)==WAIT_FAILED;
442         }
443
444         void UnLock(void)
445         {
446                 ReleaseMutex(handle);
447         }
448 };
449
450
451 #endif // if defined HAVE_CREATETHREAD
452 #endif // if defined HAVE_PTHREAD_CREATE
453 #endif // if defined CALLISTO_THREADS
454
455
456 #if !defined(CALLISTO_THREADS)
457 // Dummy object used when not threading
458 class ReadWriteLock
459 {
460 public:
461
462         ReadWriteLock() {}
463         ~ReadWriteLock() {}
464         void LockRead(void) {}
465         void LockWrite(void) {}
466         bool TryLockRead(void) {return true;}
467         bool TryLockWrite(void) {return true;}
468         void UnLockRead(void) {}
469         void UnLockWrite(void) {}
470 };
471
472 class Mutex
473 {
474 public:
475
476         Mutex(){}
477         ~Mutex(){}
478         void Lock(void){}
479         bool TryLock(void){return true;}
480         void UnLock(void){}
481 };
482
483 #endif
484
485 class Condition : private Mutex
486 {
487         bool flag;
488 public:
489         Condition()
490         { flag=false; }
491         ~Condition()
492         { }
493         void operator()(void)
494         { flag=true; }
495         void Wait(void)
496         {
497                 Lock();
498                 while(!flag)Yield();
499                 flag=false;
500                 UnLock();
501         }
502         void WaitNext(void)
503         {
504                 Lock();
505                 flag=false;
506                 while(!flag)Yield();
507                 UnLock();
508         }
509 };
510
511 /* === E X T E R N S ======================================================= */
512
513 /* === E N D =============================================================== */
514
515 #endif