]> git.saurik.com Git - wxWidgets.git/blame - src/os2/thread.cpp
added functions to read/write several elements at once (patch 754986)
[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
2b5f62a0
VZ
12#ifdef __GNUG__
13 #pragma implementation "thread.h"
14#endif
15
d90895ac
DW
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
0e320a79 19
d90895ac
DW
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
0e320a79
DW
22
23#if wxUSE_THREADS
24
d90895ac
DW
25#include <stdio.h>
26
d90895ac 27#include "wx/module.h"
19193a2c
KB
28#include "wx/intl.h"
29#include "wx/utils.h"
30#include "wx/log.h"
d90895ac
DW
31#include "wx/thread.h"
32
c5fb56c0
DW
33#define INCL_DOSSEMAPHORES
34#define INCL_DOSPROCESS
35#define INCL_ERRORS
36#include <os2.h>
2b5f62a0 37#ifndef __EMX__
c5fb56c0 38#include <bseerr.h>
2b5f62a0 39#endif
d90895ac
DW
40// the possible states of the thread ("=>" shows all possible transitions from
41// this state)
42enum wxThreadState
43{
44 STATE_NEW, // didn't start execution yet (=> RUNNING)
45 STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
46 STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
47 STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
48 STATE_EXITED // thread is terminating
0e320a79
DW
49};
50
d90895ac
DW
51// ----------------------------------------------------------------------------
52// static variables
53// ----------------------------------------------------------------------------
0e320a79 54
d90895ac
DW
55// id of the main thread - the one which can call GUI functions without first
56// calling wxMutexGuiEnter()
c5fb56c0
DW
57static ULONG s_ulIdMainThread = 0;
58wxMutex* p_wxMainMutex;
59
60// OS2 substitute for Tls pointer the current parent thread object
61wxThread* m_pThread; // pointer to the wxWindows thread object
d90895ac
DW
62
63// if it's FALSE, some secondary thread is holding the GUI lock
43543d98 64static bool gs_bGuiOwnedByMainThread = TRUE;
0e320a79 65
d90895ac
DW
66// critical section which controls access to all GUI functions: any secondary
67// thread (i.e. except the main one) must enter this crit section before doing
68// any GUI calls
43543d98 69static wxCriticalSection *gs_pCritsectGui = NULL;
d90895ac
DW
70
71// critical section which protects s_nWaitingForGui variable
43543d98 72static wxCriticalSection *gs_pCritsectWaitingForGui = NULL;
d90895ac
DW
73
74// number of threads waiting for GUI in wxMutexGuiEnter()
43543d98 75static size_t gs_nWaitingForGui = 0;
d90895ac
DW
76
77// are we waiting for a thread termination?
43543d98 78static bool gs_bWaitingForThread = FALSE;
d90895ac
DW
79
80// ============================================================================
c5fb56c0 81// OS/2 implementation of thread classes
d90895ac
DW
82// ============================================================================
83
84// ----------------------------------------------------------------------------
85// wxMutex implementation
86// ----------------------------------------------------------------------------
87class wxMutexInternal
88{
0e320a79 89public:
c5fb56c0 90 HMTX m_vMutex;
0e320a79
DW
91};
92
47df2b8c
DW
93wxMutex::wxMutex(
94 wxMutexType eMutexType
95)
0e320a79 96{
c5fb56c0
DW
97 APIRET ulrc;
98
d01cc696
DW
99 m_internal = new wxMutexInternal;
100 ulrc = ::DosCreateMutexSem(NULL, &m_internal->m_vMutex, 0L, FALSE);
c5fb56c0 101 if (ulrc != 0)
d90895ac
DW
102 {
103 wxLogSysError(_("Can not create mutex."));
104 }
0e320a79
DW
105}
106
107wxMutex::~wxMutex()
108{
d01cc696
DW
109 ::DosCloseMutexSem(m_internal->m_vMutex);
110 m_internal->m_vMutex = NULL;
0e320a79
DW
111}
112
113wxMutexError wxMutex::Lock()
114{
c5fb56c0
DW
115 APIRET ulrc;
116
d01cc696 117 ulrc = ::DosRequestMutexSem(m_internal->m_vMutex, SEM_INDEFINITE_WAIT);
d90895ac 118
c5fb56c0 119 switch (ulrc)
d90895ac 120 {
c5fb56c0 121 case ERROR_TOO_MANY_SEM_REQUESTS:
d90895ac
DW
122 return wxMUTEX_BUSY;
123
c5fb56c0 124 case NO_ERROR:
d90895ac
DW
125 // ok
126 break;
127
c5fb56c0
DW
128 case ERROR_INVALID_HANDLE:
129 case ERROR_INTERRUPT:
130 case ERROR_SEM_OWNER_DIED:
d90895ac
DW
131 wxLogSysError(_("Couldn't acquire a mutex lock"));
132 return wxMUTEX_MISC_ERROR;
133
c5fb56c0 134 case ERROR_TIMEOUT:
d90895ac
DW
135 default:
136 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
137 }
0e320a79
DW
138 return wxMUTEX_NO_ERROR;
139}
140
141wxMutexError wxMutex::TryLock()
142{
c5fb56c0 143 ULONG ulrc;
d90895ac 144
d01cc696 145 ulrc = ::DosRequestMutexSem(m_internal->m_vMutex, SEM_IMMEDIATE_RETURN /*0L*/);
c5fb56c0 146 if (ulrc == ERROR_TIMEOUT || ulrc == ERROR_TOO_MANY_SEM_REQUESTS)
d90895ac
DW
147 return wxMUTEX_BUSY;
148
0e320a79
DW
149 return wxMUTEX_NO_ERROR;
150}
151
152wxMutexError wxMutex::Unlock()
153{
c5fb56c0
DW
154 APIRET ulrc;
155
d01cc696 156 ulrc = ::DosReleaseMutexSem(m_internal->m_vMutex);
c5fb56c0 157 if (ulrc != 0)
d90895ac
DW
158 {
159 wxLogSysError(_("Couldn't release a mutex"));
160 return wxMUTEX_MISC_ERROR;
161 }
0e320a79
DW
162 return wxMUTEX_NO_ERROR;
163}
164
d90895ac
DW
165// ----------------------------------------------------------------------------
166// wxCondition implementation
167// ----------------------------------------------------------------------------
168
169class wxConditionInternal
170{
0e320a79 171public:
3437f881 172 inline wxConditionInternal (wxMutex& rMutex) : m_vMutex(rMutex)
d01cc696
DW
173 {
174 ::DosCreateEventSem(NULL, &m_vEvent, DC_SEM_SHARED, FALSE);
175 if (!m_vEvent)
176 {
177 wxLogSysError(_("Can not create event semaphore."));
178 }
179 m_nWaiters = 0;
180 }
181
47df2b8c 182 inline APIRET Wait(
d01cc696
DW
183 unsigned long ulTimeout
184 )
185 {
186 APIRET ulrc;
187
188 m_nWaiters++;
189 ulrc = ::DosWaitEventSem(m_vEvent, ulTimeout);
190 m_nWaiters--;
47df2b8c 191 return (ulrc);
d01cc696
DW
192 }
193
194 inline ~wxConditionInternal ()
195 {
196 APIRET ulrc;
197
198 if (m_vEvent)
199 {
200 ulrc = ::DosCloseEventSem(m_vEvent);
201 if (!ulrc)
202 {
203 wxLogLastError("DosCloseEventSem(m_vEvent)");
204 }
205 }
206 }
207
c5fb56c0
DW
208 HEV m_vEvent;
209 int m_nWaiters;
3437f881 210 wxMutex& m_vMutex;
0e320a79
DW
211};
212
3437f881 213wxCondition::wxCondition(wxMutex& rMutex)
0e320a79 214{
c5fb56c0
DW
215 APIRET ulrc;
216 ULONG ulCount;
217
3437f881 218 m_internal = new wxConditionInternal(rMutex);
d01cc696 219 ulrc = ::DosCreateEventSem(NULL, &m_internal->m_vEvent, 0L, FALSE);
c5fb56c0 220 if (ulrc != 0)
d90895ac
DW
221 {
222 wxLogSysError(_("Can not create event object."));
223 }
d01cc696 224 m_internal->m_nWaiters = 0;
c5fb56c0 225 // ?? just for good measure?
d01cc696 226 ::DosResetEventSem(m_internal->m_vEvent, &ulCount);
0e320a79
DW
227}
228
229wxCondition::~wxCondition()
230{
d01cc696
DW
231 ::DosCloseEventSem(m_internal->m_vEvent);
232 delete m_internal;
233 m_internal = NULL;
0e320a79
DW
234}
235
47df2b8c 236wxCondError wxCondition::Wait()
0e320a79 237{
47df2b8c
DW
238 APIRET rc = m_internal->Wait(SEM_INDEFINITE_WAIT);
239
240 switch(rc)
241 {
242 case NO_ERROR:
243 return wxCOND_NO_ERROR;
244 case ERROR_INVALID_HANDLE:
245 return wxCOND_INVALID;
246 case ERROR_TIMEOUT:
247 return wxCOND_TIMEOUT;
248 default:
249 return wxCOND_MISC_ERROR;
250 }
0e320a79
DW
251}
252
47df2b8c 253wxCondError wxCondition::WaitTimeout(
3437f881
DW
254 unsigned long lMilliSec
255)
0e320a79 256{
47df2b8c
DW
257 APIRET rc = m_internal->Wait(lMilliSec);
258
259 switch(rc)
260 {
261 case NO_ERROR:
262 return wxCOND_NO_ERROR;
263 case ERROR_INVALID_HANDLE:
264 return wxCOND_INVALID;
265 case ERROR_TIMEOUT:
266 return wxCOND_TIMEOUT;
267 default:
268 return wxCOND_MISC_ERROR;
269 }
0e320a79
DW
270}
271
47df2b8c 272wxCondError wxCondition::Signal()
0e320a79 273{
47df2b8c
DW
274 APIRET rc = ::DosPostEventSem(m_internal->m_vEvent);
275
276 switch(rc)
277 {
278 case NO_ERROR:
279 return wxCOND_NO_ERROR;
280 case ERROR_INVALID_HANDLE:
281 return wxCOND_INVALID;
282 default:
283 return wxCOND_MISC_ERROR;
284 }
0e320a79
DW
285}
286
47df2b8c 287wxCondError wxCondition::Broadcast()
0e320a79 288{
c5fb56c0 289 int i;
47df2b8c 290 APIRET rc = NO_ERROR;
d90895ac 291
d01cc696 292 for (i = 0; i < m_internal->m_nWaiters; i++)
d90895ac 293 {
47df2b8c 294 if ((rc = ::DosPostEventSem(m_internal->m_vEvent)) != NO_ERROR)
d90895ac
DW
295 {
296 wxLogSysError(_("Couldn't change the state of event object."));
47df2b8c 297 break;
d90895ac
DW
298 }
299 }
47df2b8c
DW
300
301 switch(rc)
302 {
303 case NO_ERROR:
304 return wxCOND_NO_ERROR;
305 case ERROR_INVALID_HANDLE:
306 return wxCOND_INVALID;
307 default:
308 return wxCOND_MISC_ERROR;
309 }
0e320a79
DW
310}
311
892b89f3
DW
312// ----------------------------------------------------------------------------
313// wxCriticalSection implementation
314// ----------------------------------------------------------------------------
315
316wxCriticalSection::wxCriticalSection()
317{
318}
319
320wxCriticalSection::~wxCriticalSection()
321{
322}
323
324void wxCriticalSection::Enter()
325{
326 ::DosEnterCritSec();
327}
328
329void wxCriticalSection::Leave()
330{
331 ::DosExitCritSec();
332}
333
d90895ac
DW
334// ----------------------------------------------------------------------------
335// wxThread implementation
336// ----------------------------------------------------------------------------
337
338// wxThreadInternal class
339// ----------------------
340
341class wxThreadInternal
342{
343public:
c5fb56c0 344 inline wxThreadInternal()
d90895ac
DW
345 {
346 m_hThread = 0;
c5fb56c0
DW
347 m_eState = STATE_NEW;
348 m_nPriority = 0;
d90895ac
DW
349 }
350
d01cc696
DW
351 ~wxThreadInternal()
352 {
353 Free();
354 }
355
356 void Free()
357 {
358 if (m_hThread)
359 {
360 ::DosExit(0,0);
361 m_hThread = 0;
362 }
363 }
364
d90895ac 365 // create a new (suspended) thread (for the given thread object)
793c7f9b
DW
366 bool Create( wxThread* pThread
367 ,unsigned int uStackSize
368 );
d90895ac
DW
369
370 // suspend/resume/terminate
371 bool Suspend();
372 bool Resume();
c5fb56c0 373 inline void Cancel() { m_eState = STATE_CANCELED; }
d90895ac
DW
374
375 // thread state
c5fb56c0
DW
376 inline void SetState(wxThreadState eState) { m_eState = eState; }
377 inline wxThreadState GetState() const { return m_eState; }
d90895ac
DW
378
379 // thread priority
d01cc696 380 void SetPriority(unsigned int nPriority);
c5fb56c0 381 inline unsigned int GetPriority() const { return m_nPriority; }
d90895ac
DW
382
383 // thread handle and id
c5fb56c0
DW
384 inline TID GetHandle() const { return m_hThread; }
385 TID GetId() const { return m_hThread; }
d90895ac
DW
386
387 // thread function
388 static DWORD OS2ThreadStart(wxThread *thread);
389
390private:
c5fb56c0
DW
391 // Threads in OS/2 have only an ID, so m_hThread is both it's handle and ID
392 // PM also has no real Tls mechanism to index pointers by so we'll just
393 // keep track of the wxWindows parent object here.
394 TID m_hThread; // handle and ID of the thread
395 wxThreadState m_eState; // state, see wxThreadState enum
396 unsigned int m_nPriority; // thread priority in "wx" units
d90895ac
DW
397};
398
c5fb56c0
DW
399ULONG wxThreadInternal::OS2ThreadStart(
400 wxThread* pThread
401)
d90895ac 402{
c5fb56c0 403 m_pThread = pThread;
d90895ac 404
c5fb56c0 405 DWORD dwRet = (DWORD)pThread->Entry();
d90895ac 406
d01cc696
DW
407 // enter m_critsect before changing the thread state
408 pThread->m_critsect.Enter();
409
43543d98 410 bool bWasCancelled = pThread->m_internal->GetState() == STATE_CANCELED;
d01cc696
DW
411
412 pThread->m_internal->SetState(STATE_EXITED);
43543d98 413 pThread->m_critsect.Leave();
d01cc696 414
c5fb56c0 415 pThread->OnExit();
d90895ac 416
d01cc696
DW
417 // if the thread was cancelled (from Delete()), then it the handle is still
418 // needed there
419 if (pThread->IsDetached() && !bWasCancelled)
420 {
421 // auto delete
43543d98 422 delete pThread;
d01cc696
DW
423 }
424 //else: the joinable threads handle will be closed when Wait() is done
c5fb56c0 425 return dwRet;
d90895ac
DW
426}
427
d01cc696
DW
428void wxThreadInternal::SetPriority(
429 unsigned int nPriority
c5fb56c0 430)
d90895ac 431{
c5fb56c0
DW
432 // translate wxWindows priority to the PM one
433 ULONG ulOS2_Priority;
43543d98 434 ULONG ulrc;
c5fb56c0 435
d01cc696
DW
436 m_nPriority = nPriority;
437
c5fb56c0
DW
438 if (m_nPriority <= 20)
439 ulOS2_Priority = PRTYC_NOCHANGE;
440 else if (m_nPriority <= 40)
441 ulOS2_Priority = PRTYC_IDLETIME;
442 else if (m_nPriority <= 60)
443 ulOS2_Priority = PRTYC_REGULAR;
444 else if (m_nPriority <= 80)
445 ulOS2_Priority = PRTYC_TIMECRITICAL;
446 else if (m_nPriority <= 100)
447 ulOS2_Priority = PRTYC_FOREGROUNDSERVER;
d90895ac
DW
448 else
449 {
450 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
c5fb56c0 451 ulOS2_Priority = PRTYC_REGULAR;
d90895ac 452 }
c5fb56c0
DW
453 ulrc = ::DosSetPriority( PRTYS_THREAD
454 ,ulOS2_Priority
455 ,0
456 ,(ULONG)m_hThread
457 );
458 if (ulrc != 0)
d90895ac
DW
459 {
460 wxLogSysError(_("Can't set thread priority"));
461 }
d01cc696
DW
462}
463
464bool wxThreadInternal::Create(
465 wxThread* pThread
793c7f9b 466, unsigned int uStackSize
d01cc696
DW
467)
468{
469 APIRET ulrc;
470
471 ulrc = ::DosCreateThread( &m_hThread
472 ,(PFNTHREAD)wxThreadInternal::OS2ThreadStart
473 ,(ULONG)pThread
474 ,CREATE_SUSPENDED | STACK_SPARSE
793c7f9b 475 ,(ULONG)uStackSize
d01cc696
DW
476 );
477 if(ulrc != 0)
478 {
479 wxLogSysError(_("Can't create thread"));
480
481 return FALSE;
482 }
483 if (m_nPriority != WXTHREAD_DEFAULT_PRIORITY)
484 {
485 SetPriority(m_nPriority);
486 }
1dfc3cda
JS
487
488 m_eState = STATE_NEW;
489
d01cc696 490 return(TRUE);
d90895ac
DW
491}
492
493bool wxThreadInternal::Suspend()
494{
c5fb56c0 495 ULONG ulrc = ::DosSuspendThread(m_hThread);
d90895ac 496
c5fb56c0
DW
497 if (ulrc != 0)
498 {
499 wxLogSysError(_("Can not suspend thread %lu"), m_hThread);
d90895ac
DW
500 return FALSE;
501 }
c5fb56c0
DW
502 m_eState = STATE_PAUSED;
503 return TRUE;
d90895ac
DW
504}
505
506bool wxThreadInternal::Resume()
507{
c5fb56c0 508 ULONG ulrc = ::DosResumeThread(m_hThread);
d90895ac 509
c5fb56c0
DW
510 if (ulrc != 0)
511 {
512 wxLogSysError(_("Can not suspend thread %lu"), m_hThread);
d90895ac
DW
513 return FALSE;
514 }
c5fb56c0
DW
515 m_eState = STATE_PAUSED;
516 return TRUE;
d90895ac
DW
517}
518
519// static functions
520// ----------------
521
522wxThread *wxThread::This()
523{
c5fb56c0
DW
524 wxThread* pThread = m_pThread;
525 return pThread;
d90895ac
DW
526}
527
528bool wxThread::IsMain()
529{
c5fb56c0
DW
530 PTIB ptib;
531 PPIB ppib;
532
533 ::DosGetInfoBlocks(&ptib, &ppib);
534
535 if (ptib->tib_ptib2->tib2_ultid == s_ulIdMainThread)
536 return TRUE;
d90895ac
DW
537 return FALSE;
538}
539
540#ifdef Yield
541 #undef Yield
542#endif
543
544void wxThread::Yield()
545{
d90895ac
DW
546 ::DosSleep(0);
547}
548
c5fb56c0
DW
549void wxThread::Sleep(
550 unsigned long ulMilliseconds
551)
d90895ac 552{
c5fb56c0 553 ::DosSleep(ulMilliseconds);
d90895ac
DW
554}
555
d01cc696
DW
556// ctor and dtor
557// -------------
558
559wxThread::wxThread(wxThreadKind kind)
560{
561 m_internal = new wxThreadInternal();
562
563 m_isDetached = kind == wxTHREAD_DETACHED;
564}
565
566wxThread::~wxThread()
567{
568 delete m_internal;
569}
570
d90895ac
DW
571// create/start thread
572// -------------------
573
793c7f9b
DW
574wxThreadError wxThread::Create(
575 unsigned int uStackSize
576)
0e320a79 577{
793c7f9b 578 if ( !m_internal->Create(this, uStackSize) )
d90895ac
DW
579 return wxTHREAD_NO_RESOURCE;
580
0e320a79
DW
581 return wxTHREAD_NO_ERROR;
582}
583
d90895ac 584wxThreadError wxThread::Run()
0e320a79 585{
c5fb56c0 586 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 587
d01cc696 588 if ( m_internal->GetState() != STATE_NEW )
d90895ac
DW
589 {
590 // actually, it may be almost any state at all, not only STATE_RUNNING
591 return wxTHREAD_RUNNING;
592 }
d90895ac 593 return Resume();
0e320a79
DW
594}
595
d90895ac
DW
596// suspend/resume thread
597// ---------------------
598
0e320a79
DW
599wxThreadError wxThread::Pause()
600{
c5fb56c0 601 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 602
d01cc696 603 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
0e320a79
DW
604}
605
606wxThreadError wxThread::Resume()
607{
c5fb56c0 608 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
0e320a79 609
d01cc696 610 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
0e320a79
DW
611}
612
d90895ac
DW
613// stopping thread
614// ---------------
615
d01cc696 616wxThread::ExitCode wxThread::Wait()
0e320a79 617{
d01cc696
DW
618 // although under Windows we can wait for any thread, it's an error to
619 // wait for a detached one in wxWin API
620 wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
621 _T("can't wait for detached thread") );
622 ExitCode rc = (ExitCode)-1;
623 (void)Delete(&rc);
624 m_internal->Free();
625 return(rc);
626}
627
628wxThreadError wxThread::Delete(ExitCode *pRc)
629{
630 ExitCode rc = 0;
d90895ac
DW
631
632 // Delete() is always safe to call, so consider all possible states
c5fb56c0 633 if (IsPaused())
d90895ac
DW
634 Resume();
635
d01cc696
DW
636 TID hThread = m_internal->GetHandle();
637
c5fb56c0 638 if (IsRunning())
d90895ac 639 {
c5fb56c0 640 if (IsMain())
d90895ac
DW
641 {
642 // set flag for wxIsWaitingForThread()
43543d98 643 gs_bWaitingForThread = TRUE;
d01cc696
DW
644
645#if wxUSE_GUI
d90895ac 646 wxBeginBusyCursor();
d01cc696 647#endif // wxUSE_GUI
d90895ac
DW
648 }
649
d01cc696 650 // ask the thread to terminate
d90895ac 651 {
d01cc696
DW
652 wxCriticalSectionLocker lock(m_critsect);
653 m_internal->Cancel();
d90895ac
DW
654 }
655
d01cc696 656#if wxUSE_GUI
3b9e3455
DW
657 // need a way to finish GUI processing before killing the thread
658 // until then we just exit
659
660 if ((gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread())
d01cc696 661 {
3b9e3455 662 wxMutexGuiLeave();
d01cc696 663 }
3b9e3455
DW
664#else // !wxUSE_GUI
665
666 // can't wait for yourself to end under OS/2 so just quit
667
d01cc696 668#endif // wxUSE_GUI/!wxUSE_GUI
d90895ac 669
d01cc696 670 if ( IsMain() )
d90895ac 671 {
43543d98 672 gs_bWaitingForThread = FALSE;
d01cc696
DW
673
674#if wxUSE_GUI
c5fb56c0 675 wxEndBusyCursor();
d01cc696 676#endif // wxUSE_GUI
d90895ac 677 }
d01cc696
DW
678 }
679
3b9e3455
DW
680 ::DosExit(0, 0);
681 // probably won't get this far, but
682 if (IsDetached())
d01cc696 683 {
d01cc696
DW
684 delete this;
685 }
686
d01cc696
DW
687 if ( pRc )
688 *pRc = rc;
689
690 return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;
0e320a79
DW
691}
692
d90895ac 693wxThreadError wxThread::Kill()
0e320a79 694{
c5fb56c0 695 if (!IsRunning())
d90895ac
DW
696 return wxTHREAD_NOT_RUNNING;
697
d01cc696 698 ::DosKillThread(m_internal->GetHandle());
3b9e3455
DW
699 m_internal->Free();
700 if (IsDetached())
701 {
702 delete this;
703 }
d90895ac 704 return wxTHREAD_NO_ERROR;
0e320a79
DW
705}
706
c5fb56c0 707void wxThread::Exit(
3b9e3455 708 ExitCode pStatus
c5fb56c0 709)
0e320a79 710{
3b9e3455 711 m_internal->Free();
d90895ac 712 delete this;
c5fb56c0
DW
713 ::DosExit(EXIT_THREAD, ULONG(pStatus));
714 wxFAIL_MSG(wxT("Couldn't return from DosExit()!"));
0e320a79
DW
715}
716
c5fb56c0
DW
717void wxThread::SetPriority(
718 unsigned int nPrio
719)
0e320a79 720{
c5fb56c0 721 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 722
d01cc696 723 m_internal->SetPriority(nPrio);
0e320a79
DW
724}
725
d90895ac 726unsigned int wxThread::GetPriority() const
0e320a79 727{
c5fb56c0 728 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 729
d01cc696 730 return m_internal->GetPriority();
0e320a79
DW
731}
732
3b9e3455
DW
733unsigned long wxThread::GetId() const
734{
735 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
736
737 return (unsigned long)m_internal->GetId();
738}
739
d90895ac 740bool wxThread::IsRunning() const
0e320a79 741{
c5fb56c0 742 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 743
3b9e3455 744 return(m_internal->GetState() == STATE_RUNNING);
0e320a79 745}
0e320a79
DW
746
747bool wxThread::IsAlive() const
748{
c5fb56c0 749 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 750
d01cc696
DW
751 return (m_internal->GetState() == STATE_RUNNING) ||
752 (m_internal->GetState() == STATE_PAUSED);
0e320a79
DW
753}
754
d90895ac 755bool wxThread::IsPaused() const
0e320a79 756{
c5fb56c0 757 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 758
d01cc696 759 return (m_internal->GetState() == STATE_PAUSED);
0e320a79
DW
760}
761
d90895ac 762bool wxThread::TestDestroy()
0e320a79 763{
c5fb56c0 764 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 765
d01cc696 766 return m_internal->GetState() == STATE_CANCELED;
0e320a79
DW
767}
768
d90895ac
DW
769// ----------------------------------------------------------------------------
770// Automatic initialization for thread module
771// ----------------------------------------------------------------------------
0e320a79 772
d90895ac
DW
773class wxThreadModule : public wxModule
774{
0e320a79 775public:
d90895ac
DW
776 virtual bool OnInit();
777 virtual void OnExit();
0e320a79 778
d90895ac
DW
779private:
780 DECLARE_DYNAMIC_CLASS(wxThreadModule)
0e320a79
DW
781};
782
783IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
784
d90895ac
DW
785bool wxThreadModule::OnInit()
786{
43543d98 787 gs_pCritsectWaitingForGui = new wxCriticalSection();
d90895ac 788
43543d98
DW
789 gs_pCritsectGui = new wxCriticalSection();
790 gs_pCritsectGui->Enter();
d90895ac 791
c5fb56c0
DW
792 PTIB ptib;
793 PPIB ppib;
d90895ac 794
c5fb56c0 795 ::DosGetInfoBlocks(&ptib, &ppib);
d90895ac 796
c5fb56c0 797 s_ulIdMainThread = ptib->tib_ptib2->tib2_ultid;
d90895ac
DW
798 return TRUE;
799}
800
801void wxThreadModule::OnExit()
802{
43543d98 803 if (gs_pCritsectGui)
d90895ac 804 {
43543d98 805 gs_pCritsectGui->Leave();
f6bcfd97 806#if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
43543d98 807 delete gs_pCritsectGui;
f6bcfd97 808#endif
43543d98 809 gs_pCritsectGui = NULL;
d90895ac
DW
810 }
811
f6bcfd97 812#if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
43543d98 813 wxDELETE(gs_pCritsectWaitingForGui);
f6bcfd97 814#endif
d90895ac
DW
815}
816
817// ----------------------------------------------------------------------------
c5fb56c0 818// Helper functions
d90895ac
DW
819// ----------------------------------------------------------------------------
820
c5fb56c0
DW
821// Does nothing under OS/2 [for now]
822void WXDLLEXPORT wxWakeUpMainThread()
d90895ac 823{
d90895ac
DW
824}
825
826void WXDLLEXPORT wxMutexGuiLeave()
827{
43543d98 828 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
d90895ac
DW
829
830 if ( wxThread::IsMain() )
831 {
43543d98 832 gs_bGuiOwnedByMainThread = FALSE;
d90895ac
DW
833 }
834 else
835 {
836 // decrement the number of waiters now
43543d98 837 wxASSERT_MSG(gs_nWaitingForGui > 0,
d90895ac
DW
838 wxT("calling wxMutexGuiLeave() without entering it first?") );
839
43543d98 840 gs_nWaitingForGui--;
d90895ac
DW
841
842 wxWakeUpMainThread();
843 }
844
43543d98 845 gs_pCritsectGui->Leave();
d90895ac
DW
846}
847
848void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
849{
850 wxASSERT_MSG( wxThread::IsMain(),
851 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
852
43543d98 853 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
d90895ac 854
43543d98 855 if (gs_nWaitingForGui == 0)
d90895ac
DW
856 {
857 // no threads are waiting for GUI - so we may acquire the lock without
858 // any danger (but only if we don't already have it)
c5fb56c0 859 if (!wxGuiOwnedByMainThread())
d90895ac 860 {
43543d98 861 gs_pCritsectGui->Enter();
d90895ac 862
43543d98 863 gs_bGuiOwnedByMainThread = TRUE;
d90895ac
DW
864 }
865 //else: already have it, nothing to do
866 }
867 else
868 {
869 // some threads are waiting, release the GUI lock if we have it
c5fb56c0 870 if (wxGuiOwnedByMainThread())
d90895ac
DW
871 {
872 wxMutexGuiLeave();
873 }
874 //else: some other worker thread is doing GUI
875 }
876}
877
878bool WXDLLEXPORT wxGuiOwnedByMainThread()
879{
43543d98 880 return gs_bGuiOwnedByMainThread;
d90895ac
DW
881}
882
9ed0fac8
DW
883bool WXDLLEXPORT wxIsWaitingForThread()
884{
43543d98 885 return gs_bWaitingForThread;
9ed0fac8
DW
886}
887
0e320a79
DW
888#endif
889 // wxUSE_THREADS