]> git.saurik.com Git - wxWidgets.git/blame - src/os2/thread.cpp
Committing in .
[wxWidgets.git] / src / os2 / thread.cpp
CommitLineData
0e320a79
DW
1/////////////////////////////////////////////////////////////////////////////
2// Name: thread.cpp
3// Purpose: wxThread Implementation. For Unix ports, see e.g. src/gtk
4// Author: Original from Wolfram Gloger/Guilhem Lavaux
d90895ac 5// Modified by: David Webster
0e320a79
DW
6// Created: 04/22/98
7// RCS-ID: $Id$
8// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998)
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
d90895ac
DW
12// ----------------------------------------------------------------------------
13// headers
14// ----------------------------------------------------------------------------
0e320a79 15
d90895ac
DW
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
0e320a79
DW
18
19#if wxUSE_THREADS
20
d90895ac
DW
21#include <stdio.h>
22
d90895ac
DW
23#include "wx/module.h"
24#include "wx/thread.h"
25
c5fb56c0
DW
26#define INCL_DOSSEMAPHORES
27#define INCL_DOSPROCESS
28#define INCL_ERRORS
29#include <os2.h>
30#include <bseerr.h>
31
d90895ac
DW
32// the possible states of the thread ("=>" shows all possible transitions from
33// this state)
34enum wxThreadState
35{
36 STATE_NEW, // didn't start execution yet (=> RUNNING)
37 STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
38 STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
39 STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
40 STATE_EXITED // thread is terminating
0e320a79
DW
41};
42
d90895ac
DW
43// ----------------------------------------------------------------------------
44// static variables
45// ----------------------------------------------------------------------------
0e320a79 46
d90895ac
DW
47// id of the main thread - the one which can call GUI functions without first
48// calling wxMutexGuiEnter()
c5fb56c0
DW
49static ULONG s_ulIdMainThread = 0;
50wxMutex* p_wxMainMutex;
51
52// OS2 substitute for Tls pointer the current parent thread object
53wxThread* m_pThread; // pointer to the wxWindows thread object
d90895ac
DW
54
55// if it's FALSE, some secondary thread is holding the GUI lock
56static bool s_bGuiOwnedByMainThread = TRUE;
0e320a79 57
d90895ac
DW
58// critical section which controls access to all GUI functions: any secondary
59// thread (i.e. except the main one) must enter this crit section before doing
60// any GUI calls
c5fb56c0 61static wxCriticalSection *s_pCritsectGui = NULL;
d90895ac
DW
62
63// critical section which protects s_nWaitingForGui variable
c5fb56c0 64static wxCriticalSection *s_pCritsectWaitingForGui = NULL;
d90895ac
DW
65
66// number of threads waiting for GUI in wxMutexGuiEnter()
67static size_t s_nWaitingForGui = 0;
68
69// are we waiting for a thread termination?
c5fb56c0 70static bool s_bWaitingForThread = FALSE;
d90895ac
DW
71
72// ============================================================================
c5fb56c0 73// OS/2 implementation of thread classes
d90895ac
DW
74// ============================================================================
75
76// ----------------------------------------------------------------------------
77// wxMutex implementation
78// ----------------------------------------------------------------------------
79class wxMutexInternal
80{
0e320a79 81public:
c5fb56c0 82 HMTX m_vMutex;
0e320a79
DW
83};
84
85wxMutex::wxMutex()
86{
c5fb56c0
DW
87 APIRET ulrc;
88
0e320a79 89 p_internal = new wxMutexInternal;
c5fb56c0
DW
90 ulrc = ::DosCreateMutexSem(NULL, &p_internal->m_vMutex, 0L, FALSE);
91 if (ulrc != 0)
d90895ac
DW
92 {
93 wxLogSysError(_("Can not create mutex."));
94 }
0e320a79
DW
95 m_locked = 0;
96}
97
98wxMutex::~wxMutex()
99{
100 if (m_locked > 0)
d90895ac 101 wxLogDebug(wxT("Warning: freeing a locked mutex (%d locks)."), m_locked);
c5fb56c0 102 ::DosCloseMutexSem(p_internal->m_vMutex);
5d4b632b 103 p_internal->m_vMutex = NULL;
0e320a79
DW
104}
105
106wxMutexError wxMutex::Lock()
107{
c5fb56c0
DW
108 APIRET ulrc;
109
110 ulrc = ::DosRequestMutexSem(p_internal->m_vMutex, SEM_INDEFINITE_WAIT);
d90895ac 111
c5fb56c0 112 switch (ulrc)
d90895ac 113 {
c5fb56c0 114 case ERROR_TOO_MANY_SEM_REQUESTS:
d90895ac
DW
115 return wxMUTEX_BUSY;
116
c5fb56c0 117 case NO_ERROR:
d90895ac
DW
118 // ok
119 break;
120
c5fb56c0
DW
121 case ERROR_INVALID_HANDLE:
122 case ERROR_INTERRUPT:
123 case ERROR_SEM_OWNER_DIED:
d90895ac
DW
124 wxLogSysError(_("Couldn't acquire a mutex lock"));
125 return wxMUTEX_MISC_ERROR;
126
c5fb56c0 127 case ERROR_TIMEOUT:
d90895ac
DW
128 default:
129 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
130 }
0e320a79
DW
131 m_locked++;
132 return wxMUTEX_NO_ERROR;
133}
134
135wxMutexError wxMutex::TryLock()
136{
c5fb56c0 137 ULONG ulrc;
d90895ac 138
c5fb56c0
DW
139 ulrc = ::DosRequestMutexSem(p_internal->m_vMutex, SEM_IMMEDIATE_RETURN /*0L*/);
140 if (ulrc == ERROR_TIMEOUT || ulrc == ERROR_TOO_MANY_SEM_REQUESTS)
d90895ac
DW
141 return wxMUTEX_BUSY;
142
0e320a79
DW
143 m_locked++;
144 return wxMUTEX_NO_ERROR;
145}
146
147wxMutexError wxMutex::Unlock()
148{
c5fb56c0
DW
149 APIRET ulrc;
150
0e320a79
DW
151 if (m_locked > 0)
152 m_locked--;
153
c5fb56c0
DW
154 ulrc = ::DosReleaseMutexSem(p_internal->m_vMutex);
155 if (ulrc != 0)
d90895ac
DW
156 {
157 wxLogSysError(_("Couldn't release a mutex"));
158 return wxMUTEX_MISC_ERROR;
159 }
0e320a79
DW
160 return wxMUTEX_NO_ERROR;
161}
162
d90895ac
DW
163// ----------------------------------------------------------------------------
164// wxCondition implementation
165// ----------------------------------------------------------------------------
166
167class wxConditionInternal
168{
0e320a79 169public:
c5fb56c0
DW
170 HEV m_vEvent;
171 int m_nWaiters;
0e320a79
DW
172};
173
174wxCondition::wxCondition()
175{
c5fb56c0
DW
176 APIRET ulrc;
177 ULONG ulCount;
178
0e320a79 179 p_internal = new wxConditionInternal;
c5fb56c0
DW
180 ulrc = ::DosCreateEventSem(NULL, &p_internal->m_vEvent, 0L, FALSE);
181 if (ulrc != 0)
d90895ac
DW
182 {
183 wxLogSysError(_("Can not create event object."));
184 }
c5fb56c0
DW
185 p_internal->m_nWaiters = 0;
186 // ?? just for good measure?
187 ::DosResetEventSem(p_internal->m_vEvent, &ulCount);
0e320a79
DW
188}
189
190wxCondition::~wxCondition()
191{
c5fb56c0
DW
192 ::DosCloseEventSem(p_internal->m_vEvent);
193 delete p_internal;
194 p_internal = NULL;
0e320a79
DW
195}
196
c5fb56c0
DW
197void wxCondition::Wait(
198 wxMutex& rMutex
199)
0e320a79 200{
c5fb56c0
DW
201 rMutex.Unlock();
202 p_internal->m_nWaiters++;
203 ::DosWaitEventSem(p_internal->m_vEvent, SEM_INDEFINITE_WAIT);
204 p_internal->m_nWaiters--;
205 rMutex.Lock();
0e320a79
DW
206}
207
c5fb56c0
DW
208bool wxCondition::Wait(
209 wxMutex& rMutex
210, unsigned long ulSec
211, unsigned long ulMillisec)
0e320a79 212{
c5fb56c0 213 APIRET ulrc;
d90895ac 214
c5fb56c0
DW
215 rMutex.Unlock();
216 p_internal->m_nWaiters++;
217 ulrc = ::DosWaitEventSem(p_internal->m_vEvent, ULONG((ulSec * 1000L) + ulMillisec));
218 p_internal->m_nWaiters--;
219 rMutex.Lock();
0e320a79 220
c5fb56c0 221 return (ulrc != ERROR_TIMEOUT);
0e320a79
DW
222}
223
224void wxCondition::Signal()
225{
c5fb56c0 226 ::DosPostEventSem(p_internal->m_vEvent);
0e320a79
DW
227}
228
229void wxCondition::Broadcast()
230{
c5fb56c0 231 int i;
d90895ac 232
c5fb56c0 233 for (i = 0; i < p_internal->m_nWaiters; i++)
d90895ac 234 {
c5fb56c0 235 if (::DosPostEventSem(p_internal->m_vEvent) != 0)
d90895ac
DW
236 {
237 wxLogSysError(_("Couldn't change the state of event object."));
238 }
239 }
0e320a79
DW
240}
241
d90895ac
DW
242// ----------------------------------------------------------------------------
243// wxCriticalSection implementation
244// ----------------------------------------------------------------------------
d90895ac 245
5d4b632b
DW
246class wxCriticalSectionInternal
247{
248public:
249 // init the critical section object
250 wxCriticalSectionInternal()
251 { }
252
253 // free the associated ressources
254 ~wxCriticalSectionInternal()
255 { }
256
257private:
258};
259
260// ----------------------------------------------------------------------------
261// wxCriticalSection implementation
262// ----------------------------------------------------------------------------
263
264wxCriticalSection::wxCriticalSection()
265{
266 m_critsect = new wxCriticalSectionInternal;
267}
268
269wxCriticalSection::~wxCriticalSection()
270{
271 delete m_critsect;
272}
273
d90895ac
DW
274void wxCriticalSection::Enter()
275{
c5fb56c0 276 ::DosEnterCritSec();
d90895ac
DW
277}
278
279void wxCriticalSection::Leave()
280{
c5fb56c0 281 ::DosExitCritSec();
d90895ac
DW
282}
283
284// ----------------------------------------------------------------------------
285// wxThread implementation
286// ----------------------------------------------------------------------------
287
288// wxThreadInternal class
289// ----------------------
290
291class wxThreadInternal
292{
293public:
c5fb56c0 294 inline wxThreadInternal()
d90895ac
DW
295 {
296 m_hThread = 0;
c5fb56c0
DW
297 m_eState = STATE_NEW;
298 m_nPriority = 0;
d90895ac
DW
299 }
300
301 // create a new (suspended) thread (for the given thread object)
c5fb56c0 302 bool Create(wxThread* pThread);
d90895ac
DW
303
304 // suspend/resume/terminate
305 bool Suspend();
306 bool Resume();
c5fb56c0 307 inline void Cancel() { m_eState = STATE_CANCELED; }
d90895ac
DW
308
309 // thread state
c5fb56c0
DW
310 inline void SetState(wxThreadState eState) { m_eState = eState; }
311 inline wxThreadState GetState() const { return m_eState; }
d90895ac
DW
312
313 // thread priority
c5fb56c0
DW
314 inline void SetPriority(unsigned int nPriority) { m_nPriority = nPriority; }
315 inline unsigned int GetPriority() const { return m_nPriority; }
d90895ac
DW
316
317 // thread handle and id
c5fb56c0
DW
318 inline TID GetHandle() const { return m_hThread; }
319 TID GetId() const { return m_hThread; }
d90895ac
DW
320
321 // thread function
322 static DWORD OS2ThreadStart(wxThread *thread);
323
324private:
c5fb56c0
DW
325 // Threads in OS/2 have only an ID, so m_hThread is both it's handle and ID
326 // PM also has no real Tls mechanism to index pointers by so we'll just
327 // keep track of the wxWindows parent object here.
328 TID m_hThread; // handle and ID of the thread
329 wxThreadState m_eState; // state, see wxThreadState enum
330 unsigned int m_nPriority; // thread priority in "wx" units
d90895ac
DW
331};
332
c5fb56c0
DW
333ULONG wxThreadInternal::OS2ThreadStart(
334 wxThread* pThread
335)
d90895ac 336{
c5fb56c0 337 m_pThread = pThread;
d90895ac 338
c5fb56c0 339 DWORD dwRet = (DWORD)pThread->Entry();
d90895ac 340
c5fb56c0
DW
341 pThread->p_internal->SetState(STATE_EXITED);
342 pThread->OnExit();
d90895ac 343
c5fb56c0
DW
344 delete pThread;
345 m_pThread = NULL;
346 return dwRet;
d90895ac
DW
347}
348
c5fb56c0
DW
349bool wxThreadInternal::Create(
350 wxThread* pThread
351)
d90895ac 352{
c5fb56c0 353 APIRET ulrc;
d90895ac 354
c5fb56c0
DW
355 ulrc = ::DosCreateThread( &m_hThread
356 ,(PFNTHREAD)wxThreadInternal::OS2ThreadStart
357 ,(ULONG)pThread
358 ,CREATE_SUSPENDED | STACK_SPARSE
359 ,8192L
360 );
361 if(ulrc != 0)
d90895ac
DW
362 {
363 wxLogSysError(_("Can't create thread"));
364
365 return FALSE;
366 }
367
c5fb56c0
DW
368 // translate wxWindows priority to the PM one
369 ULONG ulOS2_Priority;
370
371 if (m_nPriority <= 20)
372 ulOS2_Priority = PRTYC_NOCHANGE;
373 else if (m_nPriority <= 40)
374 ulOS2_Priority = PRTYC_IDLETIME;
375 else if (m_nPriority <= 60)
376 ulOS2_Priority = PRTYC_REGULAR;
377 else if (m_nPriority <= 80)
378 ulOS2_Priority = PRTYC_TIMECRITICAL;
379 else if (m_nPriority <= 100)
380 ulOS2_Priority = PRTYC_FOREGROUNDSERVER;
d90895ac
DW
381 else
382 {
383 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
c5fb56c0 384 ulOS2_Priority = PRTYC_REGULAR;
d90895ac 385 }
c5fb56c0
DW
386 ulrc = ::DosSetPriority( PRTYS_THREAD
387 ,ulOS2_Priority
388 ,0
389 ,(ULONG)m_hThread
390 );
391 if (ulrc != 0)
d90895ac
DW
392 {
393 wxLogSysError(_("Can't set thread priority"));
394 }
c5fb56c0 395 return TRUE;
d90895ac
DW
396}
397
398bool wxThreadInternal::Suspend()
399{
c5fb56c0 400 ULONG ulrc = ::DosSuspendThread(m_hThread);
d90895ac 401
c5fb56c0
DW
402 if (ulrc != 0)
403 {
404 wxLogSysError(_("Can not suspend thread %lu"), m_hThread);
d90895ac
DW
405 return FALSE;
406 }
c5fb56c0
DW
407 m_eState = STATE_PAUSED;
408 return TRUE;
d90895ac
DW
409}
410
411bool wxThreadInternal::Resume()
412{
c5fb56c0 413 ULONG ulrc = ::DosResumeThread(m_hThread);
d90895ac 414
c5fb56c0
DW
415 if (ulrc != 0)
416 {
417 wxLogSysError(_("Can not suspend thread %lu"), m_hThread);
d90895ac
DW
418 return FALSE;
419 }
c5fb56c0
DW
420 m_eState = STATE_PAUSED;
421 return TRUE;
d90895ac
DW
422}
423
424// static functions
425// ----------------
426
427wxThread *wxThread::This()
428{
c5fb56c0
DW
429 wxThread* pThread = m_pThread;
430 return pThread;
d90895ac
DW
431}
432
433bool wxThread::IsMain()
434{
c5fb56c0
DW
435 PTIB ptib;
436 PPIB ppib;
437
438 ::DosGetInfoBlocks(&ptib, &ppib);
439
440 if (ptib->tib_ptib2->tib2_ultid == s_ulIdMainThread)
441 return TRUE;
d90895ac
DW
442 return FALSE;
443}
444
445#ifdef Yield
446 #undef Yield
447#endif
448
449void wxThread::Yield()
450{
d90895ac
DW
451 ::DosSleep(0);
452}
453
c5fb56c0
DW
454void wxThread::Sleep(
455 unsigned long ulMilliseconds
456)
d90895ac 457{
c5fb56c0 458 ::DosSleep(ulMilliseconds);
d90895ac
DW
459}
460
461// create/start thread
462// -------------------
463
0e320a79
DW
464wxThreadError wxThread::Create()
465{
d90895ac
DW
466 if ( !p_internal->Create(this) )
467 return wxTHREAD_NO_RESOURCE;
468
0e320a79
DW
469 return wxTHREAD_NO_ERROR;
470}
471
d90895ac 472wxThreadError wxThread::Run()
0e320a79 473{
c5fb56c0 474 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac
DW
475
476 if ( p_internal->GetState() != STATE_NEW )
477 {
478 // actually, it may be almost any state at all, not only STATE_RUNNING
479 return wxTHREAD_RUNNING;
480 }
d90895ac 481 return Resume();
0e320a79
DW
482}
483
d90895ac
DW
484// suspend/resume thread
485// ---------------------
486
0e320a79
DW
487wxThreadError wxThread::Pause()
488{
c5fb56c0 489 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac
DW
490
491 return p_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
0e320a79
DW
492}
493
494wxThreadError wxThread::Resume()
495{
c5fb56c0 496 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
0e320a79 497
d90895ac 498 return p_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
0e320a79
DW
499}
500
d90895ac
DW
501// stopping thread
502// ---------------
503
504wxThread::ExitCode wxThread::Delete()
0e320a79 505{
c5fb56c0
DW
506 ExitCode rc = 0;
507 ULONG ulrc;
d90895ac
DW
508
509 // Delete() is always safe to call, so consider all possible states
c5fb56c0 510 if (IsPaused())
d90895ac
DW
511 Resume();
512
c5fb56c0 513 if (IsRunning())
d90895ac 514 {
c5fb56c0 515 if (IsMain())
d90895ac
DW
516 {
517 // set flag for wxIsWaitingForThread()
c5fb56c0 518 s_bWaitingForThread = TRUE;
d90895ac
DW
519 wxBeginBusyCursor();
520 }
521
c5fb56c0
DW
522 TID hThread;
523
d90895ac 524 {
c5fb56c0 525 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac
DW
526
527 p_internal->Cancel();
528 hThread = p_internal->GetHandle();
529 }
530
531 // we can't just wait for the thread to terminate because it might be
532 // calling some GUI functions and so it will never terminate before we
533 // process the Windows messages that result from these functions
c5fb56c0 534
d90895ac
DW
535 do
536 {
c5fb56c0
DW
537 ulrc = ::DosWaitThread( &hThread
538 ,DCWW_NOWAIT
539 );
540 switch (ulrc)
d90895ac 541 {
c5fb56c0
DW
542 case ERROR_INTERRUPT:
543 case ERROR_INVALID_THREADID:
d90895ac
DW
544 // error
545 wxLogSysError(_("Can not wait for thread termination"));
546 Kill();
547 return (ExitCode)-1;
548
c5fb56c0 549 case 0:
d90895ac
DW
550 // thread we're waiting for terminated
551 break;
552
c5fb56c0 553 case ERROR_THREAD_NOT_TERMINATED:
d90895ac 554 // new message arrived, process it
c5fb56c0 555 if (!wxTheApp->DoMessage())
d90895ac
DW
556 {
557 // WM_QUIT received: kill the thread
558 Kill();
d90895ac
DW
559 return (ExitCode)-1;
560 }
c5fb56c0 561 if (IsMain())
d90895ac
DW
562 {
563 // give the thread we're waiting for chance to exit
564 // from the GUI call it might have been in
c5fb56c0 565 if ((s_nWaitingForGui > 0) && wxGuiOwnedByMainThread())
d90895ac
DW
566 {
567 wxMutexGuiLeave();
568 }
569 }
d90895ac
DW
570 break;
571
572 default:
c5fb56c0 573 wxFAIL_MSG(wxT("unexpected result of DosWatiThread"));
d90895ac 574 }
c5fb56c0 575 } while (ulrc != 0);
d90895ac 576
c5fb56c0 577 if (IsMain())
d90895ac 578 {
c5fb56c0
DW
579 s_bWaitingForThread = FALSE;
580 wxEndBusyCursor();
d90895ac
DW
581 }
582
c5fb56c0 583 ::DosExit(EXIT_THREAD, ulrc);
d90895ac 584 }
c5fb56c0 585 rc = (ExitCode)ulrc;
d90895ac 586 return rc;
0e320a79
DW
587}
588
d90895ac 589wxThreadError wxThread::Kill()
0e320a79 590{
c5fb56c0 591 if (!IsRunning())
d90895ac
DW
592 return wxTHREAD_NOT_RUNNING;
593
c5fb56c0 594 ::DosKillThread(p_internal->GetHandle());
d90895ac 595 delete this;
d90895ac 596 return wxTHREAD_NO_ERROR;
0e320a79
DW
597}
598
c5fb56c0
DW
599void wxThread::Exit(
600 void* pStatus
601)
0e320a79 602{
d90895ac 603 delete this;
c5fb56c0
DW
604 ::DosExit(EXIT_THREAD, ULONG(pStatus));
605 wxFAIL_MSG(wxT("Couldn't return from DosExit()!"));
0e320a79
DW
606}
607
c5fb56c0
DW
608void wxThread::SetPriority(
609 unsigned int nPrio
610)
0e320a79 611{
c5fb56c0 612 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 613
c5fb56c0 614 p_internal->SetPriority(nPrio);
0e320a79
DW
615}
616
d90895ac 617unsigned int wxThread::GetPriority() const
0e320a79 618{
c5fb56c0 619 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac
DW
620
621 return p_internal->GetPriority();
0e320a79
DW
622}
623
624unsigned long wxThread::GetID() const
625{
c5fb56c0 626 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac
DW
627
628 return (unsigned long)p_internal->GetId();
0e320a79
DW
629}
630
d90895ac 631bool wxThread::IsRunning() const
0e320a79 632{
c5fb56c0 633 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac
DW
634
635 return p_internal->GetState() == STATE_RUNNING;
0e320a79 636}
0e320a79
DW
637
638bool wxThread::IsAlive() const
639{
c5fb56c0 640 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac
DW
641
642 return (p_internal->GetState() == STATE_RUNNING) ||
643 (p_internal->GetState() == STATE_PAUSED);
0e320a79
DW
644}
645
d90895ac 646bool wxThread::IsPaused() const
0e320a79 647{
c5fb56c0 648 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac
DW
649
650 return (p_internal->GetState() == STATE_PAUSED);
0e320a79
DW
651}
652
d90895ac 653bool wxThread::TestDestroy()
0e320a79 654{
c5fb56c0 655 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac
DW
656
657 return p_internal->GetState() == STATE_CANCELED;
0e320a79
DW
658}
659
660wxThread::wxThread()
661{
662 p_internal = new wxThreadInternal();
0e320a79
DW
663}
664
665wxThread::~wxThread()
666{
0e320a79
DW
667 delete p_internal;
668}
669
d90895ac
DW
670// ----------------------------------------------------------------------------
671// Automatic initialization for thread module
672// ----------------------------------------------------------------------------
0e320a79 673
d90895ac
DW
674class wxThreadModule : public wxModule
675{
0e320a79 676public:
d90895ac
DW
677 virtual bool OnInit();
678 virtual void OnExit();
0e320a79 679
d90895ac
DW
680private:
681 DECLARE_DYNAMIC_CLASS(wxThreadModule)
0e320a79
DW
682};
683
684IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
685
d90895ac
DW
686bool wxThreadModule::OnInit()
687{
c5fb56c0 688 s_pCritsectWaitingForGui = new wxCriticalSection();
d90895ac 689
c5fb56c0
DW
690 s_pCritsectGui = new wxCriticalSection();
691 s_pCritsectGui->Enter();
d90895ac 692
c5fb56c0
DW
693 PTIB ptib;
694 PPIB ppib;
d90895ac 695
c5fb56c0 696 ::DosGetInfoBlocks(&ptib, &ppib);
d90895ac 697
c5fb56c0 698 s_ulIdMainThread = ptib->tib_ptib2->tib2_ultid;
d90895ac
DW
699 return TRUE;
700}
701
702void wxThreadModule::OnExit()
703{
c5fb56c0 704 if (s_pCritsectGui)
d90895ac 705 {
c5fb56c0
DW
706 s_pCritsectGui->Leave();
707 delete s_pCritsectGui;
708 s_pCritsectGui = NULL;
d90895ac
DW
709 }
710
c5fb56c0 711 wxDELETE(s_pCritsectWaitingForGui);
d90895ac
DW
712}
713
714// ----------------------------------------------------------------------------
c5fb56c0 715// Helper functions
d90895ac
DW
716// ----------------------------------------------------------------------------
717
c5fb56c0
DW
718// Does nothing under OS/2 [for now]
719void WXDLLEXPORT wxWakeUpMainThread()
d90895ac 720{
d90895ac
DW
721}
722
723void WXDLLEXPORT wxMutexGuiLeave()
724{
c5fb56c0 725 wxCriticalSectionLocker enter(*s_pCritsectWaitingForGui);
d90895ac
DW
726
727 if ( wxThread::IsMain() )
728 {
729 s_bGuiOwnedByMainThread = FALSE;
730 }
731 else
732 {
733 // decrement the number of waiters now
734 wxASSERT_MSG( s_nWaitingForGui > 0,
735 wxT("calling wxMutexGuiLeave() without entering it first?") );
736
737 s_nWaitingForGui--;
738
739 wxWakeUpMainThread();
740 }
741
c5fb56c0 742 s_pCritsectGui->Leave();
d90895ac
DW
743}
744
745void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
746{
747 wxASSERT_MSG( wxThread::IsMain(),
748 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
749
c5fb56c0 750 wxCriticalSectionLocker enter(*s_pCritsectWaitingForGui);
d90895ac
DW
751
752 if ( s_nWaitingForGui == 0 )
753 {
754 // no threads are waiting for GUI - so we may acquire the lock without
755 // any danger (but only if we don't already have it)
c5fb56c0 756 if (!wxGuiOwnedByMainThread())
d90895ac 757 {
c5fb56c0 758 s_pCritsectGui->Enter();
d90895ac
DW
759
760 s_bGuiOwnedByMainThread = TRUE;
761 }
762 //else: already have it, nothing to do
763 }
764 else
765 {
766 // some threads are waiting, release the GUI lock if we have it
c5fb56c0 767 if (wxGuiOwnedByMainThread())
d90895ac
DW
768 {
769 wxMutexGuiLeave();
770 }
771 //else: some other worker thread is doing GUI
772 }
773}
774
775bool WXDLLEXPORT wxGuiOwnedByMainThread()
776{
777 return s_bGuiOwnedByMainThread;
778}
779
0e320a79
DW
780#endif
781 // wxUSE_THREADS