]> git.saurik.com Git - wxWidgets.git/blob - src/motif/thread.cpp
compilation fixes
[wxWidgets.git] / src / motif / thread.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: threadpsx.cpp
3 // Purpose: wxThread (Posix) Implementation
4 // Author: Original from Wolfram Gloger/Guilhem Lavaux
5 // Modified by:
6 // Created: 04/22/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Wolfram Gloger (1996, 1997)
9 // Guilhem Lavaux (1998)
10 // Robert Roebling (1999)
11 // Licence: wxWindows licence
12 /////////////////////////////////////////////////////////////////////////////
13
14 #ifdef __GNUG__
15 #pragma implementation "thread.h"
16 #endif
17
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <pthread.h>
21 #include <errno.h>
22
23 #ifdef __linux__
24 #include <sched.h>
25 #endif
26
27 #include "wx/thread.h"
28 #include "wx/module.h"
29 #include "wx/utils.h"
30 #include "wx/log.h"
31 #include "wx/intl.h"
32 #include "wx/dynarray.h"
33
34 enum thread_state
35 {
36 STATE_NEW, // didn't start execution yet (=> RUNNING)
37 STATE_RUNNING,
38 STATE_PAUSED,
39 STATE_CANCELED,
40 STATE_EXITED
41 };
42
43 WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
44
45 // -----------------------------------------------------------------------------
46 // global data
47 // -----------------------------------------------------------------------------
48
49 // we keep the list of all threads created by the application to be able to
50 // terminate them on exit if there are some left - otherwise the process would
51 // be left in memory
52 static wxArrayThread gs_allThreads;
53
54 // the id of the main thread
55 static pthread_t gs_tidMain;
56
57 // the key for the pointer to the associated wxThread object
58 static pthread_key_t gs_keySelf;
59
60 // this mutex must be acquired before any call to a GUI function
61 static wxMutex *gs_mutexGui;
62
63 //--------------------------------------------------------------------
64 // common GUI thread code
65 //--------------------------------------------------------------------
66
67 //--------------------------------------------------------------------
68 // wxMutex (Posix implementation)
69 //--------------------------------------------------------------------
70
71 class wxMutexInternal
72 {
73 public:
74 pthread_mutex_t p_mutex;
75 };
76
77 wxMutex::wxMutex()
78 {
79 p_internal = new wxMutexInternal;
80 pthread_mutex_init( &(p_internal->p_mutex), (const pthread_mutexattr_t*) NULL );
81 m_locked = 0;
82 }
83
84 wxMutex::~wxMutex()
85 {
86 if (m_locked > 0)
87 wxLogDebug("Freeing a locked mutex (%d locks)", m_locked);
88
89 pthread_mutex_destroy( &(p_internal->p_mutex) );
90 delete p_internal;
91 }
92
93 wxMutexError wxMutex::Lock()
94 {
95 int err = pthread_mutex_lock( &(p_internal->p_mutex) );
96 if (err == EDEADLK)
97 {
98 wxLogDebug("Locking this mutex would lead to deadlock!");
99
100 return wxMUTEX_DEAD_LOCK;
101 }
102
103 m_locked++;
104
105 return wxMUTEX_NO_ERROR;
106 }
107
108 wxMutexError wxMutex::TryLock()
109 {
110 if (m_locked)
111 {
112 return wxMUTEX_BUSY;
113 }
114
115 int err = pthread_mutex_trylock( &(p_internal->p_mutex) );
116 switch (err)
117 {
118 case EBUSY: return wxMUTEX_BUSY;
119 }
120
121 m_locked++;
122
123 return wxMUTEX_NO_ERROR;
124 }
125
126 wxMutexError wxMutex::Unlock()
127 {
128 if (m_locked > 0)
129 {
130 m_locked--;
131 }
132 else
133 {
134 wxLogDebug("Unlocking not locked mutex.");
135
136 return wxMUTEX_UNLOCKED;
137 }
138
139 pthread_mutex_unlock( &(p_internal->p_mutex) );
140
141 return wxMUTEX_NO_ERROR;
142 }
143
144 //--------------------------------------------------------------------
145 // wxCondition (Posix implementation)
146 //--------------------------------------------------------------------
147
148 class wxConditionInternal
149 {
150 public:
151 pthread_cond_t p_condition;
152 };
153
154 wxCondition::wxCondition()
155 {
156 p_internal = new wxConditionInternal;
157 pthread_cond_init( &(p_internal->p_condition), (const pthread_condattr_t *) NULL );
158 }
159
160 wxCondition::~wxCondition()
161 {
162 pthread_cond_destroy( &(p_internal->p_condition) );
163
164 delete p_internal;
165 }
166
167 void wxCondition::Wait(wxMutex& mutex)
168 {
169 pthread_cond_wait( &(p_internal->p_condition), &(mutex.p_internal->p_mutex) );
170 }
171
172 bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec)
173 {
174 struct timespec tspec;
175
176 tspec.tv_sec = time(0L)+sec;
177 tspec.tv_nsec = nsec;
178 return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT);
179 }
180
181 void wxCondition::Signal()
182 {
183 pthread_cond_signal( &(p_internal->p_condition) );
184 }
185
186 void wxCondition::Broadcast()
187 {
188 pthread_cond_broadcast( &(p_internal->p_condition) );
189 }
190
191 //--------------------------------------------------------------------
192 // wxThread (Posix implementation)
193 //--------------------------------------------------------------------
194
195 class wxThreadInternal
196 {
197 public:
198 wxThreadInternal();
199 ~wxThreadInternal();
200
201 // thread entry function
202 static void *PthreadStart(void *ptr);
203
204 // thread actions
205 // start the thread
206 wxThreadError Run();
207 // ask the thread to terminate
208 void Cancel();
209 // wake up threads waiting for our termination
210 void SignalExit();
211 // go to sleep until Resume() is called
212 void Pause();
213 // resume the thread
214 void Resume();
215
216 // accessors
217 // priority
218 int GetPriority() const { return m_prio; }
219 void SetPriority(int prio) { m_prio = prio; }
220 // state
221 thread_state GetState() const { return m_state; }
222 void SetState(thread_state state) { m_state = state; }
223 // id
224 pthread_t GetId() const { return thread_id; }
225 // "cancelled" flag
226 bool WasCancelled() const { return m_cancelled; }
227
228 //private: -- should be!
229 pthread_t thread_id;
230
231 private:
232 thread_state m_state; // see thread_state enum
233 int m_prio; // in wxWindows units: from 0 to 100
234
235 // set when the thread should terminate
236 bool m_cancelled;
237
238 // this (mutex, cond) pair is used to synchronize the main thread and this
239 // thread in several situations:
240 // 1. The thread function blocks until condition is signaled by Run() when
241 // it's initially created - this allows create thread in "suspended"
242 // state
243 // 2. The Delete() function blocks until the condition is signaled when the
244 // thread exits.
245 wxMutex m_mutex;
246 wxCondition m_cond;
247
248 // another (mutex, cond) pair for Pause()/Resume() usage
249 //
250 // VZ: it's possible that we might reuse the mutex and condition from above
251 // for this too, but as I'm not at all sure that it won't create subtle
252 // problems with race conditions between, say, Pause() and Delete() I
253 // prefer this may be a bit less efficient but much safer solution
254 wxMutex m_mutexSuspend;
255 wxCondition m_condSuspend;
256 };
257
258 void *wxThreadInternal::PthreadStart(void *ptr)
259 {
260 wxThread *thread = (wxThread *)ptr;
261 wxThreadInternal *pthread = thread->p_internal;
262
263 if ( pthread_setspecific(gs_keySelf, thread) != 0 )
264 {
265 wxLogError(_("Can not start thread: error writing TLS."));
266
267 return (void *)-1;
268 }
269
270 // wait for the condition to be signaled from Run()
271 // mutex state: currently locked by the thread which created us
272 pthread->m_cond.Wait(pthread->m_mutex);
273
274 // mutex state: locked again on exit of Wait()
275
276 // call the main entry
277 void* status = thread->Entry();
278
279 // terminate the thread
280 thread->Exit(status);
281
282 wxFAIL_MSG("wxThread::Exit() can't return.");
283
284 return NULL;
285 }
286
287 wxThreadInternal::wxThreadInternal()
288 {
289 m_state = STATE_NEW;
290 m_cancelled = FALSE;
291
292 // this mutex is locked during almost all thread lifetime - it will only be
293 // unlocked in the very end
294 m_mutex.Lock();
295
296 // this mutex is used in Pause()/Resume() and is also locked all the time
297 // unless the thread is paused
298 m_mutexSuspend.Lock();
299 }
300
301 wxThreadInternal::~wxThreadInternal()
302 {
303 m_mutexSuspend.Unlock();
304
305 // note that m_mutex will be unlocked by the thread which waits for our
306 // termination
307 }
308
309 wxThreadError wxThreadInternal::Run()
310 {
311 wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
312 "thread may only be started once after successful Create()" );
313
314 // the mutex was locked on Create(), so we will be able to lock it again
315 // only when the thread really starts executing and enters the wait -
316 // otherwise we might signal the condition before anybody is waiting for it
317 wxMutexLocker lock(m_mutex);
318 m_cond.Signal();
319
320 m_state = STATE_RUNNING;
321
322 return wxTHREAD_NO_ERROR;
323
324 // now the mutex is unlocked back - but just to allow Wait() function to
325 // terminate by relocking it, so the net result is that the worker thread
326 // starts executing and the mutex is still locked
327 }
328
329 void wxThreadInternal::Cancel()
330 {
331 // if the thread we're waiting for is waiting for the GUI mutex, we will
332 // deadlock so make sure we release it temporarily
333 if ( wxThread::IsMain() )
334 wxMutexGuiLeave();
335
336 // nobody ever writes this variable so it's safe to not use any
337 // synchronization here
338 m_cancelled = TRUE;
339
340 // entering Wait() releases the mutex thus allowing SignalExit() to acquire
341 // it and to signal us its termination
342 m_cond.Wait(m_mutex);
343
344 // mutex is still in the locked state - relocked on exit from Wait(), so
345 // unlock it - we don't need it any more, the thread has already terminated
346 m_mutex.Unlock();
347
348 // reacquire GUI mutex
349 if ( wxThread::IsMain() )
350 wxMutexGuiEnter();
351 }
352
353 void wxThreadInternal::SignalExit()
354 {
355 // as mutex is currently locked, this will block until some other thread
356 // (normally the same which created this one) unlocks it by entering Wait()
357 m_mutex.Lock();
358
359 // wake up all the threads waiting for our termination
360 m_cond.Broadcast();
361
362 // after this call mutex will be finally unlocked
363 m_mutex.Unlock();
364 }
365
366 void wxThreadInternal::Pause()
367 {
368 wxCHECK_RET( m_state == STATE_PAUSED,
369 "thread must first be paused with wxThread::Pause()." );
370
371 // wait until the condition is signaled from Resume()
372 m_condSuspend.Wait(m_mutexSuspend);
373 }
374
375 void wxThreadInternal::Resume()
376 {
377 wxCHECK_RET( m_state == STATE_PAUSED,
378 "can't resume thread which is not suspended." );
379
380 // we will be able to lock this mutex only when Pause() starts waiting
381 wxMutexLocker lock(m_mutexSuspend);
382 m_condSuspend.Signal();
383
384 SetState(STATE_RUNNING);
385 }
386
387 // -----------------------------------------------------------------------------
388 // static functions
389 // -----------------------------------------------------------------------------
390
391 wxThread *wxThread::This()
392 {
393 return (wxThread *)pthread_getspecific(gs_keySelf);
394 }
395
396 bool wxThread::IsMain()
397 {
398 return (bool)pthread_equal(pthread_self(), gs_tidMain);
399 }
400
401 void wxThread::Yield()
402 {
403 sched_yield();
404 }
405
406 void wxThread::Sleep(unsigned long milliseconds)
407 {
408 wxUsleep(milliseconds);
409 }
410
411 // -----------------------------------------------------------------------------
412 // creating thread
413 // -----------------------------------------------------------------------------
414
415 wxThread::wxThread()
416 {
417 // add this thread to the global list of all threads
418 gs_allThreads.Add(this);
419
420 p_internal = new wxThreadInternal();
421 }
422
423 wxThreadError wxThread::Create()
424 {
425 if (p_internal->GetState() != STATE_NEW)
426 return wxTHREAD_RUNNING;
427
428 // set up the thread attribute: right now, we only set thread priority
429 pthread_attr_t attr;
430 pthread_attr_init(&attr);
431
432 int prio;
433 if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 )
434 {
435 wxLogError(_("Can not retrieve thread scheduling policy."));
436 }
437
438 int min_prio = sched_get_priority_min(prio),
439 max_prio = sched_get_priority_max(prio);
440
441 if ( min_prio == -1 || max_prio == -1 )
442 {
443 wxLogError(_("Can not get priority range for scheduling policy %d."),
444 prio);
445 }
446 else
447 {
448 struct sched_param sp;
449 pthread_attr_getschedparam(&attr, &sp);
450 sp.sched_priority = min_prio +
451 (p_internal->GetPriority()*(max_prio-min_prio))/100;
452 pthread_attr_setschedparam(&attr, &sp);
453 }
454
455 // create the new OS thread object
456 int rc = pthread_create(&p_internal->thread_id, &attr,
457 wxThreadInternal::PthreadStart,
458 (void *)this);
459 pthread_attr_destroy(&attr);
460
461 if ( rc != 0 )
462 {
463 p_internal->SetState(STATE_EXITED);
464 return wxTHREAD_NO_RESOURCE;
465 }
466
467 return wxTHREAD_NO_ERROR;
468 }
469
470 wxThreadError wxThread::Run()
471 {
472 return p_internal->Run();
473 }
474
475 // -----------------------------------------------------------------------------
476 // misc accessors
477 // -----------------------------------------------------------------------------
478
479 void wxThread::SetPriority(unsigned int prio)
480 {
481 wxCHECK_RET( (WXTHREAD_MIN_PRIORITY <= prio) &&
482 (prio <= WXTHREAD_MAX_PRIORITY), "invalid thread priority" );
483
484 wxCriticalSectionLocker lock(m_critsect);
485
486 switch ( p_internal->GetState() )
487 {
488 case STATE_NEW:
489 // thread not yet started, priority will be set when it is
490 p_internal->SetPriority(prio);
491 break;
492
493 case STATE_RUNNING:
494 case STATE_PAUSED:
495 {
496 struct sched_param sparam;
497 sparam.sched_priority = prio;
498
499 if ( pthread_setschedparam(p_internal->GetId(),
500 SCHED_OTHER, &sparam) != 0 )
501 {
502 wxLogError(_("Failed to set thread priority %d."), prio);
503 }
504 }
505 break;
506
507 case STATE_EXITED:
508 default:
509 wxFAIL_MSG("impossible to set thread priority in this state");
510 }
511 }
512
513 unsigned int wxThread::GetPriority() const
514 {
515 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
516
517 return p_internal->GetPriority();
518 }
519
520 unsigned long wxThread::GetID() const
521 {
522 return (unsigned long)p_internal->thread_id;
523 }
524
525 // -----------------------------------------------------------------------------
526 // pause/resume
527 // -----------------------------------------------------------------------------
528
529 wxThreadError wxThread::Pause()
530 {
531 wxCriticalSectionLocker lock(m_critsect);
532
533 if ( p_internal->GetState() != STATE_RUNNING )
534 {
535 wxLogDebug("Can't pause thread which is not running.");
536
537 return wxTHREAD_NOT_RUNNING;
538 }
539
540 p_internal->SetState(STATE_PAUSED);
541
542 return wxTHREAD_NO_ERROR;
543 }
544
545 wxThreadError wxThread::Resume()
546 {
547 wxCriticalSectionLocker lock(m_critsect);
548
549 if ( p_internal->GetState() == STATE_PAUSED )
550 {
551 p_internal->Resume();
552
553 return wxTHREAD_NO_ERROR;
554 }
555 else
556 {
557 wxLogDebug("Attempt to resume a thread which is not paused.");
558
559 return wxTHREAD_MISC_ERROR;
560 }
561 }
562
563 // -----------------------------------------------------------------------------
564 // exiting thread
565 // -----------------------------------------------------------------------------
566
567 wxThread::ExitCode wxThread::Delete()
568 {
569 m_critsect.Enter();
570 thread_state state = p_internal->GetState();
571 m_critsect.Leave();
572
573 switch ( state )
574 {
575 case STATE_NEW:
576 case STATE_EXITED:
577 // nothing to do
578 break;
579
580 case STATE_PAUSED:
581 // resume the thread first
582 Resume();
583
584 // fall through
585
586 default:
587 // set the flag telling to the thread to stop and wait
588 p_internal->Cancel();
589 }
590
591 return NULL;
592 }
593
594 wxThreadError wxThread::Kill()
595 {
596 switch ( p_internal->GetState() )
597 {
598 case STATE_NEW:
599 case STATE_EXITED:
600 return wxTHREAD_NOT_RUNNING;
601
602 default:
603 if ( pthread_cancel(p_internal->GetId()) != 0 )
604 {
605 wxLogError(_("Failed to terminate a thread."));
606
607 return wxTHREAD_MISC_ERROR;
608 }
609
610 return wxTHREAD_NO_ERROR;
611 }
612 }
613
614 void wxThread::Exit(void *status)
615 {
616 // first call user-level clean up code
617 OnExit();
618
619 // next wake up the threads waiting for us (OTOH, this function won't return
620 // until someone waited for us!)
621 p_internal->SignalExit();
622
623 p_internal->SetState(STATE_EXITED);
624
625 // delete both C++ thread object and terminate the OS thread object
626 delete this;
627 pthread_exit(status);
628 }
629
630 // also test whether we were paused
631 bool wxThread::TestDestroy()
632 {
633 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
634
635 if ( p_internal->GetState() == STATE_PAUSED )
636 {
637 // leave the crit section or the other threads will stop too if they try
638 // to call any of (seemingly harmless) IsXXX() functions while we sleep
639 m_critsect.Leave();
640
641 p_internal->Pause();
642
643 // enter it back before it's finally left in lock object dtor
644 m_critsect.Enter();
645 }
646
647 return p_internal->WasCancelled();
648 }
649
650 wxThread::~wxThread()
651 {
652 // remove this thread from the global array
653 gs_allThreads.Remove(this);
654 }
655
656 // -----------------------------------------------------------------------------
657 // state tests
658 // -----------------------------------------------------------------------------
659
660 bool wxThread::IsRunning() const
661 {
662 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
663
664 return p_internal->GetState() == STATE_RUNNING;
665 }
666
667 bool wxThread::IsAlive() const
668 {
669 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
670
671 switch ( p_internal->GetState() )
672 {
673 case STATE_RUNNING:
674 case STATE_PAUSED:
675 return TRUE;
676
677 default:
678 return FALSE;
679 }
680 }
681
682 //--------------------------------------------------------------------
683 // wxThreadModule
684 //--------------------------------------------------------------------
685
686 class wxThreadModule : public wxModule
687 {
688 public:
689 virtual bool OnInit();
690 virtual void OnExit();
691
692 private:
693 DECLARE_DYNAMIC_CLASS(wxThreadModule)
694 };
695
696 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
697
698 bool wxThreadModule::OnInit()
699 {
700 if ( pthread_key_create(&gs_keySelf, NULL /* dtor function */) != 0 )
701 {
702 wxLogError(_("Thread module initialization failed: "
703 "failed to create pthread key."));
704
705 return FALSE;
706 }
707
708 gs_mutexGui = new wxMutex();
709 //wxThreadGuiInit();
710 gs_tidMain = pthread_self();
711 gs_mutexGui->Lock();
712
713 return TRUE;
714 }
715
716 void wxThreadModule::OnExit()
717 {
718 wxASSERT_MSG( wxThread::IsMain(), "only main thread can be here" );
719
720 // terminate any threads left
721 size_t count = gs_allThreads.GetCount();
722 if ( count != 0u )
723 wxLogDebug("Some threads were not terminated by the application.");
724
725 for ( size_t n = 0u; n < count; n++ )
726 {
727 gs_allThreads[n]->Delete();
728 }
729
730 // destroy GUI mutex
731 gs_mutexGui->Unlock();
732 //wxThreadGuiExit();
733 delete gs_mutexGui;
734
735 // and free TLD slot
736 (void)pthread_key_delete(gs_keySelf);
737 }
738
739 void wxMutexGuiEnter()
740 {
741 gs_mutexGui->Lock();
742 }
743
744 void wxMutexGuiLeave()
745 {
746 gs_mutexGui->Unlock();
747 }