]> git.saurik.com Git - wxWidgets.git/blame - src/os2/thread.cpp
Added Cocoa_canBecomeKeyWindow.
[wxWidgets.git] / src / os2 / thread.cpp
CommitLineData
0e320a79 1/////////////////////////////////////////////////////////////////////////////
d1bab566
SN
2// Name: src/os2/thread.cpp
3// Purpose: wxThread Implementation
4// Author: Original from Wolfram Gloger/Guilhem Lavaux/David Webster
5// Modified by: Stefan Neis
0e320a79
DW
6// Created: 04/22/98
7// RCS-ID: $Id$
d1bab566 8// Copyright: (c) Stefan Neis (2003)
17b35e1d 9//
65571936 10// Licence: wxWindows licence
0e320a79
DW
11/////////////////////////////////////////////////////////////////////////////
12
d90895ac
DW
13// ----------------------------------------------------------------------------
14// headers
15// ----------------------------------------------------------------------------
0e320a79 16
d90895ac
DW
17// For compilers that support precompilation, includes "wx.h".
18#include "wx/wxprec.h"
0e320a79
DW
19
20#if wxUSE_THREADS
21
d90895ac
DW
22#include <stdio.h>
23
d1bab566 24#include "wx/app.h"
737928c2 25#include "wx/apptrait.h"
d90895ac 26#include "wx/module.h"
19193a2c
KB
27#include "wx/intl.h"
28#include "wx/utils.h"
29#include "wx/log.h"
d90895ac
DW
30#include "wx/thread.h"
31
c5fb56c0
DW
32#define INCL_DOSSEMAPHORES
33#define INCL_DOSPROCESS
d1bab566 34#define INCL_DOSMISC
c5fb56c0
DW
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 51// ----------------------------------------------------------------------------
d1bab566 52// this module's globals
d90895ac 53// ----------------------------------------------------------------------------
0e320a79 54
d90895ac
DW
55// id of the main thread - the one which can call GUI functions without first
56// calling wxMutexGuiEnter()
d1bab566 57static ULONG s_ulIdMainThread = 1;
c5fb56c0
DW
58wxMutex* p_wxMainMutex;
59
60// OS2 substitute for Tls pointer the current parent thread object
77ffb593 61wxThread* m_pThread; // pointer to the wxWidgets thread object
d90895ac 62
6670f564
WS
63// if it's false, some secondary thread is holding the GUI lock
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?
6670f564 78static bool gs_bWaitingForThread = false;
d90895ac
DW
79
80// ============================================================================
d1bab566 81// OS/2 implementation of thread and related classes
d90895ac
DW
82// ============================================================================
83
84// ----------------------------------------------------------------------------
85// wxMutex implementation
86// ----------------------------------------------------------------------------
87class wxMutexInternal
88{
0e320a79 89public:
d1bab566
SN
90 wxMutexInternal(wxMutexType mutexType);
91 ~wxMutexInternal();
92
93 bool IsOk() const { return m_vMutex != NULL; }
94
95 wxMutexError Lock() { return LockTimeout(SEM_INDEFINITE_WAIT); }
96 wxMutexError TryLock() { return LockTimeout(SEM_IMMEDIATE_RETURN); }
97 wxMutexError Unlock();
98
99private:
100 wxMutexError LockTimeout(ULONG ulMilliseconds);
c5fb56c0 101 HMTX m_vMutex;
0e320a79
DW
102};
103
d1bab566
SN
104// all mutexes are "pseudo-"recursive under OS2 so we don't use mutexType
105// (Calls to DosRequestMutexSem and DosReleaseMutexSem can be nested, but
106// the request count for a semaphore cannot exceed 65535. If an attempt is
107// made to exceed this number, ERROR_TOO_MANY_SEM_REQUESTS is returned.)
6670f564 108wxMutexInternal::wxMutexInternal(wxMutexType WXUNUSED(eMutexType))
0e320a79 109{
6670f564 110 APIRET ulrc = ::DosCreateMutexSem(NULL, &m_vMutex, 0L, FALSE);
c5fb56c0 111 if (ulrc != 0)
d90895ac
DW
112 {
113 wxLogSysError(_("Can not create mutex."));
d1bab566 114 m_vMutex = NULL;
d90895ac 115 }
0e320a79
DW
116}
117
d1bab566 118wxMutexInternal::~wxMutexInternal()
0e320a79 119{
d1bab566
SN
120 if (m_vMutex)
121 {
122 if (::DosCloseMutexSem(m_vMutex))
123 wxLogLastError(_T("DosCloseMutexSem(mutex)"));
124 }
0e320a79
DW
125}
126
d1bab566 127wxMutexError wxMutexInternal::LockTimeout(ULONG ulMilliseconds)
0e320a79 128{
c5fb56c0
DW
129 APIRET ulrc;
130
d1bab566 131 ulrc = ::DosRequestMutexSem(m_vMutex, ulMilliseconds);
d90895ac 132
c5fb56c0 133 switch (ulrc)
d90895ac 134 {
d1bab566 135 case ERROR_TIMEOUT:
c5fb56c0 136 case ERROR_TOO_MANY_SEM_REQUESTS:
d90895ac
DW
137 return wxMUTEX_BUSY;
138
c5fb56c0 139 case NO_ERROR:
d90895ac
DW
140 // ok
141 break;
142
c5fb56c0
DW
143 case ERROR_INVALID_HANDLE:
144 case ERROR_INTERRUPT:
145 case ERROR_SEM_OWNER_DIED:
d90895ac
DW
146 wxLogSysError(_("Couldn't acquire a mutex lock"));
147 return wxMUTEX_MISC_ERROR;
148
d90895ac
DW
149 default:
150 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
d1bab566
SN
151 return wxMUTEX_MISC_ERROR;
152 }
0e320a79
DW
153 return wxMUTEX_NO_ERROR;
154}
155
d1bab566 156wxMutexError wxMutexInternal::Unlock()
0e320a79 157{
c5fb56c0
DW
158 APIRET ulrc;
159
d1bab566 160 ulrc = ::DosReleaseMutexSem(m_vMutex);
c5fb56c0 161 if (ulrc != 0)
d90895ac
DW
162 {
163 wxLogSysError(_("Couldn't release a mutex"));
164 return wxMUTEX_MISC_ERROR;
165 }
0e320a79
DW
166 return wxMUTEX_NO_ERROR;
167}
168
d1bab566
SN
169// --------------------------------------------------------------------------
170// wxSemaphore
171// --------------------------------------------------------------------------
d90895ac 172
d1bab566
SN
173// a trivial wrapper around OS2 event semaphore
174class wxSemaphoreInternal
d90895ac 175{
0e320a79 176public:
d1bab566
SN
177 wxSemaphoreInternal(int initialcount, int maxcount);
178 ~wxSemaphoreInternal();
d01cc696 179
d1bab566 180 bool IsOk() const { return m_vEvent != NULL; }
d01cc696 181
d1bab566
SN
182 wxSemaError Wait() { return WaitTimeout(SEM_INDEFINITE_WAIT); }
183 wxSemaError TryWait() { return WaitTimeout(SEM_IMMEDIATE_RETURN); }
184 wxSemaError WaitTimeout(unsigned long milliseconds);
d01cc696 185
d1bab566 186 wxSemaError Post();
d01cc696 187
d1bab566
SN
188private:
189 HEV m_vEvent;
190 HMTX m_vMutex;
191 int m_count;
192 int m_maxcount;
0e320a79
DW
193};
194
d1bab566 195wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
0e320a79 196{
d1bab566
SN
197 APIRET ulrc;
198 if ( maxcount == 0 )
d90895ac 199 {
d1bab566
SN
200 // make it practically infinite
201 maxcount = INT_MAX;
d90895ac 202 }
0e320a79 203
d1bab566
SN
204 m_count = initialcount;
205 m_maxcount = maxcount;
206 ulrc = ::DosCreateMutexSem(NULL, &m_vMutex, 0L, FALSE);
207 if (ulrc != 0)
47df2b8c 208 {
d1bab566
SN
209 wxLogLastError(_T("DosCreateMutexSem()"));
210 m_vMutex = NULL;
211 m_vEvent = NULL;
212 return;
47df2b8c 213 }
d1bab566
SN
214 ulrc = ::DosCreateEventSem(NULL, &m_vEvent, 0L, FALSE);
215 if ( ulrc != 0)
47df2b8c 216 {
d1bab566
SN
217 wxLogLastError(_T("DosCreateEventSem()"));
218 ::DosCloseMutexSem(m_vMutex);
219 m_vMutex = NULL;
220 m_vEvent = NULL;
47df2b8c 221 }
d1bab566
SN
222 if (initialcount)
223 ::DosPostEventSem(m_vEvent);
0e320a79
DW
224}
225
d1bab566 226wxSemaphoreInternal::~wxSemaphoreInternal()
0e320a79 227{
d1bab566 228 if ( m_vEvent )
d90895ac 229 {
d1bab566 230 if ( ::DosCloseEventSem(m_vEvent) )
d90895ac 231 {
d1bab566 232 wxLogLastError(_T("DosCloseEventSem(semaphore)"));
d90895ac 233 }
d1bab566
SN
234 if ( ::DosCloseMutexSem(m_vMutex) )
235 {
236 wxLogLastError(_T("DosCloseMutexSem(semaphore)"));
237 }
238 else
239 m_vEvent = NULL;
47df2b8c 240 }
0e320a79
DW
241}
242
d1bab566 243wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long ulMilliseconds)
892b89f3 244{
d1bab566
SN
245 APIRET ulrc;
246 do {
247 ulrc = ::DosWaitEventSem(m_vEvent, ulMilliseconds );
248 switch ( ulrc )
249 {
250 case NO_ERROR:
251 break;
252
253 case ERROR_TIMEOUT:
254 if (ulMilliseconds == SEM_IMMEDIATE_RETURN)
255 return wxSEMA_BUSY;
256 else
257 return wxSEMA_TIMEOUT;
258
259 default:
260 wxLogLastError(_T("DosWaitEventSem(semaphore)"));
261 return wxSEMA_MISC_ERROR;
262 }
263 ulrc = :: DosRequestMutexSem(m_vMutex, ulMilliseconds);
264 switch ( ulrc )
265 {
266 case NO_ERROR:
267 // ok
268 break;
269
270 case ERROR_TIMEOUT:
271 case ERROR_TOO_MANY_SEM_REQUESTS:
272 if (ulMilliseconds == SEM_IMMEDIATE_RETURN)
273 return wxSEMA_BUSY;
274 else
275 return wxSEMA_TIMEOUT;
276
277 default:
278 wxFAIL_MSG(wxT("DosRequestMutexSem(mutex)"));
279 return wxSEMA_MISC_ERROR;
280 }
281 bool OK = false;
282 if (m_count > 0)
283 {
284 m_count--;
285 OK = true;
286 }
287 else
288 {
289 ULONG ulPostCount;
290 ::DosResetEventSem(m_vEvent, &ulPostCount);
291 }
292 ::DosReleaseMutexSem(m_vMutex);
293 if (OK)
294 return wxSEMA_NO_ERROR;
295 } while (ulMilliseconds == SEM_INDEFINITE_WAIT);
296
297 if (ulMilliseconds == SEM_IMMEDIATE_RETURN)
298 return wxSEMA_BUSY;
299 return wxSEMA_TIMEOUT;
892b89f3
DW
300}
301
d1bab566 302wxSemaError wxSemaphoreInternal::Post()
892b89f3 303{
d1bab566
SN
304 APIRET ulrc;
305 ulrc = ::DosRequestMutexSem(m_vMutex, SEM_INDEFINITE_WAIT);
306 if (ulrc != NO_ERROR)
307 return wxSEMA_MISC_ERROR;
308 bool OK = false;
309 if (m_count < m_maxcount)
310 {
311 m_count++;
312 ulrc = ::DosPostEventSem(m_vEvent);
313 OK = true;
314 }
315 ::DosReleaseMutexSem(m_vMutex);
316 if (!OK)
317 return wxSEMA_OVERFLOW;
318 if ( ulrc != NO_ERROR && ulrc != ERROR_ALREADY_POSTED )
319 {
320 wxLogLastError(_T("DosPostEventSem(semaphore)"));
892b89f3 321
d1bab566
SN
322 return wxSEMA_MISC_ERROR;
323 }
892b89f3 324
d1bab566 325 return wxSEMA_NO_ERROR;
892b89f3
DW
326}
327
d90895ac
DW
328// ----------------------------------------------------------------------------
329// wxThread implementation
330// ----------------------------------------------------------------------------
331
332// wxThreadInternal class
333// ----------------------
334
335class wxThreadInternal
336{
337public:
c5fb56c0 338 inline wxThreadInternal()
d90895ac
DW
339 {
340 m_hThread = 0;
c5fb56c0 341 m_eState = STATE_NEW;
d1bab566 342 m_nPriority = WXTHREAD_DEFAULT_PRIORITY;
d90895ac
DW
343 }
344
d01cc696
DW
345 ~wxThreadInternal()
346 {
d1bab566 347 m_hThread = 0;
d01cc696
DW
348 }
349
d90895ac 350 // create a new (suspended) thread (for the given thread object)
793c7f9b
DW
351 bool Create( wxThread* pThread
352 ,unsigned int uStackSize
353 );
d90895ac
DW
354
355 // suspend/resume/terminate
356 bool Suspend();
357 bool Resume();
c5fb56c0 358 inline void Cancel() { m_eState = STATE_CANCELED; }
d90895ac
DW
359
360 // thread state
c5fb56c0
DW
361 inline void SetState(wxThreadState eState) { m_eState = eState; }
362 inline wxThreadState GetState() const { return m_eState; }
d90895ac
DW
363
364 // thread priority
d01cc696 365 void SetPriority(unsigned int nPriority);
c5fb56c0 366 inline unsigned int GetPriority() const { return m_nPriority; }
d90895ac
DW
367
368 // thread handle and id
c5fb56c0
DW
369 inline TID GetHandle() const { return m_hThread; }
370 TID GetId() const { return m_hThread; }
d90895ac
DW
371
372 // thread function
f877815e 373 static void OS2ThreadStart(void* pParam);
d90895ac
DW
374
375private:
c5fb56c0
DW
376 // Threads in OS/2 have only an ID, so m_hThread is both it's handle and ID
377 // PM also has no real Tls mechanism to index pointers by so we'll just
77ffb593 378 // keep track of the wxWidgets parent object here.
c5fb56c0
DW
379 TID m_hThread; // handle and ID of the thread
380 wxThreadState m_eState; // state, see wxThreadState enum
381 unsigned int m_nPriority; // thread priority in "wx" units
d90895ac
DW
382};
383
f877815e
SN
384void wxThreadInternal::OS2ThreadStart(
385 void * pParam
c5fb56c0 386)
d90895ac 387{
d1bab566
SN
388 DWORD dwRet;
389 bool bWasCancelled;
d90895ac 390
f877815e
SN
391 wxThread *pThread = (wxThread *)pParam;
392
393 // first of all, wait for the thread to be started.
394 pThread->m_critsect.Enter();
395 pThread->m_critsect.Leave();
396 // Now check whether we hadn't been cancelled already and don't
397 // start the user code at all in this case.
d1bab566
SN
398 if ( pThread->m_internal->GetState() == STATE_EXITED )
399 {
400 dwRet = (DWORD)-1;
6670f564 401 bWasCancelled = true;
d1bab566
SN
402 }
403 else // do run thread
404 {
737928c2
SN
405 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
406 unsigned long ulHab;
17b35e1d
SN
407 if (traits)
408 traits->InitializeGui(ulHab);
d1bab566 409 dwRet = (DWORD)pThread->Entry();
17b35e1d
SN
410 if (traits)
411 traits->TerminateGui(ulHab);
d01cc696 412
17b35e1d
SN
413 // enter m_critsect before changing the thread state
414 pThread->m_critsect.Enter();
d01cc696 415
17b35e1d 416 bWasCancelled = pThread->m_internal->GetState() == STATE_CANCELED;
d01cc696 417
17b35e1d
SN
418 pThread->m_internal->SetState(STATE_EXITED);
419 pThread->m_critsect.Leave();
d1bab566 420 }
c5fb56c0 421 pThread->OnExit();
d90895ac 422
d01cc696
DW
423 // if the thread was cancelled (from Delete()), then it the handle is still
424 // needed there
425 if (pThread->IsDetached() && !bWasCancelled)
426 {
427 // auto delete
43543d98 428 delete pThread;
d01cc696
DW
429 }
430 //else: the joinable threads handle will be closed when Wait() is done
f877815e 431 return;
d90895ac
DW
432}
433
d01cc696
DW
434void wxThreadInternal::SetPriority(
435 unsigned int nPriority
c5fb56c0 436)
d90895ac 437{
77ffb593 438 // translate wxWidgets priority to the PM one
d1bab566
SN
439 ULONG ulOS2_PriorityClass;
440 ULONG ulOS2_SubPriority;
43543d98 441 ULONG ulrc;
c5fb56c0 442
d01cc696 443 m_nPriority = nPriority;
d1bab566
SN
444 if (m_nPriority <= 25)
445 ulOS2_PriorityClass = PRTYC_IDLETIME;
446 else if (m_nPriority <= 50)
447 ulOS2_PriorityClass = PRTYC_REGULAR;
448 else if (m_nPriority <= 75)
449 ulOS2_PriorityClass = PRTYC_TIMECRITICAL;
c5fb56c0 450 else if (m_nPriority <= 100)
d1bab566 451 ulOS2_PriorityClass = PRTYC_FOREGROUNDSERVER;
d90895ac
DW
452 else
453 {
454 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
d1bab566 455 ulOS2_PriorityClass = PRTYC_REGULAR;
d90895ac 456 }
d1bab566 457 ulOS2_SubPriority = (ULONG) (((m_nPriority - 1) % 25 + 1) * 31.0 / 25);
c5fb56c0 458 ulrc = ::DosSetPriority( PRTYS_THREAD
d1bab566
SN
459 ,ulOS2_PriorityClass
460 ,ulOS2_SubPriority
c5fb56c0
DW
461 ,(ULONG)m_hThread
462 );
463 if (ulrc != 0)
d90895ac
DW
464 {
465 wxLogSysError(_("Can't set thread priority"));
466 }
d01cc696
DW
467}
468
6670f564
WS
469bool wxThreadInternal::Create( wxThread* pThread,
470 unsigned int uStackSize)
d01cc696 471{
6670f564 472 int tid;
17b35e1d 473
f877815e 474 if (!uStackSize)
6670f564
WS
475 uStackSize = 131072;
476
f877815e
SN
477 pThread->m_critsect.Enter();
478 tid = _beginthread(wxThreadInternal::OS2ThreadStart,
17b35e1d 479 NULL, uStackSize, pThread);
f877815e 480 if(tid == -1)
d01cc696
DW
481 {
482 wxLogSysError(_("Can't create thread"));
483
6670f564 484 return false;
d01cc696 485 }
f877815e 486 m_hThread = tid;
d01cc696
DW
487 if (m_nPriority != WXTHREAD_DEFAULT_PRIORITY)
488 {
489 SetPriority(m_nPriority);
490 }
1dfc3cda 491
6670f564 492 return true;
d90895ac
DW
493}
494
495bool wxThreadInternal::Suspend()
496{
6670f564 497 ULONG ulrc = ::DosSuspendThread(m_hThread);
d90895ac 498
c5fb56c0
DW
499 if (ulrc != 0)
500 {
501 wxLogSysError(_("Can not suspend thread %lu"), m_hThread);
6670f564 502 return false;
d90895ac 503 }
c5fb56c0 504 m_eState = STATE_PAUSED;
6670f564
WS
505
506 return true;
d90895ac
DW
507}
508
509bool wxThreadInternal::Resume()
510{
6670f564 511 ULONG ulrc = ::DosResumeThread(m_hThread);
d90895ac 512
c5fb56c0
DW
513 if (ulrc != 0)
514 {
f877815e 515 wxLogSysError(_("Can not resume thread %lu"), m_hThread);
6670f564 516 return false;
d90895ac 517 }
d1bab566
SN
518
519 // don't change the state from STATE_EXITED because it's special and means
520 // we are going to terminate without running any user code - if we did it,
521 // the codei n Delete() wouldn't work
522 if ( m_eState != STATE_EXITED )
523 {
524 m_eState = STATE_RUNNING;
525 }
526
6670f564 527 return true;
d90895ac
DW
528}
529
530// static functions
531// ----------------
532
533wxThread *wxThread::This()
534{
c5fb56c0
DW
535 wxThread* pThread = m_pThread;
536 return pThread;
d90895ac
DW
537}
538
539bool wxThread::IsMain()
540{
6670f564
WS
541 PTIB ptib;
542 PPIB ppib;
c5fb56c0
DW
543
544 ::DosGetInfoBlocks(&ptib, &ppib);
545
546 if (ptib->tib_ptib2->tib2_ultid == s_ulIdMainThread)
6670f564
WS
547 return true;
548
549 return false;
d90895ac
DW
550}
551
552#ifdef Yield
553 #undef Yield
554#endif
555
556void wxThread::Yield()
557{
d90895ac
DW
558 ::DosSleep(0);
559}
560
c5fb56c0
DW
561void wxThread::Sleep(
562 unsigned long ulMilliseconds
563)
d90895ac 564{
c5fb56c0 565 ::DosSleep(ulMilliseconds);
d90895ac
DW
566}
567
d1bab566
SN
568int wxThread::GetCPUCount()
569{
570 ULONG CPUCount;
571 APIRET ulrc;
572 ulrc = ::DosQuerySysInfo(26, 26, (void *)&CPUCount, sizeof(ULONG));
573 // QSV_NUMPROCESSORS(26) is typically not defined in header files
574
575 if (ulrc != 0)
576 CPUCount = 1;
577
578 return CPUCount;
579}
580
581unsigned long wxThread::GetCurrentId()
582{
583 PTIB ptib;
584 PPIB ppib;
585
586 ::DosGetInfoBlocks(&ptib, &ppib);
587 return (unsigned long) ptib->tib_ptib2->tib2_ultid;
588}
589
590bool wxThread::SetConcurrency(size_t level)
591{
592 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
593
594 // ok only for the default one
595 if ( level == 0 )
596 return 0;
597
598 // Don't know how to realize this on OS/2.
599 return level == 1;
600}
601
d01cc696
DW
602// ctor and dtor
603// -------------
604
605wxThread::wxThread(wxThreadKind kind)
606{
607 m_internal = new wxThreadInternal();
608
609 m_isDetached = kind == wxTHREAD_DETACHED;
610}
611
612wxThread::~wxThread()
613{
614 delete m_internal;
615}
616
d90895ac
DW
617// create/start thread
618// -------------------
619
793c7f9b
DW
620wxThreadError wxThread::Create(
621 unsigned int uStackSize
622)
0e320a79 623{
d1bab566
SN
624 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
625
793c7f9b 626 if ( !m_internal->Create(this, uStackSize) )
d90895ac
DW
627 return wxTHREAD_NO_RESOURCE;
628
0e320a79
DW
629 return wxTHREAD_NO_ERROR;
630}
631
d90895ac 632wxThreadError wxThread::Run()
0e320a79 633{
c5fb56c0 634 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 635
d01cc696 636 if ( m_internal->GetState() != STATE_NEW )
d90895ac
DW
637 {
638 // actually, it may be almost any state at all, not only STATE_RUNNING
639 return wxTHREAD_RUNNING;
640 }
d90895ac 641 return Resume();
0e320a79
DW
642}
643
d90895ac
DW
644// suspend/resume thread
645// ---------------------
646
0e320a79
DW
647wxThreadError wxThread::Pause()
648{
c5fb56c0 649 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 650
d01cc696 651 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
0e320a79
DW
652}
653
654wxThreadError wxThread::Resume()
655{
f877815e
SN
656 if (m_internal->GetState() == STATE_NEW)
657 {
17b35e1d 658 m_internal->SetState(STATE_RUNNING);
f877815e 659 m_critsect.Leave();
17b35e1d 660 return wxTHREAD_NO_ERROR;
f877815e
SN
661 }
662
c5fb56c0 663 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
0e320a79 664
d01cc696 665 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
0e320a79
DW
666}
667
d90895ac
DW
668// stopping thread
669// ---------------
670
d01cc696 671wxThread::ExitCode wxThread::Wait()
0e320a79 672{
d01cc696
DW
673 // although under Windows we can wait for any thread, it's an error to
674 // wait for a detached one in wxWin API
675 wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
676 _T("can't wait for detached thread") );
677 ExitCode rc = (ExitCode)-1;
678 (void)Delete(&rc);
d01cc696
DW
679 return(rc);
680}
681
682wxThreadError wxThread::Delete(ExitCode *pRc)
683{
684 ExitCode rc = 0;
d90895ac
DW
685
686 // Delete() is always safe to call, so consider all possible states
d1bab566
SN
687
688 // we might need to resume the thread, but we might also not need to cancel
689 // it if it doesn't run yet
6670f564
WS
690 bool shouldResume = false,
691 shouldCancel = true,
692 isRunning = false;
d1bab566
SN
693
694 // check if the thread already started to run
695 {
696 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
697
698 if ( m_internal->GetState() == STATE_NEW )
699 {
700 // WinThreadStart() will see it and terminate immediately, no need
701 // to cancel the thread - but we still need to resume it to let it
702 // run
703 m_internal->SetState(STATE_EXITED);
704
705 Resume(); // it knows about STATE_EXITED special case
706
6670f564
WS
707 shouldCancel = false;
708 isRunning = true;
d1bab566 709
6670f564 710 // shouldResume is correctly set to false here
d1bab566
SN
711 }
712 else
713 {
714 shouldResume = IsPaused();
715 }
716 }
717
718 // resume the thread if it is paused
719 if ( shouldResume )
d90895ac
DW
720 Resume();
721
6670f564 722 TID hThread = m_internal->GetHandle();
d01cc696 723
d1bab566 724 if ( isRunning || IsRunning())
d90895ac 725 {
c5fb56c0 726 if (IsMain())
d90895ac
DW
727 {
728 // set flag for wxIsWaitingForThread()
6670f564 729 gs_bWaitingForThread = true;
17b35e1d 730 }
d90895ac 731
d01cc696 732 // ask the thread to terminate
d1bab566 733 if ( shouldCancel )
d90895ac 734 {
d01cc696 735 wxCriticalSectionLocker lock(m_critsect);
d1bab566 736
d01cc696 737 m_internal->Cancel();
d90895ac
DW
738 }
739
17b35e1d 740#if 0
d1bab566
SN
741 // we can't just wait for the thread to terminate because it might be
742 // calling some GUI functions and so it will never terminate before we
743 // process the Windows messages that result from these functions
744 DWORD result = 0; // suppress warnings from broken compilers
745 do
d01cc696 746 {
d1bab566
SN
747 if ( IsMain() )
748 {
749 // give the thread we're waiting for chance to do the GUI call
750 // it might be in
751 if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
752 {
753 wxMutexGuiLeave();
754 }
755 }
756
f877815e 757 result = ::DosWaitThread(&hThread, DCWW_NOWAIT);
17b35e1d 758 // FIXME: We ought to have a message processing loop here!!
d1bab566
SN
759
760 switch ( result )
17b35e1d
SN
761 {
762 case ERROR_INTERRUPT:
763 case ERROR_THREAD_NOT_TERMINATED:
764 break;
765 case ERROR_INVALID_THREADID:
d1bab566 766 case NO_ERROR:
f877815e 767 // thread we're waiting for just terminated
17b35e1d
SN
768 // or even does not exist any more.
769 result = NO_ERROR;
770 break;
d1bab566
SN
771 default:
772 wxFAIL_MSG(wxT("unexpected result of DosWaitThread"));
773 }
17b35e1d
SN
774 if ( IsMain() )
775 {
776 // event processing - needed if we are the main thread
777 // to give other threads a chance to do remaining GUI
778 // processing and terminate cleanly.
779 wxTheApp->HandleSockets();
780 if (wxTheApp->Pending())
781 if ( !wxTheApp->DoMessage() )
782 {
783 // WM_QUIT received: kill the thread
784 Kill();
785
786 return wxTHREAD_KILLED;
787 }
788 else
789 wxUsleep(10);
790 }
791 else
792 wxUsleep(10);
d1bab566
SN
793 } while ( result != NO_ERROR );
794#else // !wxUSE_GUI
795 // simply wait for the thread to terminate
796 //
797 // OTOH, even console apps create windows (in wxExecute, for WinSock
798 // &c), so may be use MsgWaitForMultipleObject() too here?
799 if ( ::DosWaitThread(&hThread, DCWW_WAIT) != NO_ERROR )
800 {
801 wxFAIL_MSG(wxT("unexpected result of DosWaitThread"));
802 }
d01cc696 803#endif // wxUSE_GUI/!wxUSE_GUI
d90895ac 804
d01cc696 805 if ( IsMain() )
d90895ac 806 {
6670f564 807 gs_bWaitingForThread = false;
d90895ac 808 }
d01cc696
DW
809 }
810
d1bab566
SN
811#if 0
812 // although the thread might be already in the EXITED state it might not
813 // have terminated yet and so we are not sure that it has actually
814 // terminated if the "if" above hadn't been taken
815 do
816 {
817 if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
818 {
819 wxLogLastError(wxT("GetExitCodeThread"));
820
821 rc = (ExitCode)-1;
822 }
823 } while ( (DWORD)rc == STILL_ACTIVE );
824#endif
825
826 if ( IsDetached() )
d01cc696 827 {
d1bab566
SN
828 // if the thread exits normally, this is done in WinThreadStart, but in
829 // this case it would have been too early because
830 // MsgWaitForMultipleObject() would fail if the thread handle was
831 // closed while we were waiting on it, so we must do it here
d01cc696
DW
832 delete this;
833 }
834
d01cc696
DW
835 if ( pRc )
836 *pRc = rc;
837
838 return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;
0e320a79
DW
839}
840
d90895ac 841wxThreadError wxThread::Kill()
0e320a79 842{
c5fb56c0 843 if (!IsRunning())
d90895ac
DW
844 return wxTHREAD_NOT_RUNNING;
845
d01cc696 846 ::DosKillThread(m_internal->GetHandle());
3b9e3455
DW
847 if (IsDetached())
848 {
849 delete this;
850 }
d90895ac 851 return wxTHREAD_NO_ERROR;
0e320a79
DW
852}
853
6670f564 854void wxThread::Exit(ExitCode WXUNUSED(pStatus))
0e320a79 855{
d90895ac 856 delete this;
f877815e 857 _endthread();
c5fb56c0 858 wxFAIL_MSG(wxT("Couldn't return from DosExit()!"));
0e320a79
DW
859}
860
c5fb56c0
DW
861void wxThread::SetPriority(
862 unsigned int nPrio
863)
0e320a79 864{
c5fb56c0 865 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 866
d01cc696 867 m_internal->SetPriority(nPrio);
0e320a79
DW
868}
869
d90895ac 870unsigned int wxThread::GetPriority() const
0e320a79 871{
c5fb56c0 872 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 873
d01cc696 874 return m_internal->GetPriority();
0e320a79
DW
875}
876
3b9e3455
DW
877unsigned long wxThread::GetId() const
878{
879 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
880
881 return (unsigned long)m_internal->GetId();
882}
883
d90895ac 884bool wxThread::IsRunning() const
0e320a79 885{
c5fb56c0 886 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 887
3b9e3455 888 return(m_internal->GetState() == STATE_RUNNING);
0e320a79 889}
0e320a79
DW
890
891bool wxThread::IsAlive() const
892{
c5fb56c0 893 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 894
d01cc696
DW
895 return (m_internal->GetState() == STATE_RUNNING) ||
896 (m_internal->GetState() == STATE_PAUSED);
0e320a79
DW
897}
898
d90895ac 899bool wxThread::IsPaused() const
0e320a79 900{
c5fb56c0 901 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 902
d01cc696 903 return (m_internal->GetState() == STATE_PAUSED);
0e320a79
DW
904}
905
d90895ac 906bool wxThread::TestDestroy()
0e320a79 907{
c5fb56c0 908 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 909
d01cc696 910 return m_internal->GetState() == STATE_CANCELED;
0e320a79
DW
911}
912
d90895ac
DW
913// ----------------------------------------------------------------------------
914// Automatic initialization for thread module
915// ----------------------------------------------------------------------------
0e320a79 916
d90895ac
DW
917class wxThreadModule : public wxModule
918{
0e320a79 919public:
d90895ac
DW
920 virtual bool OnInit();
921 virtual void OnExit();
0e320a79 922
d90895ac
DW
923private:
924 DECLARE_DYNAMIC_CLASS(wxThreadModule)
0e320a79
DW
925};
926
927IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
928
d90895ac
DW
929bool wxThreadModule::OnInit()
930{
43543d98 931 gs_pCritsectWaitingForGui = new wxCriticalSection();
d90895ac 932
43543d98
DW
933 gs_pCritsectGui = new wxCriticalSection();
934 gs_pCritsectGui->Enter();
d90895ac 935
6670f564
WS
936 PTIB ptib;
937 PPIB ppib;
d90895ac 938
c5fb56c0 939 ::DosGetInfoBlocks(&ptib, &ppib);
d90895ac 940
c5fb56c0 941 s_ulIdMainThread = ptib->tib_ptib2->tib2_ultid;
6670f564 942 return true;
d90895ac
DW
943}
944
945void wxThreadModule::OnExit()
946{
43543d98 947 if (gs_pCritsectGui)
d90895ac 948 {
43543d98 949 gs_pCritsectGui->Leave();
f6bcfd97 950#if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
43543d98 951 delete gs_pCritsectGui;
f6bcfd97 952#endif
43543d98 953 gs_pCritsectGui = NULL;
d90895ac
DW
954 }
955
f6bcfd97 956#if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
43543d98 957 wxDELETE(gs_pCritsectWaitingForGui);
f6bcfd97 958#endif
d90895ac
DW
959}
960
961// ----------------------------------------------------------------------------
c5fb56c0 962// Helper functions
d90895ac
DW
963// ----------------------------------------------------------------------------
964
d1bab566 965// wake up the main thread if it's in ::GetMessage()
c5fb56c0 966void WXDLLEXPORT wxWakeUpMainThread()
d90895ac 967{
8e5052fa 968#if 0
d1bab566
SN
969 if ( !::WinPostQueueMsg(wxTheApp->m_hMq, WM_NULL, 0, 0) )
970 {
971 // should never happen
972 wxLogLastError(wxT("WinPostMessage(WM_NULL)"));
973 }
8e5052fa 974#endif
d90895ac
DW
975}
976
28a75c29
SN
977void WXDLLEXPORT wxMutexGuiEnter()
978{
979 // this would dead lock everything...
980 wxASSERT_MSG( !wxThread::IsMain(),
981 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
982
983 // the order in which we enter the critical sections here is crucial!!
984
985 // set the flag telling to the main thread that we want to do some GUI
986 {
987 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
988
989 gs_nWaitingForGui++;
990 }
991
992 wxWakeUpMainThread();
993
994 // now we may block here because the main thread will soon let us in
995 // (during the next iteration of OnIdle())
996 gs_pCritsectGui->Enter();
997}
998
d90895ac
DW
999void WXDLLEXPORT wxMutexGuiLeave()
1000{
43543d98 1001 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
d90895ac
DW
1002
1003 if ( wxThread::IsMain() )
1004 {
6670f564 1005 gs_bGuiOwnedByMainThread = false;
d90895ac
DW
1006 }
1007 else
1008 {
1009 // decrement the number of waiters now
43543d98 1010 wxASSERT_MSG(gs_nWaitingForGui > 0,
d90895ac
DW
1011 wxT("calling wxMutexGuiLeave() without entering it first?") );
1012
43543d98 1013 gs_nWaitingForGui--;
d90895ac
DW
1014
1015 wxWakeUpMainThread();
1016 }
1017
43543d98 1018 gs_pCritsectGui->Leave();
d90895ac
DW
1019}
1020
1021void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
1022{
1023 wxASSERT_MSG( wxThread::IsMain(),
1024 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1025
43543d98 1026 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
d90895ac 1027
43543d98 1028 if (gs_nWaitingForGui == 0)
d90895ac
DW
1029 {
1030 // no threads are waiting for GUI - so we may acquire the lock without
1031 // any danger (but only if we don't already have it)
c5fb56c0 1032 if (!wxGuiOwnedByMainThread())
d90895ac 1033 {
43543d98 1034 gs_pCritsectGui->Enter();
d90895ac 1035
6670f564 1036 gs_bGuiOwnedByMainThread = true;
d90895ac
DW
1037 }
1038 //else: already have it, nothing to do
1039 }
1040 else
1041 {
1042 // some threads are waiting, release the GUI lock if we have it
c5fb56c0 1043 if (wxGuiOwnedByMainThread())
d90895ac
DW
1044 {
1045 wxMutexGuiLeave();
1046 }
1047 //else: some other worker thread is doing GUI
1048 }
1049}
1050
1051bool WXDLLEXPORT wxGuiOwnedByMainThread()
1052{
43543d98 1053 return gs_bGuiOwnedByMainThread;
d90895ac
DW
1054}
1055
9ed0fac8
DW
1056bool WXDLLEXPORT wxIsWaitingForThread()
1057{
43543d98 1058 return gs_bWaitingForThread;
9ed0fac8
DW
1059}
1060
d1bab566
SN
1061// ----------------------------------------------------------------------------
1062// include common implementation code
1063// ----------------------------------------------------------------------------
1064
1065#include "wx/thrimpl.cpp"
1066
0e320a79
DW
1067#endif
1068 // wxUSE_THREADS