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