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