]> git.saurik.com Git - wxWidgets.git/blob - src/unix/threadpsx.cpp
another attempt to improve combobox behaviour
[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 create thread 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 if ( pthread_setspecific(gs_keySelf, thread) != 0 )
283 {
284 wxLogError(_("Can not start thread: error writing TLS."));
285
286 return (void *)-1;
287 }
288
289 // wait for the condition to be signaled from Run()
290 // mutex state: currently locked by the thread which created us
291 pthread->m_cond.Wait(pthread->m_mutex);
292
293 // mutex state: locked again on exit of Wait()
294
295 // call the main entry
296 void* status = thread->Entry();
297
298 // terminate the thread
299 thread->Exit(status);
300
301 wxFAIL_MSG("wxThread::Exit() can't return.");
302
303 return NULL;
304 }
305
306 wxThreadInternal::wxThreadInternal()
307 {
308 m_state = STATE_NEW;
309 m_cancelled = FALSE;
310
311 // this mutex is locked during almost all thread lifetime - it will only be
312 // unlocked in the very end
313 m_mutex.Lock();
314
315 // this mutex is used in Pause()/Resume() and is also locked all the time
316 // unless the thread is paused
317 m_mutexSuspend.Lock();
318 }
319
320 wxThreadInternal::~wxThreadInternal()
321 {
322 m_mutexSuspend.Unlock();
323
324 // note that m_mutex will be unlocked by the thread which waits for our
325 // termination
326 }
327
328 wxThreadError wxThreadInternal::Run()
329 {
330 wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING,
331 "thread may only be started once after successful Create()" );
332
333 // the mutex was locked on Create(), so we will be able to lock it again
334 // only when the thread really starts executing and enters the wait -
335 // otherwise we might signal the condition before anybody is waiting for it
336 wxMutexLocker lock(m_mutex);
337 m_cond.Signal();
338
339 m_state = STATE_RUNNING;
340
341 return wxTHREAD_NO_ERROR;
342
343 // now the mutex is unlocked back - but just to allow Wait() function to
344 // terminate by relocking it, so the net result is that the worker thread
345 // starts executing and the mutex is still locked
346 }
347
348 void wxThreadInternal::Cancel()
349 {
350 // if the thread we're waiting for is waiting for the GUI mutex, we will
351 // deadlock so make sure we release it temporarily
352 if ( wxThread::IsMain() )
353 wxMutexGuiLeave();
354
355 // nobody ever writes this variable so it's safe to not use any
356 // synchronization here
357 m_cancelled = TRUE;
358
359 // entering Wait() releases the mutex thus allowing SignalExit() to acquire
360 // it and to signal us its termination
361 m_cond.Wait(m_mutex);
362
363 // mutex is still in the locked state - relocked on exit from Wait(), so
364 // unlock it - we don't need it any more, the thread has already terminated
365 m_mutex.Unlock();
366
367 // reacquire GUI mutex
368 if ( wxThread::IsMain() )
369 wxMutexGuiEnter();
370 }
371
372 void wxThreadInternal::SignalExit()
373 {
374 // as mutex is currently locked, this will block until some other thread
375 // (normally the same which created this one) unlocks it by entering Wait()
376 m_mutex.Lock();
377
378 // wake up all the threads waiting for our termination
379 m_cond.Broadcast();
380
381 // after this call mutex will be finally unlocked
382 m_mutex.Unlock();
383 }
384
385 void wxThreadInternal::Pause()
386 {
387 wxCHECK_RET( m_state == STATE_PAUSED,
388 "thread must first be paused with wxThread::Pause()." );
389
390 // wait until the condition is signaled from Resume()
391 m_condSuspend.Wait(m_mutexSuspend);
392 }
393
394 void wxThreadInternal::Resume()
395 {
396 wxCHECK_RET( m_state == STATE_PAUSED,
397 "can't resume thread which is not suspended." );
398
399 // we will be able to lock this mutex only when Pause() starts waiting
400 wxMutexLocker lock(m_mutexSuspend);
401 m_condSuspend.Signal();
402
403 SetState(STATE_RUNNING);
404 }
405
406 // -----------------------------------------------------------------------------
407 // static functions
408 // -----------------------------------------------------------------------------
409
410 wxThread *wxThread::This()
411 {
412 return (wxThread *)pthread_getspecific(gs_keySelf);
413 }
414
415 bool wxThread::IsMain()
416 {
417 return (bool)pthread_equal(pthread_self(), gs_tidMain);
418 }
419
420 void wxThread::Yield()
421 {
422 sched_yield();
423 }
424
425 void wxThread::Sleep(unsigned long milliseconds)
426 {
427 wxUsleep(milliseconds);
428 }
429
430 // -----------------------------------------------------------------------------
431 // creating thread
432 // -----------------------------------------------------------------------------
433
434 wxThread::wxThread()
435 {
436 // add this thread to the global list of all threads
437 gs_allThreads.Add(this);
438
439 p_internal = new wxThreadInternal();
440 }
441
442 wxThreadError wxThread::Create()
443 {
444 if (p_internal->GetState() != STATE_NEW)
445 return wxTHREAD_RUNNING;
446
447 // set up the thread attribute: right now, we only set thread priority
448 pthread_attr_t attr;
449 pthread_attr_init(&attr);
450
451 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
452 int prio;
453 if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 )
454 {
455 wxLogError(_("Can not retrieve thread scheduling policy."));
456 }
457
458 int min_prio = sched_get_priority_min(prio),
459 max_prio = sched_get_priority_max(prio);
460
461 if ( min_prio == -1 || max_prio == -1 )
462 {
463 wxLogError(_("Can not get priority range for scheduling policy %d."),
464 prio);
465 }
466 else
467 {
468 struct sched_param sp;
469 pthread_attr_getschedparam(&attr, &sp);
470 sp.sched_priority = min_prio +
471 (p_internal->GetPriority()*(max_prio-min_prio))/100;
472 pthread_attr_setschedparam(&attr, &sp);
473 }
474 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
475
476 // create the new OS thread object
477 int rc = pthread_create(&p_internal->thread_id, &attr,
478 wxThreadInternal::PthreadStart, (void *)this);
479 pthread_attr_destroy(&attr);
480
481 if ( rc != 0 )
482 {
483 p_internal->SetState(STATE_EXITED);
484 return wxTHREAD_NO_RESOURCE;
485 }
486
487 return wxTHREAD_NO_ERROR;
488 }
489
490 wxThreadError wxThread::Run()
491 {
492 return p_internal->Run();
493 }
494
495 // -----------------------------------------------------------------------------
496 // misc accessors
497 // -----------------------------------------------------------------------------
498
499 void wxThread::SetPriority(unsigned int prio)
500 {
501 wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY <= (int)prio) &&
502 ((int)prio <= (int)WXTHREAD_MAX_PRIORITY),
503 "invalid thread priority" );
504
505 wxCriticalSectionLocker lock(m_critsect);
506
507 switch ( p_internal->GetState() )
508 {
509 case STATE_NEW:
510 // thread not yet started, priority will be set when it is
511 p_internal->SetPriority(prio);
512 break;
513
514 case STATE_RUNNING:
515 case STATE_PAUSED:
516 #ifdef HAVE_THREAD_PRIORITY_FUNCTIONS
517 {
518 struct sched_param sparam;
519 sparam.sched_priority = prio;
520
521 if ( pthread_setschedparam(p_internal->GetId(),
522 SCHED_OTHER, &sparam) != 0 )
523 {
524 wxLogError(_("Failed to set thread priority %d."), prio);
525 }
526 }
527 #endif // HAVE_THREAD_PRIORITY_FUNCTIONS
528 break;
529
530 case STATE_EXITED:
531 default:
532 wxFAIL_MSG("impossible to set thread priority in this state");
533 }
534 }
535
536 unsigned int wxThread::GetPriority() const
537 {
538 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
539
540 return p_internal->GetPriority();
541 }
542
543 unsigned long wxThread::GetID() const
544 {
545 return (unsigned long)p_internal->thread_id;
546 }
547
548 // -----------------------------------------------------------------------------
549 // pause/resume
550 // -----------------------------------------------------------------------------
551
552 wxThreadError wxThread::Pause()
553 {
554 wxCriticalSectionLocker lock(m_critsect);
555
556 if ( p_internal->GetState() != STATE_RUNNING )
557 {
558 wxLogDebug("Can't pause thread which is not running.");
559
560 return wxTHREAD_NOT_RUNNING;
561 }
562
563 p_internal->SetState(STATE_PAUSED);
564
565 return wxTHREAD_NO_ERROR;
566 }
567
568 wxThreadError wxThread::Resume()
569 {
570 wxCriticalSectionLocker lock(m_critsect);
571
572 if ( p_internal->GetState() == STATE_PAUSED )
573 {
574 p_internal->Resume();
575
576 return wxTHREAD_NO_ERROR;
577 }
578 else
579 {
580 wxLogDebug("Attempt to resume a thread which is not paused.");
581
582 return wxTHREAD_MISC_ERROR;
583 }
584 }
585
586 // -----------------------------------------------------------------------------
587 // exiting thread
588 // -----------------------------------------------------------------------------
589
590 wxThread::ExitCode wxThread::Delete()
591 {
592 m_critsect.Enter();
593 thread_state state = p_internal->GetState();
594 m_critsect.Leave();
595
596 switch ( state )
597 {
598 case STATE_NEW:
599 case STATE_EXITED:
600 // nothing to do
601 break;
602
603 case STATE_PAUSED:
604 // resume the thread first
605 Resume();
606
607 // fall through
608
609 default:
610 // set the flag telling to the thread to stop and wait
611 p_internal->Cancel();
612 }
613
614 return NULL;
615 }
616
617 wxThreadError wxThread::Kill()
618 {
619 switch ( p_internal->GetState() )
620 {
621 case STATE_NEW:
622 case STATE_EXITED:
623 return wxTHREAD_NOT_RUNNING;
624
625 default:
626 #ifdef HAVE_PTHREAD_CANCEL
627 if ( pthread_cancel(p_internal->GetId()) != 0 )
628 #endif
629 {
630 wxLogError(_("Failed to terminate a thread."));
631
632 return wxTHREAD_MISC_ERROR;
633 }
634
635 return wxTHREAD_NO_ERROR;
636 }
637 }
638
639 void wxThread::Exit(void *status)
640 {
641 // first call user-level clean up code
642 OnExit();
643
644 // next wake up the threads waiting for us (OTOH, this function won't return
645 // until someone waited for us!)
646 p_internal->SignalExit();
647
648 p_internal->SetState(STATE_EXITED);
649
650 // delete both C++ thread object and terminate the OS thread object
651 delete this;
652 pthread_exit(status);
653 }
654
655 // also test whether we were paused
656 bool wxThread::TestDestroy()
657 {
658 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
659
660 if ( p_internal->GetState() == STATE_PAUSED )
661 {
662 // leave the crit section or the other threads will stop too if they try
663 // to call any of (seemingly harmless) IsXXX() functions while we sleep
664 m_critsect.Leave();
665
666 p_internal->Pause();
667
668 // enter it back before it's finally left in lock object dtor
669 m_critsect.Enter();
670 }
671
672 return p_internal->WasCancelled();
673 }
674
675 wxThread::~wxThread()
676 {
677 // remove this thread from the global array
678 gs_allThreads.Remove(this);
679 }
680
681 // -----------------------------------------------------------------------------
682 // state tests
683 // -----------------------------------------------------------------------------
684
685 bool wxThread::IsRunning() const
686 {
687 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
688
689 return p_internal->GetState() == STATE_RUNNING;
690 }
691
692 bool wxThread::IsAlive() const
693 {
694 wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect);
695
696 switch ( p_internal->GetState() )
697 {
698 case STATE_RUNNING:
699 case STATE_PAUSED:
700 return TRUE;
701
702 default:
703 return FALSE;
704 }
705 }
706
707 //--------------------------------------------------------------------
708 // wxThreadModule
709 //--------------------------------------------------------------------
710
711 class wxThreadModule : public wxModule
712 {
713 public:
714 virtual bool OnInit();
715 virtual void OnExit();
716
717 private:
718 DECLARE_DYNAMIC_CLASS(wxThreadModule)
719 };
720
721 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
722
723 bool wxThreadModule::OnInit()
724 {
725 if ( pthread_key_create(&gs_keySelf, NULL /* dtor function */) != 0 )
726 {
727 wxLogError(_("Thread module initialization failed: "
728 "failed to create pthread key."));
729
730 return FALSE;
731 }
732
733 gs_mutexGui = new wxMutex();
734
735 //wxThreadGuiInit();
736
737 gs_tidMain = pthread_self();
738 gs_mutexGui->Lock();
739
740 return TRUE;
741 }
742
743 void wxThreadModule::OnExit()
744 {
745 wxASSERT_MSG( wxThread::IsMain(), "only main thread can be here" );
746
747 // terminate any threads left
748 size_t count = gs_allThreads.GetCount();
749 if ( count != 0u )
750 wxLogDebug("Some threads were not terminated by the application.");
751
752 for ( size_t n = 0u; n < count; n++ )
753 {
754 gs_allThreads[n]->Delete();
755 }
756
757 // destroy GUI mutex
758 gs_mutexGui->Unlock();
759
760 //wxThreadGuiExit();
761
762 delete gs_mutexGui;
763
764 // and free TLD slot
765 (void)pthread_key_delete(gs_keySelf);
766 }
767
768 // ----------------------------------------------------------------------------
769 // global functions
770 // ----------------------------------------------------------------------------
771
772 void wxMutexGuiEnter()
773 {
774 gs_mutexGui->Lock();
775 }
776
777 void wxMutexGuiLeave()
778 {
779 gs_mutexGui->Unlock();
780 }
781