1 /********************************************************************************
2 *                                                                               *
3 *                 M u l i t h r e a d i n g   S u p p o r t                     *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 2004,2006 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or                 *
9 * modify it under the terms of the GNU Lesser General Public                    *
10 * License as published by the Free Software Foundation; either                  *
11 * version 2.1 of the License, or (at your option) any later version.            *
12 *                                                                               *
13 * This library 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 * Lesser General Public License for more details.                               *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public              *
19 * License along with this library; if not, write to the Free Software           *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.    *
21 *********************************************************************************
22 * $Id: FXThread.cpp 5723 2021-03-13 09:18:00Z arthurcnorman $                   *
23 ********************************************************************************/
24 #ifdef WIN32
25 #if _WIN32_WINNT < 0x0400
26 #define _WIN32_WINNT 0x0400
27 #endif
28 #endif
29 #include "xincs.h"
30 #include "fxver.h"
31 #include "fxdefs.h"
32 #include "FXThread.h"
33 #ifndef WIN32
34 #include <sys/time.h>
35 #ifdef __APPLE__
36 #ifdef Status
37 #undef Status
38 #endif
39 #ifdef KeyClass
40 #undef KeyClass
41 #endif
42 #include <CoreServices/CoreServices.h>
43 #include <pthread.h>
44 #else
45 #include <pthread.h>
46 #include <semaphore.h>
47 #endif
48 #else
49 #include <process.h>
50 #endif
51 
52 
53 /*
54   Notes:
55 
56   - We have a amorphous blob of memory reserved for the mutex implementation.
57     Since we're trying to avoid having to include platform-specific headers
58     in application code, we can't easily know how much to allocate for
59     pthread_mutex_t [or CRITICAL_SECTION].
60 
61   - We don't want to allocate dynamically because of the performance
62     issues, and also because obviously, since heap memory is shared between
63     threads, a malloc itself involves locking another mutex, leaving a
64     potential for an unexpected deadlock.
65 
66   - So we just reserve some memory which we will hope to be enough.  If it
67     ever turns out its not, the assert should trigger and we'll just have
68     to change the source a bit.
69 
70   - If you run into this, try to figure out sizeof(pthread_mutex_t) and
71     let me know about it (jeroen@fox-toolkit.org).
72 
73   - I do recommend running this in debug mode first time around on a
74     new platform.
75 
76   - Picked unsigned long so as to ensure alignment issues are taken
77     care off.
78 
79   - I now believe its safe to set tid=0 after run returns; if FXThread
80     is destroyed then the execution is stopped immediately; if the thread
81     exits, tid is also set to 0.  If the thread is cancelled, tid is also
82     set to 0.  In no circumstance I can see is it possible for run() to
83     return when FXThread no longer exists.
84 */
85 
86 using namespace FX;
87 
88 
89 namespace FX {
90 
91 /*******************************************************************************/
92 
93 // Unix implementation
94 
95 #ifndef WIN32
96 
97 
98 // Initialize mutex
FXMutex(FXbool recursive)99 FXMutex::FXMutex(FXbool recursive){
100   pthread_mutexattr_t mutexatt;
101   // If this fails on your machine, determine what value
102   // of sizeof(pthread_mutex_t) is supposed to be on your
103   // machine and mail it to: jeroen@fox-toolkit.org!!
104   //FXTRACE((150,"sizeof(pthread_mutex_t)=%d\n",sizeof(pthread_mutex_t)));
105   FXASSERT(sizeof(data)>=sizeof(pthread_mutex_t));
106   pthread_mutexattr_init(&mutexatt);
107   pthread_mutexattr_settype(&mutexatt,recursive?PTHREAD_MUTEX_RECURSIVE:PTHREAD_MUTEX_DEFAULT);
108   pthread_mutex_init((pthread_mutex_t*)data,&mutexatt);
109   pthread_mutexattr_destroy(&mutexatt);
110   }
111 
112 
113 // Lock the mutex
lock()114 void FXMutex::lock(){
115   pthread_mutex_lock((pthread_mutex_t*)data);
116   }
117 
118 
119 // Try lock the mutex
trylock()120 FXbool FXMutex::trylock(){
121   return pthread_mutex_trylock((pthread_mutex_t*)data)==0;
122   }
123 
124 
125 // Unlock mutex
unlock()126 void FXMutex::unlock(){
127   pthread_mutex_unlock((pthread_mutex_t*)data);
128   }
129 
130 
131 // Test if locked
locked()132 FXbool FXMutex::locked(){
133   if(pthread_mutex_trylock((pthread_mutex_t*)data)==0){
134     pthread_mutex_unlock((pthread_mutex_t*)data);
135     return false;
136     }
137   return true;
138   }
139 
140 
141 // Delete mutex
~FXMutex()142 FXMutex::~FXMutex(){
143   pthread_mutex_destroy((pthread_mutex_t*)data);
144   }
145 
146 
147 /*******************************************************************************/
148 
149 
150 #ifdef __APPLE__
151 
152 
153 // Initialize semaphore
FXSemaphore(FXint initial)154 FXSemaphore::FXSemaphore(FXint initial){
155   // If this fails on your machine, determine what value
156   // of sizeof(MPSemaphoreID*) is supposed to be on your
157   // machine and mail it to: jeroen@fox-toolkit.org!!
158   //FXTRACE((150,"sizeof(MPSemaphoreID*)=%d\n",sizeof(MPSemaphoreID*)));
159   FXASSERT(sizeof(data)>=sizeof(MPSemaphoreID*));
160   MPCreateSemaphore(2147483647,initial,(MPSemaphoreID*)data);
161   }
162 
163 
164 // Decrement semaphore
wait()165 void FXSemaphore::wait(){
166   MPWaitOnSemaphore(*((MPSemaphoreID*)data),kDurationForever);
167   }
168 
169 
170 // Decrement semaphore but don't block
trywait()171 FXbool FXSemaphore::trywait(){
172   return MPWaitOnSemaphore(*((MPSemaphoreID*)data),kDurationImmediate)==noErr;
173   }
174 
175 
176 // Increment semaphore
post()177 void FXSemaphore::post(){
178   MPSignalSemaphore(*((MPSemaphoreID*)data));
179   }
180 
181 
182 // Delete semaphore
~FXSemaphore()183 FXSemaphore::~FXSemaphore(){
184   MPDeleteSemaphore(*((MPSemaphoreID*)data));
185   }
186 
187 #else
188 
189 // Initialize semaphore
FXSemaphore(FXint initial)190 FXSemaphore::FXSemaphore(FXint initial){
191   // If this fails on your machine, determine what value
192   // of sizeof(sem_t) is supposed to be on your
193   // machine and mail it to: jeroen@fox-toolkit.org!!
194   //FXTRACE((150,"sizeof(sem_t)=%d\n",sizeof(sem_t)));
195   FXASSERT(sizeof(data)>=sizeof(sem_t));
196   sem_init((sem_t*)data,0,(unsigned int)initial);
197   }
198 
199 
200 // Decrement semaphore
wait()201 void FXSemaphore::wait(){
202   sem_wait((sem_t*)data);
203   }
204 
205 
206 // Decrement semaphore but don't block
trywait()207 FXbool FXSemaphore::trywait(){
208   return sem_trywait((sem_t*)data)==0;
209   }
210 
211 
212 // Increment semaphore
post()213 void FXSemaphore::post(){
214   sem_post((sem_t*)data);
215   }
216 
217 
218 // Delete semaphore
~FXSemaphore()219 FXSemaphore::~FXSemaphore(){
220   sem_destroy((sem_t*)data);
221   }
222 
223 #endif
224 
225 /*******************************************************************************/
226 
227 
228 // Initialize condition
FXCondition()229 FXCondition::FXCondition(){
230   // If this fails on your machine, determine what value
231   // of sizeof(pthread_cond_t) is supposed to be on your
232   // machine and mail it to: jeroen@fox-toolkit.org!!
233   //FXTRACE((150,"sizeof(pthread_cond_t)=%d\n",sizeof(pthread_cond_t)));
234   FXASSERT(sizeof(data)>=sizeof(pthread_cond_t));
235   pthread_cond_init((pthread_cond_t*)data,NULL);
236   }
237 
238 
239 // Wake up one single waiting thread
signal()240 void FXCondition::signal(){
241   pthread_cond_signal((pthread_cond_t*)data);
242   }
243 
244 
245 // Wake up all waiting threads
broadcast()246 void FXCondition::broadcast(){
247   pthread_cond_broadcast((pthread_cond_t*)data);
248   }
249 
250 
251 // Wait for condition indefinitely
wait(FXMutex & mtx)252 void FXCondition::wait(FXMutex& mtx){
253   pthread_cond_wait((pthread_cond_t*)data,(pthread_mutex_t*)mtx.data);
254   }
255 
256 
257 // Wait for condition but fall through after timeout
wait(FXMutex & mtx,FXlong nsec)258 FXbool FXCondition::wait(FXMutex& mtx,FXlong nsec){
259   int result;
260   struct timespec ts;
261   ts.tv_sec=nsec/1000000000;
262   ts.tv_nsec=nsec%1000000000;
263 x:result=pthread_cond_timedwait((pthread_cond_t*)data,(pthread_mutex_t*)mtx.data,&ts);
264   if(result==EINTR) goto x;
265   return result!=ETIMEDOUT;
266   }
267 
268 
269 // Delete condition
~FXCondition()270 FXCondition::~FXCondition(){
271   pthread_cond_destroy((pthread_cond_t*)data);
272   }
273 
274 
275 /*******************************************************************************/
276 
277 // Thread local storage key for back-reference to FXThread
278 static pthread_key_t self_key;
279 
280 // Global initializer for the self_key variable
281 struct TLSKEYINIT {
TLSKEYINITFX::TLSKEYINIT282   TLSKEYINIT(){ pthread_key_create(&self_key,NULL); }
~TLSKEYINITFX::TLSKEYINIT283  ~TLSKEYINIT(){ pthread_key_delete(self_key); }
284   };
285 
286 
287 // Extern declaration prevents overzealous optimizer from noticing we're
288 // never using this object, and subsequently eliminating it from the code.
289 extern TLSKEYINIT initializer;
290 
291 // Dummy object causes global initializer to run
292 TLSKEYINIT initializer;
293 
294 
295 // Initialize thread
FXThread()296 FXThread::FXThread():tid(0){
297   }
298 
299 
300 // Return thread id of this thread object.
301 // Purposefully NOT inlined, the tid may be changed by another
302 // thread and therefore we must force the compiler to fetch
303 // this value fresh each time it is needed!
id() const304 FXThreadID FXThread::id() const {
305   return tid;
306   }
307 
308 
309 // Return TRUE if this thread is running
running() const310 FXbool FXThread::running() const {
311   return tid!=0;
312   }
313 
314 
315 // Start the thread; we associate the FXThread instance with
316 // this thread using thread-local storage accessed with self_key.
317 // Also, we catch any errors thrown by the thread code here.
execute(void * thread)318 void* FXThread::execute(void* thread){
319   FXint code=-1;
320   pthread_setspecific(self_key,thread);
321   pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
322   pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
323   try{ code=((FXThread*)thread)->run(); } catch(...){ }
324   ((FXThread*)thread)->tid=0;
325   return (void*)(FXival)code;
326   }
327 
328 
329 // Start thread; make sure that stacksize >= PTHREAD_STACK_MIN.
330 // We can't check for it because not all machines have this the
331 // PTHREAD_STACK_MIN definition.
start(unsigned long stacksize)332 FXbool FXThread::start(unsigned long stacksize){
333   FXbool code;
334   pthread_attr_t attr;
335   pthread_attr_init(&attr);
336   pthread_attr_setinheritsched(&attr,PTHREAD_INHERIT_SCHED);
337   if(stacksize){ pthread_attr_setstacksize(&attr,stacksize); }
338   //pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
339   code=pthread_create((pthread_t*)&tid,&attr,FXThread::execute,(void*)this)==0;
340   pthread_attr_destroy(&attr);
341   return code;
342   }
343 
344 
345 // Suspend calling thread until thread is done
join(FXint & code)346 FXbool FXThread::join(FXint& code){
347   pthread_t ttid=(pthread_t)tid;
348   void *trc=NULL;
349   if(ttid && pthread_join(ttid,&trc)==0){
350     code=(FXint)(FXival)trc;
351     tid=0;
352     return TRUE;
353     }
354   return FALSE;
355   }
356 
357 
358 // Suspend calling thread until thread is done
join()359 FXbool FXThread::join(){
360   pthread_t ttid=(pthread_t)tid;
361   if(ttid && pthread_join(ttid,NULL)==0){
362     tid=0;
363     return TRUE;
364     }
365   return FALSE;
366   }
367 
368 
369 // Cancel the thread
cancel()370 FXbool FXThread::cancel(){
371   pthread_t ttid=(pthread_t)tid;
372   if(ttid && pthread_cancel(ttid)==0){
373     pthread_join(ttid,NULL);
374     tid=0;
375     return TRUE;
376     }
377   return FALSE;
378   }
379 
380 
381 // Detach thread
detach()382 FXbool FXThread::detach(){
383   pthread_t ttid=(pthread_t)tid;
384   return ttid && pthread_detach(ttid)==0;
385   }
386 
387 
388 // Exit calling thread
exit(FXint code)389 void FXThread::exit(FXint code){
390   if(self()){ self()->tid=0; }
391   pthread_exit((void*)(FXival)code);
392   }
393 
394 
395 // Yield the thread
yield()396 void FXThread::yield(){
397   sched_yield();                // More portable than pthread_yield()
398   }
399 
400 
401 // Get time in nanoseconds since Epoch
time()402 FXlong FXThread::time(){
403 #ifdef __USE_POSIX199309
404   const FXlong seconds=1000000000;
405   struct timespec ts;
406   clock_gettime(CLOCK_REALTIME,&ts);
407   return ts.tv_sec*seconds+ts.tv_nsec;
408 #else
409   const FXlong seconds=1000000000;
410   const FXlong microseconds=1000;
411   struct timeval tv;
412   gettimeofday(&tv,NULL);
413   return tv.tv_sec*seconds+tv.tv_usec*microseconds;
414 #endif
415   }
416 
417 
418 // Sleep for some time
sleep(FXlong nsec)419 void FXThread::sleep(FXlong nsec){
420 #ifdef __USE_POSIX199309
421   const FXlong seconds=1000000000;
422   struct timespec value;
423   value.tv_sec=nsec/seconds;
424   value.tv_nsec=nsec%seconds;
425   nanosleep(&value,NULL);
426 #else
427   const FXlong seconds=1000000000;
428   const FXlong microseconds=1000;
429   const FXlong milliseconds=1000000;
430   struct timeval value;
431   value.tv_usec=(nsec/microseconds)%milliseconds;
432   value.tv_sec=nsec/seconds;
433   select(1,0,0,0,&value);
434 #endif
435   }
436 
437 
438 // Wake at appointed time
wakeat(FXlong nsec)439 void FXThread::wakeat(FXlong nsec){
440 #ifdef __USE_POSIX199309
441   const FXlong seconds=1000000000;
442   struct timespec value;
443 #ifdef __USE_XOPEN2K
444   value.tv_sec=nsec/seconds;
445   value.tv_nsec=nsec%seconds;
446   clock_nanosleep(CLOCK_REALTIME,TIMER_ABSTIME,&value,NULL);
447 #else
448   nsec-=FXThread::time();
449   if(nsec<0) nsec=0;
450   value.tv_sec=nsec/seconds;
451   value.tv_nsec=nsec%seconds;
452   nanosleep(&value,NULL);
453 #endif
454 #else
455   const FXlong seconds=1000000000;
456   const FXlong microseconds=1000;
457   const FXlong milliseconds=1000000;
458   struct timeval value;
459   if(nsec<0) nsec=0;
460   value.tv_usec=(nsec/microseconds)%milliseconds;
461   value.tv_sec=nsec/seconds;
462   select(1,0,0,0,&value);
463 #endif
464   }
465 
466 
467 // Return pointer to calling thread's instance
self()468 FXThread* FXThread::self(){
469   return (FXThread*)pthread_getspecific(self_key);
470   }
471 
472 
473 // Return thread id of caller
current()474 FXThreadID FXThread::current(){
475   return (FXThreadID)pthread_self();
476   }
477 
478 
479 // Set thread priority
priority(FXint prio)480 void FXThread::priority(FXint prio){
481   pthread_t ttid=(pthread_t)tid;
482   if(ttid){
483     sched_param sched={0};
484     int pcy=0;
485     pthread_getschedparam(ttid,&pcy,&sched);
486 #if defined(_POSIX_PRIORITY_SCHEDULING)
487     int priomax=sched_get_priority_max(pcy);
488     int priomin=sched_get_priority_min(pcy);
489     sched.sched_priority=FXCLAMP(priomin,prio,priomax);
490 #elif defined(PTHREAD_MINPRIORITY)
491     sched.sched_priority=FXCLAMP(PTHREAD_MIN_PRIORITY,prio,PTHREAD_MAX_PRIORITY);
492 #endif
493     pthread_setschedparam(ttid,pcy,&sched);
494     }
495   }
496 
497 
498 // Return thread priority
priority()499 FXint FXThread::priority(){
500   pthread_t ttid=(pthread_t)tid;
501   if(ttid){
502     sched_param sched={0};
503     int pcy=0;
504     pthread_getschedparam(ttid,&pcy,&sched);
505     return sched.sched_priority;
506     }
507   return 0;
508   }
509 
510 
511 // Destroy; if it was running, stop it
~FXThread()512 FXThread::~FXThread(){
513   pthread_t ttid=(pthread_t)tid;
514   if(ttid){
515     pthread_cancel(ttid);
516     }
517   }
518 
519 
520 /*******************************************************************************/
521 
522 // Windows implementation
523 
524 #else
525 
526 // Initialize mutex
527 FXMutex::FXMutex(FXbool){
528   // If this fails on your machine, determine what value
529   // of sizeof(CRITICAL_SECTION) is supposed to be on your
530   // machine and mail it to: jeroen@fox-toolkit.org!!
531   //FXTRACE((150,"sizeof(CRITICAL_SECTION)=%d\n",sizeof(CRITICAL_SECTION)));
532   FXASSERT(sizeof(data)>=sizeof(CRITICAL_SECTION));
533   InitializeCriticalSection((CRITICAL_SECTION*)data);
534   }
535 
536 
537 // Lock the mutex
538 void FXMutex::lock(){
539   EnterCriticalSection((CRITICAL_SECTION*)data);
540   }
541 
542 
543 
544 // Try lock the mutex
545 FXbool FXMutex::trylock(){
546 #if(_WIN32_WINNT >= 0x0400)
547   return TryEnterCriticalSection((CRITICAL_SECTION*)data)!=0;
548 #else
549   return FALSE;
550 #endif
551   }
552 
553 
554 // Unlock mutex
555 void FXMutex::unlock(){
556   LeaveCriticalSection((CRITICAL_SECTION*)data);
557   }
558 
559 
560 // Test if locked
561 FXbool FXMutex::locked(){
562 #if(_WIN32_WINNT >= 0x0400)
563   if(TryEnterCriticalSection((CRITICAL_SECTION*)data)!=0){
564     LeaveCriticalSection((CRITICAL_SECTION*)data);
565     return false;
566     }
567 #endif
568   return true;
569   }
570 
571 
572 // Delete mutex
573 FXMutex::~FXMutex(){
574   DeleteCriticalSection((CRITICAL_SECTION*)data);
575   }
576 
577 
578 /*******************************************************************************/
579 
580 
581 // Initialize semaphore
582 FXSemaphore::FXSemaphore(FXint initial){
583   data[0]=(FXuval)CreateSemaphore(NULL,initial,0x7fffffff,NULL);
584   }
585 
586 
587 // Decrement semaphore
588 void FXSemaphore::wait(){
589   WaitForSingleObject((HANDLE)data[0],INFINITE);
590   }
591 
592 
593 // Non-blocking semaphore decrement
594 FXbool FXSemaphore::trywait(){
595   return WaitForSingleObject((HANDLE)data[0],0)==WAIT_OBJECT_0;
596   }
597 
598 
599 // Increment semaphore
600 void FXSemaphore::post(){
601   ReleaseSemaphore((HANDLE)data[0],1,NULL);
602   }
603 
604 
605 // Delete semaphore
606 FXSemaphore::~FXSemaphore(){
607   CloseHandle((HANDLE)data[0]);
608   }
609 
610 
611 /*******************************************************************************/
612 
613 
614 // This is the solution according to Schmidt, the win32-threads
615 // implementation thereof which is found inside GCC somewhere.
616 // See: (http://www.cs.wustl.edu/~schmidt/win32-cv-1.html).
617 //
618 // Our implementation however initializes the Event objects in
619 // the constructor, under the assumption that you wouldn't be creating
620 // a condition object if you weren't planning to use them somewhere.
621 
622 
623 // Initialize condition
624 FXCondition::FXCondition(){
625   // If this fails on your machine, notify jeroen@fox-toolkit.org!
626   FXASSERT(sizeof(data)>=sizeof(CRITICAL_SECTION)+sizeof(HANDLE)+sizeof(HANDLE)+sizeof(FXuval));
627   data[0]=(FXuval)CreateEvent(NULL,0,0,NULL);                   // Wakes one, autoreset
628   data[1]=(FXuval)CreateEvent(NULL,1,0,NULL);                   // Wakes all, manual reset
629   data[2]=0;                                                    // Blocked count
630   InitializeCriticalSection((CRITICAL_SECTION*)&data[3]);       // Critical section
631   }
632 
633 
634 // Wake up one single waiting thread
635 void FXCondition::signal(){
636   EnterCriticalSection((CRITICAL_SECTION*)&data[3]);
637   int blocked=(data[2]>0);
638   LeaveCriticalSection((CRITICAL_SECTION*)&data[3]);
639   if(blocked) SetEvent((HANDLE)data[0]);
640   }
641 
642 
643 // Wake up all waiting threads
644 void FXCondition::broadcast(){
645   EnterCriticalSection((CRITICAL_SECTION*)&data[3]);
646   int blocked=(data[2]>0);
647   LeaveCriticalSection((CRITICAL_SECTION*)&data[3]);
648   if(blocked) SetEvent((HANDLE)data[1]);
649   }
650 
651 
652 // Wait
653 void FXCondition::wait(FXMutex& mtx){
654   EnterCriticalSection((CRITICAL_SECTION*)&data[3]);
655   data[2]++;
656   LeaveCriticalSection((CRITICAL_SECTION*)&data[3]);
657   mtx.unlock();
658   DWORD result=WaitForMultipleObjects(2,(HANDLE*)data,0,INFINITE);
659   EnterCriticalSection((CRITICAL_SECTION*)&data[3]);
660   data[2]--;
661   int last_waiter=(result==WAIT_OBJECT_0+1)&&(data[2]==0);      // Unblocked by broadcast & no other blocked threads
662   LeaveCriticalSection((CRITICAL_SECTION*)&data[3]);
663   if(last_waiter) ResetEvent((HANDLE)data[1]);                  // Reset signal
664   mtx.lock();
665   }
666 
667 
668 // Wait using single global mutex
669 FXbool FXCondition::wait(FXMutex& mtx,FXlong nsec){
670   EnterCriticalSection((CRITICAL_SECTION*)&data[3]);
671   data[2]++;
672   LeaveCriticalSection((CRITICAL_SECTION*)&data[3]);
673   mtx.unlock();
674   nsec-=FXThread::time();
675   DWORD result=WaitForMultipleObjects(2,(HANDLE*)data,0,nsec/1000000);
676   EnterCriticalSection((CRITICAL_SECTION*)&data[3]);
677   data[2]--;
678   int last_waiter=(result==WAIT_OBJECT_0+1)&&(data[2]==0);      // Unblocked by broadcast & no other blocked threads
679   LeaveCriticalSection((CRITICAL_SECTION*)&data[3]);
680   if(last_waiter) ResetEvent((HANDLE)data[1]);                  // Reset signal
681   mtx.lock();
682   return result!=WAIT_TIMEOUT;
683   }
684 
685 
686 // Delete condition
687 FXCondition::~FXCondition(){
688   CloseHandle((HANDLE)data[0]);
689   CloseHandle((HANDLE)data[1]);
690   DeleteCriticalSection((CRITICAL_SECTION*)&data[3]);
691   }
692 
693 
694 /*******************************************************************************/
695 
696 // Thread local storage key for back-reference to FXThread
697 static DWORD self_key=0xffffffff;
698 
699 // Global initializer for the self_key variable
700 struct TLSKEYINIT {
701   TLSKEYINIT(){ self_key=TlsAlloc(); }
702  ~TLSKEYINIT(){ TlsFree(self_key); }
703   };
704 
705 // Extern declaration prevents overzealous optimizer from noticing we're
706 // never using this object, and subsequently eliminating it from the code.
707 extern TLSKEYINIT initializer;
708 
709 // Dummy object causes global initializer to run
710 TLSKEYINIT initializer;
711 
712 
713 // Initialize thread
714 FXThread::FXThread():tid(0){
715   }
716 
717 
718 // Return thread id of this thread object.
719 // Purposefully NOT inlined, the tid may be changed by another
720 // thread and therefore we must force the compiler to fetch
721 // this value fresh each time it is needed!
722 FXThreadID FXThread::id() const {
723   return tid;
724   }
725 
726 
727 // Return TRUE if this thread is running
728 FXbool FXThread::running() const {
729   return tid!=0;
730   }
731 
732 
733 // Start the thread; we associate the FXThread instance with
734 // this thread using thread-local storage accessed with self_key.
735 // Also, we catch any errors thrown by the thread code here.
736 unsigned int CALLBACK FXThread::execute(void* thread){
737   FXint code=-1;
738   TlsSetValue(self_key,thread);
739   try{ code=((FXThread*)thread)->run(); } catch(...){ }
740   ((FXThread*)thread)->tid=0;
741   return code;
742   }
743 
744 
745 // Start thread
746 FXbool FXThread::start(unsigned long stacksize){
747   DWORD thd;
748   tid=(FXThreadID)CreateThread(NULL,stacksize,(LPTHREAD_START_ROUTINE)FXThread::execute,this,0,&thd);
749   return tid!=NULL;
750   }
751 
752 
753 // Suspend calling thread until thread is done
754 FXbool FXThread::join(FXint& code){
755   HANDLE ttid=(HANDLE)tid;
756   if(ttid && WaitForSingleObject(ttid,INFINITE)==WAIT_OBJECT_0){
757     GetExitCodeThread(ttid,(DWORD*)&code);
758     CloseHandle(ttid);
759     tid=0;
760     return TRUE;
761     }
762   return FALSE;
763   }
764 
765 
766 // Suspend calling thread until thread is done
767 FXbool FXThread::join(){
768   HANDLE ttid=(HANDLE)tid;
769   if(ttid && WaitForSingleObject(ttid,INFINITE)==WAIT_OBJECT_0){
770     CloseHandle(ttid);
771     tid=0;
772     return TRUE;
773     }
774   return FALSE;
775   }
776 
777 
778 // Cancel the thread
779 FXbool FXThread::cancel(){
780   HANDLE ttid=(HANDLE)tid;
781   if(ttid && TerminateThread(ttid,0)){
782     CloseHandle(ttid);
783     tid=0;
784     return TRUE;
785     }
786   return FALSE;
787   }
788 
789 
790 // Detach thread
791 FXbool FXThread::detach(){
792   return tid!=0;
793   }
794 
795 
796 // Exit calling thread
797 void FXThread::exit(FXint code){
798   if(self()){ self()->tid=0; }
799   ExitThread(code);
800   }
801 
802 
803 // Yield the thread
804 void FXThread::yield(){
805   Sleep(0);
806   }
807 
808 
809 // Get time in nanoseconds since Epoch
810 FXlong FXThread::time(){
811   FXlong now;
812   GetSystemTimeAsFileTime((FILETIME*)&now);
813 #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__SC__)
814   return (now-116444736000000000LL)*100LL;
815 #else
816   return (now-116444736000000000L)*100L;
817 #endif
818   }
819 
820 
821 // Sleep for some time
822 void FXThread::sleep(FXlong nsec){
823   Sleep(nsec/1000000);
824   }
825 
826 
827 // Wake at appointed time
828 void FXThread::wakeat(FXlong nsec){
829   nsec-=FXThread::time();
830   if(nsec<0) nsec=0;
831   Sleep(nsec/1000000);
832   }
833 
834 
835 // Return thread id of caller
836 FXThreadID FXThread::current(){
837   return (FXThreadID)GetCurrentThreadId();
838   }
839 
840 
841 // Return pointer to calling thread's instance
842 FXThread* FXThread::self(){
843   return (FXThread*)TlsGetValue(self_key);
844   }
845 
846 
847 // Set thread priority
848 void FXThread::priority(FXint prio){
849   HANDLE ttid=(HANDLE)tid;
850   if(ttid){
851     SetThreadPriority(ttid,prio);
852     }
853   }
854 
855 
856 // Return thread priority
857 FXint FXThread::priority(){
858   HANDLE ttid=(HANDLE)tid;
859   if(ttid){
860     return GetThreadPriority(ttid);
861     }
862   return 0;
863   }
864 
865 
866 // Destroy
867 FXThread::~FXThread(){
868   HANDLE ttid=(HANDLE)tid;
869   if(ttid){
870     TerminateThread(ttid,0);
871     CloseHandle(ttid);
872     }
873   }
874 
875 
876 #endif
877 
878 
879 }
880