]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/thread.cpp
adapted to mac
[wxWidgets.git] / src / mac / carbon / thread.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: thread.cpp
3 // Purpose: wxThread Implementation
4 // Author: Original from Wolfram Gloger/Guilhem Lavaux
5 // Modified by: Vadim Zeitlin to make it work :-)
6 // Created: 04/22/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998),
9 // Vadim Zeitlin (1999)
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 #ifdef __GNUG__
14 #pragma implementation "thread.h"
15 #endif
16
17 // ----------------------------------------------------------------------------
18 // headers
19 // ----------------------------------------------------------------------------
20
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
23
24 #if defined(__BORLANDC__)
25 #pragma hdrstop
26 #endif
27
28 #ifndef WX_PRECOMP
29 #include "wx/wx.h"
30 #endif
31
32 #if wxUSE_THREADS
33
34 #include <stdio.h>
35
36 #include <windows.h>
37
38 #include "wx/module.h"
39 #include "wx/thread.h"
40
41 // the possible states of the thread ("=>" shows all possible transitions from
42 // this state)
43 enum wxThreadState
44 {
45 STATE_NEW, // didn't start execution yet (=> RUNNING)
46 STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
47 STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
48 STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
49 STATE_EXITED // thread is terminating
50 };
51
52 // ----------------------------------------------------------------------------
53 // static variables
54 // ----------------------------------------------------------------------------
55
56 // if it's FALSE, some secondary thread is holding the GUI lock
57 static bool s_bGuiOwnedByMainThread = TRUE;
58
59 // critical section which controls access to all GUI functions: any secondary
60 // thread (i.e. except the main one) must enter this crit section before doing
61 // any GUI calls
62 static wxCriticalSection *s_critsectGui = NULL;
63
64 // critical section which protects s_nWaitingForGui variable
65 static wxCriticalSection *s_critsectWaitingForGui = NULL;
66
67 // number of threads waiting for GUI in wxMutexGuiEnter()
68 static size_t s_nWaitingForGui = 0;
69
70 // are we waiting for a thread termination?
71 static bool s_waitingForThread = FALSE;
72
73 // ============================================================================
74 // Windows implementation of thread classes
75 // ============================================================================
76
77 // ----------------------------------------------------------------------------
78 // wxMutex implementation
79 // ----------------------------------------------------------------------------
80 class wxMutexInternal
81 {
82 public:
83 Handle p_mutex;
84 };
85
86 wxMutex::wxMutex()
87 {
88 p_internal = new wxMutexInternal;
89 // p_internal->p_mutex = CreateMutex(NULL, FALSE, NULL);
90 if ( !p_internal->p_mutex )
91 {
92 wxLogSysError(_("Can not create mutex."));
93 }
94
95 m_locked = 0;
96 }
97
98 wxMutex::~wxMutex()
99 {
100 if (m_locked > 0)
101 wxLogDebug(wxT("Warning: freeing a locked mutex (%d locks)."), m_locked);
102 // CloseHandle(p_internal->p_mutex);
103 }
104
105 wxMutexError wxMutex::Lock()
106 {
107 /*
108 DWORD ret;
109
110 ret = WaitForSingleObject(p_internal->p_mutex, INFINITE);
111 switch ( ret )
112 {
113 case WAIT_ABANDONED:
114 return wxMUTEX_BUSY;
115
116 case WAIT_OBJECT_0:
117 // ok
118 break;
119
120 case WAIT_FAILED:
121 wxLogSysError(_("Couldn't acquire a mutex lock"));
122 return wxMUTEX_MISC_ERROR;
123
124 case WAIT_TIMEOUT:
125 default:
126 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
127 }
128 */
129 m_locked++;
130 return wxMUTEX_NO_ERROR;
131 }
132
133 wxMutexError wxMutex::TryLock()
134 {
135 /*
136 DWORD ret;
137
138 ret = WaitForSingleObject(p_internal->p_mutex, 0);
139 if (ret == WAIT_TIMEOUT || ret == WAIT_ABANDONED)
140 return wxMUTEX_BUSY;
141
142 m_locked++;
143 */
144 return wxMUTEX_NO_ERROR;
145 }
146
147 wxMutexError wxMutex::Unlock()
148 {
149 if (m_locked > 0)
150 m_locked--;
151 /*
152 BOOL ret = ReleaseMutex(p_internal->p_mutex);
153 if ( ret == 0 )
154 {
155 wxLogSysError(_("Couldn't release a mutex"));
156 return wxMUTEX_MISC_ERROR;
157 }
158 */
159 return wxMUTEX_NO_ERROR;
160 }
161
162 // ----------------------------------------------------------------------------
163 // wxCondition implementation
164 // ----------------------------------------------------------------------------
165
166 class wxConditionInternal
167 {
168 public:
169 Handle event;
170 int waiters;
171 };
172
173 wxCondition::wxCondition()
174 {
175 p_internal = new wxConditionInternal;
176 // p_internal->event = CreateEvent(NULL, FALSE, FALSE, NULL);
177 if ( !p_internal->event )
178 {
179 wxLogSysError(_("Can not create event object."));
180 }
181
182 p_internal->waiters = 0;
183 }
184
185 wxCondition::~wxCondition()
186 {
187 // CloseHandle(p_internal->event);
188 }
189
190 void wxCondition::Wait(wxMutex& mutex)
191 {
192 mutex.Unlock();
193 p_internal->waiters++;
194 // WaitForSingleObject(p_internal->event, INFINITE);
195 p_internal->waiters--;
196 mutex.Lock();
197 }
198
199 bool wxCondition::Wait(wxMutex& mutex,
200 unsigned long sec,
201 unsigned long nsec)
202 {
203 // DWORD ret;
204
205 mutex.Unlock();
206 p_internal->waiters++;
207 // ret = WaitForSingleObject(p_internal->event, (sec*1000)+(nsec/1000000));
208 p_internal->waiters--;
209 mutex.Lock();
210
211 return TRUE; // false for timeout
212 }
213
214 void wxCondition::Signal()
215 {
216 // SetEvent(p_internal->event);
217 }
218
219 void wxCondition::Broadcast()
220 {
221 int i;
222
223 for (i=0;i<p_internal->waiters;i++)
224 {
225 // if ( SetEvent(p_internal->event) == 0 )
226 {
227 wxLogSysError(_("Couldn't change the state of event object."));
228 }
229 }
230 }
231
232 // ----------------------------------------------------------------------------
233 // wxCriticalSection implementation
234 // ----------------------------------------------------------------------------
235
236 class wxCriticalSectionInternal
237 {
238 public:
239 // init the critical section object
240 wxCriticalSectionInternal()
241 { /* ::InitializeCriticalSection(&m_data);*/ }
242
243 // implicit cast to the associated data
244 operator Handle *() { return &m_data; }
245
246 // free the associated ressources
247 ~wxCriticalSectionInternal()
248 { /* ::DeleteCriticalSection(&m_data); */}
249
250 private:
251 Handle m_data;
252 };
253
254 wxCriticalSection::wxCriticalSection()
255 {
256 m_critsect = new wxCriticalSectionInternal;
257 }
258
259 wxCriticalSection::~wxCriticalSection()
260 {
261 delete m_critsect;
262 }
263
264 void wxCriticalSection::Enter()
265 {
266 // ::EnterCriticalSection(*m_critsect);
267 }
268
269 void wxCriticalSection::Leave()
270 {
271 // ::LeaveCriticalSection(*m_critsect);
272 }
273
274 // ----------------------------------------------------------------------------
275 // wxThread implementation
276 // ----------------------------------------------------------------------------
277
278 // wxThreadInternal class
279 // ----------------------
280
281 /*
282 class wxThreadInternal
283 {
284 public:
285 wxThreadInternal()
286 {
287 m_hThread = 0;
288 m_state = STATE_NEW;
289 m_priority = WXTHREAD_DEFAULT_PRIORITY;
290 }
291
292 // create a new (suspended) thread (for the given thread object)
293 bool Create(wxThread *thread);
294
295 // suspend/resume/terminate
296 bool Suspend();
297 bool Resume();
298 void Cancel() { m_state = STATE_CANCELED; }
299
300 // thread state
301 void SetState(wxThreadState state) { m_state = state; }
302 wxThreadState GetState() const { return m_state; }
303
304 // thread priority
305 void SetPriority(unsigned int priority) { m_priority = priority; }
306 unsigned int GetPriority() const { return m_priority; }
307
308 // thread handle and id
309 HANDLE GetHandle() const { return m_hThread; }
310 DWORD GetId() const { return m_tid; }
311
312 // thread function
313 static DWORD WinThreadStart(wxThread *thread);
314
315 private:
316 Handle m_hThread; // handle of the thread
317 wxThreadState m_state; // state, see wxThreadState enum
318 unsigned int m_priority; // thread priority in "wx" units
319 ThreadId m_tid; // thread id
320 };
321
322 DWORD wxThreadInternal::WinThreadStart(wxThread *thread)
323 {
324 // store the thread object in the TLS
325 if ( !::TlsSetValue(s_tlsThisThread, thread) )
326 {
327 wxLogSysError(_("Can not start thread: error writing TLS."));
328
329 return (DWORD)-1;
330 }
331
332 DWORD ret = (DWORD)thread->Entry();
333 thread->p_internal->SetState(STATE_EXITED);
334 thread->OnExit();
335
336 delete thread;
337
338 return ret;
339 }
340
341 bool wxThreadInternal::Create(wxThread *thread)
342 {
343 m_hThread = ::CreateThread
344 (
345 NULL, // default security
346 0, // default stack size
347 (LPTHREAD_START_ROUTINE) // thread entry point
348 wxThreadInternal::WinThreadStart, //
349 (LPVOID)thread, // parameter
350 CREATE_SUSPENDED, // flags
351 &m_tid // [out] thread id
352 );
353
354 if ( m_hThread == NULL )
355 {
356 wxLogSysError(_("Can't create thread"));
357
358 return FALSE;
359 }
360
361 // translate wxWindows priority to the Windows one
362 int win_priority;
363 if (m_priority <= 20)
364 win_priority = THREAD_PRIORITY_LOWEST;
365 else if (m_priority <= 40)
366 win_priority = THREAD_PRIORITY_BELOW_NORMAL;
367 else if (m_priority <= 60)
368 win_priority = THREAD_PRIORITY_NORMAL;
369 else if (m_priority <= 80)
370 win_priority = THREAD_PRIORITY_ABOVE_NORMAL;
371 else if (m_priority <= 100)
372 win_priority = THREAD_PRIORITY_HIGHEST;
373 else
374 {
375 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
376 win_priority = THREAD_PRIORITY_NORMAL;
377 }
378
379 if ( ::SetThreadPriority(m_hThread, win_priority) == 0 )
380 {
381 wxLogSysError(_("Can't set thread priority"));
382 }
383
384 return TRUE;
385 }
386
387 bool wxThreadInternal::Suspend()
388 {
389 DWORD nSuspendCount = ::SuspendThread(m_hThread);
390 if ( nSuspendCount == (DWORD)-1 )
391 {
392 wxLogSysError(_("Can not suspend thread %x"), m_hThread);
393
394 return FALSE;
395 }
396
397 m_state = STATE_PAUSED;
398
399 return TRUE;
400 }
401
402 bool wxThreadInternal::Resume()
403 {
404 DWORD nSuspendCount = ::ResumeThread(m_hThread);
405 if ( nSuspendCount == (DWORD)-1 )
406 {
407 wxLogSysError(_("Can not resume thread %x"), m_hThread);
408
409 return FALSE;
410 }
411
412 m_state = STATE_RUNNING;
413
414 return TRUE;
415 }
416
417 // static functions
418 // ----------------
419
420 wxThread *wxThread::This()
421 {
422 wxThread *thread = (wxThread *)::TlsGetValue(s_tlsThisThread);
423
424 // be careful, 0 may be a valid return value as well
425 if ( !thread && (::GetLastError() != NO_ERROR) )
426 {
427 wxLogSysError(_("Couldn't get the current thread pointer"));
428
429 // return NULL...
430 }
431
432 return thread;
433 }
434
435 bool wxThread::IsMain()
436 {
437 return ::GetCurrentThreadId() == s_idMainThread;
438 }
439
440 #ifdef Yield
441 #undef Yield
442 #endif
443
444 void wxThread::Yield()
445 {
446 // 0 argument to Sleep() is special
447 ::Sleep(0);
448 }
449
450 void wxThread::Sleep(unsigned long milliseconds)
451 {
452 ::Sleep(milliseconds);
453 }
454
455 // create/start thread
456 // -------------------
457
458 wxThreadError wxThread::Create()
459 {
460 if ( !p_internal->Create(this) )
461 return wxTHREAD_NO_RESOURCE;
462
463 return wxTHREAD_NO_ERROR;
464 }
465
466 wxThreadError wxThread::Run()
467 {
468 wxCriticalSectionLocker lock(m_critsect);
469
470 if ( p_internal->GetState() != STATE_NEW )
471 {
472 // actually, it may be almost any state at all, not only STATE_RUNNING
473 return wxTHREAD_RUNNING;
474 }
475
476 return Resume();
477 }
478
479 // suspend/resume thread
480 // ---------------------
481
482 wxThreadError wxThread::Pause()
483 {
484 wxCriticalSectionLocker lock(m_critsect);
485
486 return p_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
487 }
488
489 wxThreadError wxThread::Resume()
490 {
491 wxCriticalSectionLocker lock(m_critsect);
492
493 return p_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
494 }
495
496 // stopping thread
497 // ---------------
498
499 wxThread::ExitCode wxThread::Delete()
500 {
501 ExitCode rc = 0;
502
503 // Delete() is always safe to call, so consider all possible states
504 if ( IsPaused() )
505 Resume();
506
507 if ( IsRunning() )
508 {
509 if ( IsMain() )
510 {
511 // set flag for wxIsWaitingForThread()
512 s_waitingForThread = TRUE;
513
514 wxBeginBusyCursor();
515 }
516
517 HANDLE hThread;
518 {
519 wxCriticalSectionLocker lock(m_critsect);
520
521 p_internal->Cancel();
522 hThread = p_internal->GetHandle();
523 }
524
525 // we can't just wait for the thread to terminate because it might be
526 // calling some GUI functions and so it will never terminate before we
527 // process the Windows messages that result from these functions
528 DWORD result;
529 do
530 {
531 result = ::MsgWaitForMultipleObjects
532 (
533 1, // number of objects to wait for
534 &hThread, // the objects
535 FALSE, // don't wait for all objects
536 INFINITE, // no timeout
537 QS_ALLEVENTS // return as soon as there are any events
538 );
539
540 switch ( result )
541 {
542 case 0xFFFFFFFF:
543 // error
544 wxLogSysError(_("Can not wait for thread termination"));
545 Kill();
546 return (ExitCode)-1;
547
548 case WAIT_OBJECT_0:
549 // thread we're waiting for terminated
550 break;
551
552 case WAIT_OBJECT_0 + 1:
553 // new message arrived, process it
554 if ( !wxTheApp->DoMessage() )
555 {
556 // WM_QUIT received: kill the thread
557 Kill();
558
559 return (ExitCode)-1;
560 }
561
562 if ( IsMain() )
563 {
564 // give the thread we're waiting for chance to exit
565 // from the GUI call it might have been in
566 if ( (s_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
567 {
568 wxMutexGuiLeave();
569 }
570 }
571
572 break;
573
574 default:
575 wxFAIL_MSG(wxT("unexpected result of MsgWaitForMultipleObject"));
576 }
577 } while ( result != WAIT_OBJECT_0 );
578
579 if ( IsMain() )
580 {
581 s_waitingForThread = FALSE;
582
583 wxEndBusyCursor();
584 }
585
586 if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
587 {
588 wxLogLastError("GetExitCodeThread");
589
590 rc = (ExitCode)-1;
591 }
592
593 wxASSERT_MSG( (LPVOID)rc != (LPVOID)STILL_ACTIVE,
594 wxT("thread must be already terminated.") );
595
596 ::CloseHandle(hThread);
597 }
598
599 return rc;
600 }
601
602 wxThreadError wxThread::Kill()
603 {
604 if ( !IsRunning() )
605 return wxTHREAD_NOT_RUNNING;
606
607 if ( !::TerminateThread(p_internal->GetHandle(), (DWORD)-1) )
608 {
609 wxLogSysError(_("Couldn't terminate thread"));
610
611 return wxTHREAD_MISC_ERROR;
612 }
613
614 delete this;
615
616 return wxTHREAD_NO_ERROR;
617 }
618
619 void wxThread::Exit(void *status)
620 {
621 delete this;
622
623 ::ExitThread((DWORD)status);
624
625 wxFAIL_MSG(wxT("Couldn't return from ExitThread()!"));
626 }
627
628 void wxThread::SetPriority(unsigned int prio)
629 {
630 wxCriticalSectionLocker lock(m_critsect);
631
632 p_internal->SetPriority(prio);
633 }
634
635 unsigned int wxThread::GetPriority() const
636 {
637 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
638
639 return p_internal->GetPriority();
640 }
641
642 unsigned long wxThread::GetID() const
643 {
644 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
645
646 return (unsigned long)p_internal->GetId();
647 }
648
649 bool wxThread::IsRunning() const
650 {
651 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
652
653 return p_internal->GetState() == STATE_RUNNING;
654 }
655
656 bool wxThread::IsAlive() const
657 {
658 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
659
660 return (p_internal->GetState() == STATE_RUNNING) ||
661 (p_internal->GetState() == STATE_PAUSED);
662 }
663
664 bool wxThread::IsPaused() const
665 {
666 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
667
668 return (p_internal->GetState() == STATE_PAUSED);
669 }
670
671 bool wxThread::TestDestroy()
672 {
673 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
674
675 return p_internal->GetState() == STATE_CANCELED;
676 }
677
678 wxThread::wxThread()
679 {
680 p_internal = new wxThreadInternal();
681 }
682
683 wxThread::~wxThread()
684 {
685 delete p_internal;
686 }
687
688 // ----------------------------------------------------------------------------
689 // Automatic initialization for thread module
690 // ----------------------------------------------------------------------------
691
692 class wxThreadModule : public wxModule
693 {
694 public:
695 virtual bool OnInit();
696 virtual void OnExit();
697
698 private:
699 DECLARE_DYNAMIC_CLASS(wxThreadModule)
700 };
701
702 IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
703
704 bool wxThreadModule::OnInit()
705 {
706 // allocate TLS index for storing the pointer to the current thread
707 s_tlsThisThread = ::TlsAlloc();
708 if ( s_tlsThisThread == 0xFFFFFFFF )
709 {
710 // in normal circumstances it will only happen if all other
711 // TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other
712 // words, this should never happen
713 wxLogSysError(_("Thread module initialization failed: "
714 "impossible to allocate index in thread "
715 "local storage"));
716
717 return FALSE;
718 }
719
720 // main thread doesn't have associated wxThread object, so store 0 in the
721 // TLS instead
722 if ( !::TlsSetValue(s_tlsThisThread, (LPVOID)0) )
723 {
724 ::TlsFree(s_tlsThisThread);
725 s_tlsThisThread = 0xFFFFFFFF;
726
727 wxLogSysError(_("Thread module initialization failed: "
728 "can not store value in thread local storage"));
729
730 return FALSE;
731 }
732
733 s_critsectWaitingForGui = new wxCriticalSection();
734
735 s_critsectGui = new wxCriticalSection();
736 s_critsectGui->Enter();
737
738 // no error return for GetCurrentThreadId()
739 s_idMainThread = ::GetCurrentThreadId();
740
741 return TRUE;
742 }
743
744 void wxThreadModule::OnExit()
745 {
746 if ( !::TlsFree(s_tlsThisThread) )
747 {
748 wxLogLastError("TlsFree failed.");
749 }
750
751 if ( s_critsectGui )
752 {
753 s_critsectGui->Leave();
754 delete s_critsectGui;
755 s_critsectGui = NULL;
756 }
757
758 wxDELETE(s_critsectWaitingForGui);
759 }
760
761 // ----------------------------------------------------------------------------
762 // under Windows, these functions are implemented usign a critical section and
763 // not a mutex, so the names are a bit confusing
764 // ----------------------------------------------------------------------------
765
766 void WXDLLEXPORT wxMutexGuiEnter()
767 {
768 // this would dead lock everything...
769 wxASSERT_MSG( !wxThread::IsMain(),
770 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
771
772 // the order in which we enter the critical sections here is crucial!!
773
774 // set the flag telling to the main thread that we want to do some GUI
775 {
776 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
777
778 s_nWaitingForGui++;
779 }
780
781 wxWakeUpMainThread();
782
783 // now we may block here because the main thread will soon let us in
784 // (during the next iteration of OnIdle())
785 s_critsectGui->Enter();
786 }
787
788 void WXDLLEXPORT wxMutexGuiLeave()
789 {
790 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
791
792 if ( wxThread::IsMain() )
793 {
794 s_bGuiOwnedByMainThread = FALSE;
795 }
796 else
797 {
798 // decrement the number of waiters now
799 wxASSERT_MSG( s_nWaitingForGui > 0,
800 wxT("calling wxMutexGuiLeave() without entering it first?") );
801
802 s_nWaitingForGui--;
803
804 wxWakeUpMainThread();
805 }
806
807 s_critsectGui->Leave();
808 }
809
810 void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
811 {
812 wxASSERT_MSG( wxThread::IsMain(),
813 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
814
815 wxCriticalSectionLocker enter(*s_critsectWaitingForGui);
816
817 if ( s_nWaitingForGui == 0 )
818 {
819 // no threads are waiting for GUI - so we may acquire the lock without
820 // any danger (but only if we don't already have it)
821 if ( !wxGuiOwnedByMainThread() )
822 {
823 s_critsectGui->Enter();
824
825 s_bGuiOwnedByMainThread = TRUE;
826 }
827 //else: already have it, nothing to do
828 }
829 else
830 {
831 // some threads are waiting, release the GUI lock if we have it
832 if ( wxGuiOwnedByMainThread() )
833 {
834 wxMutexGuiLeave();
835 }
836 //else: some other worker thread is doing GUI
837 }
838 }
839
840 bool WXDLLEXPORT wxGuiOwnedByMainThread()
841 {
842 return s_bGuiOwnedByMainThread;
843 }
844
845 // wake up the main thread if it's in ::GetMessage()
846 void WXDLLEXPORT wxWakeUpMainThread()
847 {
848 // sending any message would do - hopefully WM_NULL is harmless enough
849 if ( !::PostThreadMessage(s_idMainThread, WM_NULL, 0, 0) )
850 {
851 // should never happen
852 wxLogLastError("PostThreadMessage(WM_NULL)");
853 }
854 }
855
856 bool WXDLLEXPORT wxIsWaitingForThread()
857 {
858 return s_waitingForThread;
859 }
860 */
861
862 #endif // wxUSE_THREADS