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,2005 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,v 1.38.2.3 2005/11/09 10:30:46 fox Exp $ *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "FXThread.h"
28
29 #ifndef WIN32
30 #include <pthread.h>
31 #include <semaphore.h>
32 #else
33 #include <process.h>
34 #endif
35
36
37 /*
38 Notes:
39
40 - We have a amorphous blob of memory reserved for the mutex implementation.
41 Since we're trying to avoid having to include platform-specific headers
42 in application code, we can't easily know how much to allocate for
43 pthread_mutex_t [or CRITICAL_SECTION].
44
45 - We don't want to allocate dynamically because of the performance
46 issues, and also because obviously, since heap memory is shared between
47 threads, a malloc itself involves locking another mutex, leaving a
48 potential for an unexpected deadlock.
49
50 - So we just reserve some memory which we will hope to be enough. If it
51 ever turns out its not, the assert should trigger and we'll just have
52 to change the source a bit.
53
54 - If you run into this, try to figure out sizeof(pthread_mutex_t) and
55 let me know about it (jeroen@fox-toolkit.org).
56
57 - I do recommend running this in debug mode first time around on a
58 new platform.
59
60 - Picked unsigned long so as to ensure alignment issues are taken
61 care off.
62 */
63
64 using namespace FX;
65
66
67 namespace FX {
68
69 /*******************************************************************************/
70
71 // Unix implementation
72
73 #ifndef WIN32
74
75
76 // Initialize mutex
FXMutex(FXbool recursive)77 FXMutex::FXMutex(FXbool recursive){
78 pthread_mutexattr_t mutexatt;
79 // If this fails on your machine, determine what value
80 // of sizeof(pthread_mutex_t) is supposed to be on your
81 // machine and mail it to: jeroen@fox-toolkit.org!!
82 //FXTRACE((150,"sizeof(pthread_mutex_t)=%d\n",sizeof(pthread_mutex_t)));
83 FXASSERT(sizeof(data)>=sizeof(pthread_mutex_t));
84 pthread_mutexattr_init(&mutexatt);
85 pthread_mutexattr_settype(&mutexatt,recursive?PTHREAD_MUTEX_RECURSIVE:PTHREAD_MUTEX_DEFAULT);
86 pthread_mutex_init((pthread_mutex_t*)data,&mutexatt);
87 pthread_mutexattr_destroy(&mutexatt);
88 }
89
90
91 // Lock the mutex
lock()92 void FXMutex::lock(){
93 pthread_mutex_lock((pthread_mutex_t*)data);
94 }
95
96
97 // Try lock the mutex
trylock()98 FXbool FXMutex::trylock(){
99 return pthread_mutex_trylock((pthread_mutex_t*)data)==0;
100 }
101
102
103 // Unlock mutex
unlock()104 void FXMutex::unlock(){
105 pthread_mutex_unlock((pthread_mutex_t*)data);
106 }
107
108
109 // Test if locked
locked()110 FXbool FXMutex::locked(){
111 if(pthread_mutex_trylock((pthread_mutex_t*)data)==EBUSY) return TRUE;
112 pthread_mutex_unlock((pthread_mutex_t*)data);
113 return FALSE;
114 }
115
116
117 // Delete mutex
~FXMutex()118 FXMutex::~FXMutex(){
119 pthread_mutex_destroy((pthread_mutex_t*)data);
120 }
121
122
123 /*******************************************************************************/
124
125
126 // Initialize semaphore
FXSemaphore(FXint initial)127 FXSemaphore::FXSemaphore(FXint initial){
128 // If this fails on your machine, determine what value
129 // of sizeof(sem_t) is supposed to be on your
130 // machine and mail it to: jeroen@fox-toolkit.org!!
131 //FXTRACE((150,"sizeof(sem_t)=%d\n",sizeof(sem_t)));
132 FXASSERT(sizeof(data)>=sizeof(sem_t));
133 sem_init((sem_t*)data,0,(unsigned int)initial);
134 }
135
136
137 // Decrement semaphore
wait()138 void FXSemaphore::wait(){
139 sem_wait((sem_t*)data);
140 }
141
142
143 // Decrement semaphore but don't block
trywait()144 FXbool FXSemaphore::trywait(){
145 return sem_trywait((sem_t*)data)==0;
146 }
147
148
149 // Increment semaphore
post()150 void FXSemaphore::post(){
151 sem_post((sem_t*)data);
152 }
153
154
155 // Delete semaphore
~FXSemaphore()156 FXSemaphore::~FXSemaphore(){
157 sem_destroy((sem_t*)data);
158 }
159
160
161 /*******************************************************************************/
162
163
164 // Initialize condition
FXCondition()165 FXCondition::FXCondition(){
166 // If this fails on your machine, determine what value
167 // of sizeof(pthread_cond_t) is supposed to be on your
168 // machine and mail it to: jeroen@fox-toolkit.org!!
169 //FXTRACE((150,"sizeof(pthread_cond_t)=%d\n",sizeof(pthread_cond_t)));
170 FXASSERT(sizeof(data)>=sizeof(pthread_cond_t));
171 pthread_cond_init((pthread_cond_t*)data,NULL);
172 }
173
174
175 // Wake up one single waiting thread
signal()176 void FXCondition::signal(){
177 pthread_cond_signal((pthread_cond_t*)data);
178 }
179
180
181 // Wake up all waiting threads
broadcast()182 void FXCondition::broadcast(){
183 pthread_cond_broadcast((pthread_cond_t*)data);
184 }
185
186
187 // Wait for condition indefinitely
wait(FXMutex & mtx)188 void FXCondition::wait(FXMutex& mtx){
189 pthread_cond_wait((pthread_cond_t*)data,(pthread_mutex_t*)&mtx.data);
190 }
191
192
193 // Wait for condition but fall through after timeout
wait(FXMutex & mtx,FXuint ms)194 FXbool FXCondition::wait(FXMutex& mtx,FXuint ms){
195 register int result;
196 struct timespec ts;
197 struct timeval tv;
198 gettimeofday(&tv,NULL);
199 ts.tv_nsec=((ms%1000)*1000+tv.tv_usec)*1000;
200 ts.tv_sec=(ms/1000)+(ts.tv_nsec/1000000000)+tv.tv_sec;
201 ts.tv_nsec=ts.tv_nsec%1000000000;
202 x:result=pthread_cond_timedwait((pthread_cond_t*)data,(pthread_mutex_t*)&mtx.data,&ts);
203 if(result==EINTR) goto x;
204 return result!=ETIMEDOUT;
205 }
206
207
208 // Delete condition
~FXCondition()209 FXCondition::~FXCondition(){
210 pthread_cond_destroy((pthread_cond_t*)data);
211 }
212
213
214 /*******************************************************************************/
215
216 // Thread local storage key for back-reference to FXThread
217 static pthread_key_t self_key;
218
219 // Global initializer for the self_key variable
220 struct TLSKEYINIT {
TLSKEYINITFX::TLSKEYINIT221 TLSKEYINIT(){ pthread_key_create(&self_key,NULL); }
~TLSKEYINITFX::TLSKEYINIT222 ~TLSKEYINIT(){ pthread_key_delete(self_key); }
223 };
224
225 // Extern declaration prevents overzealous optimizer from noticing we're
226 // never using this object, and subsequently eliminating it from the code.
227 extern TLSKEYINIT initializer;
228
229 // Dummy object causes global initializer to run
230 TLSKEYINIT initializer;
231
232
233 // Initialize thread
FXThread()234 FXThread::FXThread():tid(0){
235 }
236
237
238 // Return thread id of this thread object.
239 // Purposefully NOT inlined, the tid may be changed by another
240 // thread and therefore we must force the compiler to fetch
241 // this value fresh each time it is needed!
id() const242 FXThreadID FXThread::id() const {
243 return tid;
244 }
245
246
247 // Return TRUE if this thread is running
running() const248 FXbool FXThread::running() const {
249 return tid!=0;
250 }
251
252
253 // Start the thread; we associate the FXThread instance with
254 // this thread using thread-local storage accessed with self_key.
255 // Also, we catch any errors thrown by the thread code here.
execute(void * thread)256 void* FXThread::execute(void* thread){
257 register FXint code=-1;
258 pthread_setspecific(self_key,thread);
259 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
260 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
261 try{ code=((FXThread*)thread)->run(); } catch(...){ }
262 return (void*)(FXival)code;
263 }
264
265
266 // Start thread; make sure that stacksize >= PTHREAD_STACK_MIN.
267 // We can't check for it because not all machines have this the
268 // PTHREAD_STACK_MIN definition.
start(unsigned long stacksize)269 FXbool FXThread::start(unsigned long stacksize){
270 register FXbool code;
271 pthread_attr_t attr;
272 pthread_attr_init(&attr);
273 pthread_attr_setinheritsched(&attr,PTHREAD_INHERIT_SCHED);
274 if(stacksize){ pthread_attr_setstacksize(&attr,stacksize); }
275 //pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
276 code=pthread_create((pthread_t*)&tid,&attr,FXThread::execute,(void*)this)==0;
277 pthread_attr_destroy(&attr);
278 return code;
279 }
280
281
282 // Suspend calling thread until thread is done
join(FXint & code)283 FXbool FXThread::join(FXint& code){
284 void *trc=NULL;
285 if(tid && pthread_join((pthread_t)tid,&trc)==0){
286 code=(FXint)(FXival)trc;
287 tid=0;
288 return TRUE;
289 }
290 return FALSE;
291 }
292
293
294 // Suspend calling thread until thread is done
join()295 FXbool FXThread::join(){
296 if(tid && pthread_join((pthread_t)tid,NULL)==0){
297 tid=0;
298 return TRUE;
299 }
300 return FALSE;
301 }
302
303
304 // Cancel the thread
cancel()305 FXbool FXThread::cancel(){
306 if(tid && pthread_cancel((pthread_t)tid)==0){
307 pthread_join((pthread_t)tid,NULL);
308 tid=0;
309 return TRUE;
310 }
311 return FALSE;
312 }
313
314
315 // Detach thread
detach()316 FXbool FXThread::detach(){
317 return tid && pthread_detach((pthread_t)tid)==0;
318 }
319
320
321 // Exit calling thread
exit(FXint code)322 void FXThread::exit(FXint code){
323 pthread_exit((void*)(FXival)code);
324 }
325
326
327 // Yield the thread
yield()328 void FXThread::yield(){
329 sched_yield(); // More portable than pthread_yield()
330 }
331
332
333 // Sleep for some time
sleep(unsigned long sec,unsigned long nsec)334 void FXThread::sleep(unsigned long sec,unsigned long nsec){
335 struct timespec value;
336 value.tv_sec=sec+nsec/1000000000; // A few seconds is billions and billions of nanoseconds!
337 value.tv_nsec=nsec%1000000000;
338 nanosleep(&value,NULL);
339 }
340
341
342 // Return pointer to calling thread's instance
self()343 FXThread* FXThread::self(){
344 return (FXThread*)pthread_getspecific(self_key);
345 }
346
347
348 // Return thread id of caller
current()349 FXThreadID FXThread::current(){
350 return (FXThreadID)pthread_self();
351 }
352
353
354 // Set thread priority
priority(FXint prio)355 void FXThread::priority(FXint prio){
356 sched_param sched={0};
357 int priomin,priomax;
358 if(tid){
359 priomax=sched_get_priority_max(SCHED_OTHER);
360 priomin=sched_get_priority_min(SCHED_OTHER);
361 sched.sched_priority=FXCLAMP(priomin,prio,priomax);
362 pthread_setschedparam((pthread_t)tid,SCHED_OTHER,&sched);
363 }
364 }
365
366
367 // Return thread priority
priority()368 FXint FXThread::priority(){
369 sched_param sched={0};
370 int policy;
371 if(tid){
372 pthread_getschedparam((pthread_t)tid,&policy,&sched);
373 return sched.sched_priority;
374 }
375 return 0;
376 }
377
378
379 // Destroy; if it was running, stop it
~FXThread()380 FXThread::~FXThread(){
381 if(tid){ pthread_cancel((pthread_t)tid); }
382 }
383
384
385 /*******************************************************************************/
386
387 // Windows implementation
388
389 #else
390
391 // Initialize mutex
392 FXMutex::FXMutex(FXbool){
393 // If this fails on your machine, determine what value
394 // of sizeof(CRITICAL_SECTION) is supposed to be on your
395 // machine and mail it to: jeroen@fox-toolkit.org!!
396 //FXTRACE((150,"sizeof(CRITICAL_SECTION)=%d\n",sizeof(CRITICAL_SECTION)));
397 FXASSERT(sizeof(data)>=sizeof(CRITICAL_SECTION));
398 InitializeCriticalSection((CRITICAL_SECTION*)data);
399 }
400
401
402 // Lock the mutex
403 void FXMutex::lock(){
404 EnterCriticalSection((CRITICAL_SECTION*)data);
405 }
406
407
408
409 // Try lock the mutex
410 FXbool FXMutex::trylock(){
411 #if(_WIN32_WINNT >= 0x0400)
412 return TryEnterCriticalSection((CRITICAL_SECTION*)data)!=0;
413 #else
414 return FALSE;
415 #endif
416 }
417
418
419 // Unlock mutex
420 void FXMutex::unlock(){
421 LeaveCriticalSection((CRITICAL_SECTION*)data);
422 }
423
424
425 // Test if locked
426 FXbool FXMutex::locked(){
427 #if(_WIN32_WINNT >= 0x0400)
428 if(TryEnterCriticalSection((CRITICAL_SECTION*)data)==0) return FALSE;
429 LeaveCriticalSection((CRITICAL_SECTION*)data);
430 #endif
431 return TRUE;
432 }
433
434
435 // Delete mutex
436 FXMutex::~FXMutex(){
437 DeleteCriticalSection((CRITICAL_SECTION*)data);
438 }
439
440
441 /*******************************************************************************/
442
443
444 // Initialize semaphore
445 FXSemaphore::FXSemaphore(FXint initial){
446 data[0]=(FXuval)CreateSemaphore(NULL,initial,0x7fffffff,NULL);
447 }
448
449
450 // Decrement semaphore
451 void FXSemaphore::wait(){
452 WaitForSingleObject((HANDLE)data[0],INFINITE);
453 }
454
455
456 // Non-blocking semaphore decrement
457 FXbool FXSemaphore::trywait(){
458 return WaitForSingleObject((HANDLE)data[0],0)==WAIT_OBJECT_0;
459 }
460
461
462 // Increment semaphore
463 void FXSemaphore::post(){
464 ReleaseSemaphore((HANDLE)data[0],1,NULL);
465 }
466
467
468 // Delete semaphore
469 FXSemaphore::~FXSemaphore(){
470 CloseHandle((HANDLE)data[0]);
471 }
472
473
474 /*******************************************************************************/
475
476
477 // This is the solution according to Schmidt, the win32-threads
478 // implementation thereof which is found inside GCC somewhere.
479 // See: (http://www.cs.wustl.edu/~schmidt/win32-cv-1.html).
480 //
481 // Our implementation however initializes the Event objects in
482 // the constructor, under the assumption that you're not creating
483 // condition object if you weren't planning to use them somewhere.
484
485
486 // Initialize condition
487 FXCondition::FXCondition(){
488 // If this fails on your machine, notify jeroen@fox-toolkit.org!
489 FXASSERT(sizeof(data)>=sizeof(CRITICAL_SECTION)+sizeof(HANDLE)+sizeof(HANDLE)+sizeof(FXuval));
490 data[0]=(FXuval)CreateEvent(NULL,0,0,NULL); // Wakes one, autoreset
491 data[1]=(FXuval)CreateEvent(NULL,1,0,NULL); // Wakes all, manual reset
492 data[2]=0; // Blocked count
493 InitializeCriticalSection((CRITICAL_SECTION*)&data[3]); // Critical section
494 }
495
496
497 // Wake up one single waiting thread
498 void FXCondition::signal(){
499 EnterCriticalSection((CRITICAL_SECTION*)&data[3]);
500 int blocked=(data[2]>0);
501 LeaveCriticalSection((CRITICAL_SECTION*)&data[3]);
502 if(blocked) SetEvent((HANDLE)data[0]);
503 }
504
505
506 // Wake up all waiting threads
507 void FXCondition::broadcast(){
508 EnterCriticalSection((CRITICAL_SECTION*)&data[3]);
509 int blocked=(data[2]>0);
510 LeaveCriticalSection((CRITICAL_SECTION*)&data[3]);
511 if(blocked) SetEvent((HANDLE)data[1]);
512 }
513
514
515 // Wait
516 void FXCondition::wait(FXMutex& mtx){
517 EnterCriticalSection((CRITICAL_SECTION*)&data[3]);
518 data[2]++;
519 LeaveCriticalSection((CRITICAL_SECTION*)&data[3]);
520 mtx.unlock();
521 DWORD result=WaitForMultipleObjects(2,(HANDLE*)data,0,INFINITE);
522 EnterCriticalSection((CRITICAL_SECTION*)&data[3]);
523 data[2]--;
524 int last_waiter=(result==WAIT_OBJECT_0+1)&&(data[2]==0); // Unblocked by broadcast & no other blocked threads
525 LeaveCriticalSection((CRITICAL_SECTION*)&data[3]);
526 if(last_waiter) ResetEvent((HANDLE)data[1]); // Reset signal
527 mtx.lock();
528 }
529
530
531 // Wait using single global mutex
532 FXbool FXCondition::wait(FXMutex& mtx,FXuint ms){
533 EnterCriticalSection((CRITICAL_SECTION*)&data[3]);
534 data[2]++;
535 LeaveCriticalSection((CRITICAL_SECTION*)&data[3]);
536 mtx.unlock();
537 DWORD result=WaitForMultipleObjects(2,(HANDLE*)data,0,ms);
538 EnterCriticalSection((CRITICAL_SECTION*)&data[3]);
539 data[2]--;
540 int last_waiter=(result==WAIT_OBJECT_0+1)&&(data[2]==0); // Unblocked by broadcast & no other blocked threads
541 LeaveCriticalSection((CRITICAL_SECTION*)&data[3]);
542 if(last_waiter) ResetEvent((HANDLE)data[1]); // Reset signal
543 mtx.lock();
544 return result!=WAIT_TIMEOUT;
545 }
546
547
548 // Delete condition
549 FXCondition::~FXCondition(){
550 CloseHandle((HANDLE)data[0]);
551 CloseHandle((HANDLE)data[1]);
552 DeleteCriticalSection((CRITICAL_SECTION*)&data[3]);
553 }
554
555
556 /*******************************************************************************/
557
558 // Thread local storage key for back-reference to FXThread
559 static DWORD self_key=0xffffffff;
560
561 // Global initializer for the self_key variable
562 struct TLSKEYINIT {
563 TLSKEYINIT(){ self_key=TlsAlloc(); }
564 ~TLSKEYINIT(){ TlsFree(self_key); }
565 };
566
567 // Extern declaration prevents overzealous optimizer from noticing we're
568 // never using this object, and subsequently eliminating it from the code.
569 extern TLSKEYINIT initializer;
570
571 // Dummy object causes global initializer to run
572 TLSKEYINIT initializer;
573
574
575 // Initialize thread
576 FXThread::FXThread():tid(0){
577 }
578
579
580 // Return thread id of this thread object.
581 // Purposefully NOT inlined, the tid may be changed by another
582 // thread and therefore we must force the compiler to fetch
583 // this value fresh each time it is needed!
584 FXThreadID FXThread::id() const {
585 return tid;
586 }
587
588
589 // Return TRUE if this thread is running
590 FXbool FXThread::running() const {
591 return tid!=0;
592 }
593
594
595 // Start the thread; we associate the FXThread instance with
596 // this thread using thread-local storage accessed with self_key.
597 // Also, we catch any errors thrown by the thread code here.
598 unsigned int CALLBACK FXThread::execute(void* thread){
599 register FXint code=-1;
600 TlsSetValue(self_key,thread);
601 try{ code=((FXThread*)thread)->run(); } catch(...){ }
602 return code;
603 }
604
605
606 // Start thread
607 FXbool FXThread::start(unsigned long stacksize){
608 DWORD thd;
609 tid=(FXThreadID)CreateThread(NULL,stacksize,(LPTHREAD_START_ROUTINE)FXThread::execute,this,0,&thd);
610 return tid!=NULL;
611 }
612
613
614 // Suspend calling thread until thread is done
615 FXbool FXThread::join(FXint& code){
616 if(tid && WaitForSingleObject((HANDLE)tid,INFINITE)==WAIT_OBJECT_0){
617 GetExitCodeThread((HANDLE)tid,(DWORD*)&code);
618 CloseHandle((HANDLE)tid);
619 tid=0;
620 return TRUE;
621 }
622 return FALSE;
623 }
624
625
626 // Suspend calling thread until thread is done
627 FXbool FXThread::join(){
628 if(tid && WaitForSingleObject((HANDLE)tid,INFINITE)==WAIT_OBJECT_0){
629 CloseHandle((HANDLE)tid);
630 tid=0;
631 return TRUE;
632 }
633 return FALSE;
634 }
635
636
637 // Cancel the thread
638 FXbool FXThread::cancel(){
639 if(tid && TerminateThread((HANDLE)tid,0)){
640 CloseHandle((HANDLE)tid);
641 tid=0;
642 return TRUE;
643 }
644 return FALSE;
645 }
646
647
648 // Detach thread
649 FXbool FXThread::detach(){
650 return tid!=0;
651 }
652
653
654 // Exit calling thread
655 void FXThread::exit(FXint code){
656 ExitThread(code);
657 }
658
659
660 // Yield the thread
661 void FXThread::yield(){
662 Sleep(0);
663 }
664
665
666 // Sleep for some time
667 void FXThread::sleep(unsigned long sec,unsigned long nsec){
668 Sleep(sec*1000+nsec/1000000);
669 }
670
671
672 // Return thread id of caller
673 FXThreadID FXThread::current(){
674 return (FXThreadID)GetCurrentThreadId();
675 }
676
677
678 // Return pointer to calling thread's instance
679 FXThread* FXThread::self(){
680 return (FXThread*)TlsGetValue(self_key);
681 }
682
683
684 // Set thread priority
685 void FXThread::priority(FXint prio){
686 if(tid){
687 SetThreadPriority((HANDLE)tid,prio);
688 }
689 }
690
691
692 // Return thread priority
693 FXint FXThread::priority(){
694 if(tid){
695 return GetThreadPriority((HANDLE)tid);
696 }
697 return 0;
698 }
699
700
701 // Destroy
702 FXThread::~FXThread(){
703 if(tid){ TerminateThread((HANDLE)tid,0); CloseHandle((HANDLE)tid); }
704 }
705
706
707 #endif
708
709
710 }
711