]> git.saurik.com Git - wxWidgets.git/blame - src/os2/thread.cpp
Source cleaning.
[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
55034339 384void wxThreadInternal::OS2ThreadStart( void * pParam )
d90895ac 385{
55034339 386 DWORD dwRet;
d1bab566 387 bool bWasCancelled;
d90895ac 388
f877815e
SN
389 wxThread *pThread = (wxThread *)pParam;
390
391 // first of all, wait for the thread to be started.
392 pThread->m_critsect.Enter();
393 pThread->m_critsect.Leave();
394 // Now check whether we hadn't been cancelled already and don't
395 // start the user code at all in this case.
d1bab566
SN
396 if ( pThread->m_internal->GetState() == STATE_EXITED )
397 {
398 dwRet = (DWORD)-1;
6670f564 399 bWasCancelled = true;
d1bab566
SN
400 }
401 else // do run thread
402 {
737928c2
SN
403 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
404 unsigned long ulHab;
17b35e1d
SN
405 if (traits)
406 traits->InitializeGui(ulHab);
d1bab566 407 dwRet = (DWORD)pThread->Entry();
17b35e1d
SN
408 if (traits)
409 traits->TerminateGui(ulHab);
d01cc696 410
17b35e1d
SN
411 // enter m_critsect before changing the thread state
412 pThread->m_critsect.Enter();
d01cc696 413
17b35e1d 414 bWasCancelled = pThread->m_internal->GetState() == STATE_CANCELED;
d01cc696 415
17b35e1d
SN
416 pThread->m_internal->SetState(STATE_EXITED);
417 pThread->m_critsect.Leave();
d1bab566 418 }
c5fb56c0 419 pThread->OnExit();
d90895ac 420
d01cc696
DW
421 // if the thread was cancelled (from Delete()), then it the handle is still
422 // needed there
423 if (pThread->IsDetached() && !bWasCancelled)
424 {
425 // auto delete
43543d98 426 delete pThread;
d01cc696
DW
427 }
428 //else: the joinable threads handle will be closed when Wait() is done
f877815e 429 return;
d90895ac
DW
430}
431
d01cc696
DW
432void wxThreadInternal::SetPriority(
433 unsigned int nPriority
c5fb56c0 434)
d90895ac 435{
77ffb593 436 // translate wxWidgets priority to the PM one
d1bab566
SN
437 ULONG ulOS2_PriorityClass;
438 ULONG ulOS2_SubPriority;
43543d98 439 ULONG ulrc;
c5fb56c0 440
d01cc696 441 m_nPriority = nPriority;
d1bab566
SN
442 if (m_nPriority <= 25)
443 ulOS2_PriorityClass = PRTYC_IDLETIME;
444 else if (m_nPriority <= 50)
445 ulOS2_PriorityClass = PRTYC_REGULAR;
446 else if (m_nPriority <= 75)
447 ulOS2_PriorityClass = PRTYC_TIMECRITICAL;
c5fb56c0 448 else if (m_nPriority <= 100)
d1bab566 449 ulOS2_PriorityClass = PRTYC_FOREGROUNDSERVER;
d90895ac
DW
450 else
451 {
452 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
d1bab566 453 ulOS2_PriorityClass = PRTYC_REGULAR;
d90895ac 454 }
d1bab566 455 ulOS2_SubPriority = (ULONG) (((m_nPriority - 1) % 25 + 1) * 31.0 / 25);
c5fb56c0 456 ulrc = ::DosSetPriority( PRTYS_THREAD
d1bab566
SN
457 ,ulOS2_PriorityClass
458 ,ulOS2_SubPriority
c5fb56c0
DW
459 ,(ULONG)m_hThread
460 );
461 if (ulrc != 0)
d90895ac
DW
462 {
463 wxLogSysError(_("Can't set thread priority"));
464 }
d01cc696
DW
465}
466
6670f564
WS
467bool wxThreadInternal::Create( wxThread* pThread,
468 unsigned int uStackSize)
d01cc696 469{
6670f564 470 int tid;
17b35e1d 471
f877815e 472 if (!uStackSize)
6670f564
WS
473 uStackSize = 131072;
474
f877815e
SN
475 pThread->m_critsect.Enter();
476 tid = _beginthread(wxThreadInternal::OS2ThreadStart,
17b35e1d 477 NULL, uStackSize, pThread);
f877815e 478 if(tid == -1)
d01cc696
DW
479 {
480 wxLogSysError(_("Can't create thread"));
481
6670f564 482 return false;
d01cc696 483 }
f877815e 484 m_hThread = tid;
d01cc696
DW
485 if (m_nPriority != WXTHREAD_DEFAULT_PRIORITY)
486 {
487 SetPriority(m_nPriority);
488 }
1dfc3cda 489
6670f564 490 return true;
d90895ac
DW
491}
492
493bool wxThreadInternal::Suspend()
494{
6670f564 495 ULONG ulrc = ::DosSuspendThread(m_hThread);
d90895ac 496
c5fb56c0
DW
497 if (ulrc != 0)
498 {
499 wxLogSysError(_("Can not suspend thread %lu"), m_hThread);
6670f564 500 return false;
d90895ac 501 }
c5fb56c0 502 m_eState = STATE_PAUSED;
6670f564
WS
503
504 return true;
d90895ac
DW
505}
506
507bool wxThreadInternal::Resume()
508{
6670f564 509 ULONG ulrc = ::DosResumeThread(m_hThread);
d90895ac 510
c5fb56c0
DW
511 if (ulrc != 0)
512 {
f877815e 513 wxLogSysError(_("Can not resume thread %lu"), m_hThread);
6670f564 514 return false;
d90895ac 515 }
d1bab566
SN
516
517 // don't change the state from STATE_EXITED because it's special and means
518 // we are going to terminate without running any user code - if we did it,
519 // the codei n Delete() wouldn't work
520 if ( m_eState != STATE_EXITED )
521 {
522 m_eState = STATE_RUNNING;
523 }
524
6670f564 525 return true;
d90895ac
DW
526}
527
528// static functions
529// ----------------
530
531wxThread *wxThread::This()
532{
c5fb56c0
DW
533 wxThread* pThread = m_pThread;
534 return pThread;
d90895ac
DW
535}
536
537bool wxThread::IsMain()
538{
6670f564
WS
539 PTIB ptib;
540 PPIB ppib;
c5fb56c0
DW
541
542 ::DosGetInfoBlocks(&ptib, &ppib);
543
544 if (ptib->tib_ptib2->tib2_ultid == s_ulIdMainThread)
6670f564
WS
545 return true;
546
547 return false;
d90895ac
DW
548}
549
550#ifdef Yield
551 #undef Yield
552#endif
553
554void wxThread::Yield()
555{
d90895ac
DW
556 ::DosSleep(0);
557}
558
c5fb56c0
DW
559void wxThread::Sleep(
560 unsigned long ulMilliseconds
561)
d90895ac 562{
c5fb56c0 563 ::DosSleep(ulMilliseconds);
d90895ac
DW
564}
565
d1bab566
SN
566int wxThread::GetCPUCount()
567{
568 ULONG CPUCount;
569 APIRET ulrc;
570 ulrc = ::DosQuerySysInfo(26, 26, (void *)&CPUCount, sizeof(ULONG));
571 // QSV_NUMPROCESSORS(26) is typically not defined in header files
572
573 if (ulrc != 0)
574 CPUCount = 1;
575
576 return CPUCount;
577}
578
579unsigned long wxThread::GetCurrentId()
580{
581 PTIB ptib;
582 PPIB ppib;
583
584 ::DosGetInfoBlocks(&ptib, &ppib);
585 return (unsigned long) ptib->tib_ptib2->tib2_ultid;
586}
587
588bool wxThread::SetConcurrency(size_t level)
589{
590 wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") );
591
592 // ok only for the default one
593 if ( level == 0 )
594 return 0;
595
596 // Don't know how to realize this on OS/2.
597 return level == 1;
598}
599
d01cc696
DW
600// ctor and dtor
601// -------------
602
603wxThread::wxThread(wxThreadKind kind)
604{
605 m_internal = new wxThreadInternal();
606
607 m_isDetached = kind == wxTHREAD_DETACHED;
608}
609
610wxThread::~wxThread()
611{
612 delete m_internal;
613}
614
d90895ac
DW
615// create/start thread
616// -------------------
617
793c7f9b
DW
618wxThreadError wxThread::Create(
619 unsigned int uStackSize
620)
0e320a79 621{
d1bab566
SN
622 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
623
793c7f9b 624 if ( !m_internal->Create(this, uStackSize) )
d90895ac
DW
625 return wxTHREAD_NO_RESOURCE;
626
0e320a79
DW
627 return wxTHREAD_NO_ERROR;
628}
629
d90895ac 630wxThreadError wxThread::Run()
0e320a79 631{
c5fb56c0 632 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 633
d01cc696 634 if ( m_internal->GetState() != STATE_NEW )
d90895ac
DW
635 {
636 // actually, it may be almost any state at all, not only STATE_RUNNING
637 return wxTHREAD_RUNNING;
638 }
d90895ac 639 return Resume();
0e320a79
DW
640}
641
d90895ac
DW
642// suspend/resume thread
643// ---------------------
644
0e320a79
DW
645wxThreadError wxThread::Pause()
646{
c5fb56c0 647 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 648
d01cc696 649 return m_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
0e320a79
DW
650}
651
652wxThreadError wxThread::Resume()
653{
f877815e
SN
654 if (m_internal->GetState() == STATE_NEW)
655 {
17b35e1d 656 m_internal->SetState(STATE_RUNNING);
f877815e 657 m_critsect.Leave();
17b35e1d 658 return wxTHREAD_NO_ERROR;
f877815e
SN
659 }
660
c5fb56c0 661 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
0e320a79 662
d01cc696 663 return m_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
0e320a79
DW
664}
665
d90895ac
DW
666// stopping thread
667// ---------------
668
d01cc696 669wxThread::ExitCode wxThread::Wait()
0e320a79 670{
d01cc696
DW
671 // although under Windows we can wait for any thread, it's an error to
672 // wait for a detached one in wxWin API
673 wxCHECK_MSG( !IsDetached(), (ExitCode)-1,
674 _T("can't wait for detached thread") );
675 ExitCode rc = (ExitCode)-1;
676 (void)Delete(&rc);
d01cc696
DW
677 return(rc);
678}
679
680wxThreadError wxThread::Delete(ExitCode *pRc)
681{
682 ExitCode rc = 0;
d90895ac
DW
683
684 // Delete() is always safe to call, so consider all possible states
d1bab566
SN
685
686 // we might need to resume the thread, but we might also not need to cancel
687 // it if it doesn't run yet
6670f564
WS
688 bool shouldResume = false,
689 shouldCancel = true,
690 isRunning = false;
d1bab566
SN
691
692 // check if the thread already started to run
693 {
694 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
695
696 if ( m_internal->GetState() == STATE_NEW )
697 {
698 // WinThreadStart() will see it and terminate immediately, no need
699 // to cancel the thread - but we still need to resume it to let it
700 // run
701 m_internal->SetState(STATE_EXITED);
702
703 Resume(); // it knows about STATE_EXITED special case
704
6670f564
WS
705 shouldCancel = false;
706 isRunning = true;
d1bab566 707
6670f564 708 // shouldResume is correctly set to false here
d1bab566
SN
709 }
710 else
711 {
712 shouldResume = IsPaused();
713 }
714 }
715
716 // resume the thread if it is paused
717 if ( shouldResume )
d90895ac
DW
718 Resume();
719
6670f564 720 TID hThread = m_internal->GetHandle();
d01cc696 721
d1bab566 722 if ( isRunning || IsRunning())
d90895ac 723 {
c5fb56c0 724 if (IsMain())
d90895ac
DW
725 {
726 // set flag for wxIsWaitingForThread()
6670f564 727 gs_bWaitingForThread = true;
17b35e1d 728 }
d90895ac 729
d01cc696 730 // ask the thread to terminate
d1bab566 731 if ( shouldCancel )
d90895ac 732 {
d01cc696 733 wxCriticalSectionLocker lock(m_critsect);
d1bab566 734
d01cc696 735 m_internal->Cancel();
d90895ac
DW
736 }
737
17b35e1d 738#if 0
d1bab566
SN
739 // we can't just wait for the thread to terminate because it might be
740 // calling some GUI functions and so it will never terminate before we
741 // process the Windows messages that result from these functions
742 DWORD result = 0; // suppress warnings from broken compilers
743 do
d01cc696 744 {
d1bab566
SN
745 if ( IsMain() )
746 {
747 // give the thread we're waiting for chance to do the GUI call
748 // it might be in
749 if ( (gs_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
750 {
751 wxMutexGuiLeave();
752 }
753 }
754
f877815e 755 result = ::DosWaitThread(&hThread, DCWW_NOWAIT);
17b35e1d 756 // FIXME: We ought to have a message processing loop here!!
d1bab566
SN
757
758 switch ( result )
17b35e1d
SN
759 {
760 case ERROR_INTERRUPT:
761 case ERROR_THREAD_NOT_TERMINATED:
762 break;
763 case ERROR_INVALID_THREADID:
d1bab566 764 case NO_ERROR:
f877815e 765 // thread we're waiting for just terminated
17b35e1d
SN
766 // or even does not exist any more.
767 result = NO_ERROR;
768 break;
d1bab566
SN
769 default:
770 wxFAIL_MSG(wxT("unexpected result of DosWaitThread"));
771 }
17b35e1d
SN
772 if ( IsMain() )
773 {
774 // event processing - needed if we are the main thread
775 // to give other threads a chance to do remaining GUI
776 // processing and terminate cleanly.
777 wxTheApp->HandleSockets();
778 if (wxTheApp->Pending())
779 if ( !wxTheApp->DoMessage() )
780 {
781 // WM_QUIT received: kill the thread
782 Kill();
783
784 return wxTHREAD_KILLED;
785 }
786 else
787 wxUsleep(10);
788 }
789 else
790 wxUsleep(10);
d1bab566
SN
791 } while ( result != NO_ERROR );
792#else // !wxUSE_GUI
793 // simply wait for the thread to terminate
794 //
795 // OTOH, even console apps create windows (in wxExecute, for WinSock
796 // &c), so may be use MsgWaitForMultipleObject() too here?
797 if ( ::DosWaitThread(&hThread, DCWW_WAIT) != NO_ERROR )
798 {
799 wxFAIL_MSG(wxT("unexpected result of DosWaitThread"));
800 }
d01cc696 801#endif // wxUSE_GUI/!wxUSE_GUI
d90895ac 802
d01cc696 803 if ( IsMain() )
d90895ac 804 {
6670f564 805 gs_bWaitingForThread = false;
d90895ac 806 }
d01cc696
DW
807 }
808
d1bab566
SN
809#if 0
810 // although the thread might be already in the EXITED state it might not
811 // have terminated yet and so we are not sure that it has actually
812 // terminated if the "if" above hadn't been taken
813 do
814 {
815 if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
816 {
817 wxLogLastError(wxT("GetExitCodeThread"));
818
819 rc = (ExitCode)-1;
820 }
821 } while ( (DWORD)rc == STILL_ACTIVE );
822#endif
823
824 if ( IsDetached() )
d01cc696 825 {
d1bab566
SN
826 // if the thread exits normally, this is done in WinThreadStart, but in
827 // this case it would have been too early because
828 // MsgWaitForMultipleObject() would fail if the thread handle was
829 // closed while we were waiting on it, so we must do it here
d01cc696
DW
830 delete this;
831 }
832
d01cc696
DW
833 if ( pRc )
834 *pRc = rc;
835
836 return rc == (ExitCode)-1 ? wxTHREAD_MISC_ERROR : wxTHREAD_NO_ERROR;
0e320a79
DW
837}
838
d90895ac 839wxThreadError wxThread::Kill()
0e320a79 840{
c5fb56c0 841 if (!IsRunning())
d90895ac
DW
842 return wxTHREAD_NOT_RUNNING;
843
d01cc696 844 ::DosKillThread(m_internal->GetHandle());
3b9e3455
DW
845 if (IsDetached())
846 {
847 delete this;
848 }
d90895ac 849 return wxTHREAD_NO_ERROR;
0e320a79
DW
850}
851
6670f564 852void wxThread::Exit(ExitCode WXUNUSED(pStatus))
0e320a79 853{
d90895ac 854 delete this;
f877815e 855 _endthread();
c5fb56c0 856 wxFAIL_MSG(wxT("Couldn't return from DosExit()!"));
0e320a79
DW
857}
858
c5fb56c0
DW
859void wxThread::SetPriority(
860 unsigned int nPrio
861)
0e320a79 862{
c5fb56c0 863 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 864
d01cc696 865 m_internal->SetPriority(nPrio);
0e320a79
DW
866}
867
d90895ac 868unsigned int wxThread::GetPriority() const
0e320a79 869{
c5fb56c0 870 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 871
d01cc696 872 return m_internal->GetPriority();
0e320a79
DW
873}
874
3b9e3455
DW
875unsigned long wxThread::GetId() const
876{
877 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); // const_cast
878
879 return (unsigned long)m_internal->GetId();
880}
881
d90895ac 882bool wxThread::IsRunning() const
0e320a79 883{
c5fb56c0 884 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 885
3b9e3455 886 return(m_internal->GetState() == STATE_RUNNING);
0e320a79 887}
0e320a79
DW
888
889bool wxThread::IsAlive() const
890{
c5fb56c0 891 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 892
d01cc696
DW
893 return (m_internal->GetState() == STATE_RUNNING) ||
894 (m_internal->GetState() == STATE_PAUSED);
0e320a79
DW
895}
896
d90895ac 897bool wxThread::IsPaused() const
0e320a79 898{
c5fb56c0 899 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 900
d01cc696 901 return (m_internal->GetState() == STATE_PAUSED);
0e320a79
DW
902}
903
d90895ac 904bool wxThread::TestDestroy()
0e320a79 905{
c5fb56c0 906 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 907
d01cc696 908 return m_internal->GetState() == STATE_CANCELED;
0e320a79
DW
909}
910
d90895ac
DW
911// ----------------------------------------------------------------------------
912// Automatic initialization for thread module
913// ----------------------------------------------------------------------------
0e320a79 914
d90895ac
DW
915class wxThreadModule : public wxModule
916{
0e320a79 917public:
d90895ac
DW
918 virtual bool OnInit();
919 virtual void OnExit();
0e320a79 920
d90895ac
DW
921private:
922 DECLARE_DYNAMIC_CLASS(wxThreadModule)
0e320a79
DW
923};
924
925IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
926
d90895ac
DW
927bool wxThreadModule::OnInit()
928{
43543d98 929 gs_pCritsectWaitingForGui = new wxCriticalSection();
d90895ac 930
43543d98
DW
931 gs_pCritsectGui = new wxCriticalSection();
932 gs_pCritsectGui->Enter();
d90895ac 933
6670f564
WS
934 PTIB ptib;
935 PPIB ppib;
d90895ac 936
c5fb56c0 937 ::DosGetInfoBlocks(&ptib, &ppib);
d90895ac 938
c5fb56c0 939 s_ulIdMainThread = ptib->tib_ptib2->tib2_ultid;
6670f564 940 return true;
d90895ac
DW
941}
942
943void wxThreadModule::OnExit()
944{
43543d98 945 if (gs_pCritsectGui)
d90895ac 946 {
43543d98 947 gs_pCritsectGui->Leave();
f6bcfd97 948#if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
43543d98 949 delete gs_pCritsectGui;
f6bcfd97 950#endif
43543d98 951 gs_pCritsectGui = NULL;
d90895ac
DW
952 }
953
f6bcfd97 954#if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
43543d98 955 wxDELETE(gs_pCritsectWaitingForGui);
f6bcfd97 956#endif
d90895ac
DW
957}
958
959// ----------------------------------------------------------------------------
c5fb56c0 960// Helper functions
d90895ac
DW
961// ----------------------------------------------------------------------------
962
d1bab566 963// wake up the main thread if it's in ::GetMessage()
c5fb56c0 964void WXDLLEXPORT wxWakeUpMainThread()
d90895ac 965{
8e5052fa 966#if 0
d1bab566
SN
967 if ( !::WinPostQueueMsg(wxTheApp->m_hMq, WM_NULL, 0, 0) )
968 {
969 // should never happen
970 wxLogLastError(wxT("WinPostMessage(WM_NULL)"));
971 }
8e5052fa 972#endif
d90895ac
DW
973}
974
28a75c29
SN
975void WXDLLEXPORT wxMutexGuiEnter()
976{
977 // this would dead lock everything...
978 wxASSERT_MSG( !wxThread::IsMain(),
979 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
980
981 // the order in which we enter the critical sections here is crucial!!
982
983 // set the flag telling to the main thread that we want to do some GUI
984 {
985 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
986
987 gs_nWaitingForGui++;
988 }
989
990 wxWakeUpMainThread();
991
992 // now we may block here because the main thread will soon let us in
993 // (during the next iteration of OnIdle())
994 gs_pCritsectGui->Enter();
995}
996
d90895ac
DW
997void WXDLLEXPORT wxMutexGuiLeave()
998{
43543d98 999 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
d90895ac
DW
1000
1001 if ( wxThread::IsMain() )
1002 {
6670f564 1003 gs_bGuiOwnedByMainThread = false;
d90895ac
DW
1004 }
1005 else
1006 {
1007 // decrement the number of waiters now
43543d98 1008 wxASSERT_MSG(gs_nWaitingForGui > 0,
d90895ac
DW
1009 wxT("calling wxMutexGuiLeave() without entering it first?") );
1010
43543d98 1011 gs_nWaitingForGui--;
d90895ac
DW
1012
1013 wxWakeUpMainThread();
1014 }
1015
43543d98 1016 gs_pCritsectGui->Leave();
d90895ac
DW
1017}
1018
1019void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
1020{
1021 wxASSERT_MSG( wxThread::IsMain(),
1022 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1023
43543d98 1024 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
d90895ac 1025
43543d98 1026 if (gs_nWaitingForGui == 0)
d90895ac
DW
1027 {
1028 // no threads are waiting for GUI - so we may acquire the lock without
1029 // any danger (but only if we don't already have it)
c5fb56c0 1030 if (!wxGuiOwnedByMainThread())
d90895ac 1031 {
43543d98 1032 gs_pCritsectGui->Enter();
d90895ac 1033
6670f564 1034 gs_bGuiOwnedByMainThread = true;
d90895ac
DW
1035 }
1036 //else: already have it, nothing to do
1037 }
1038 else
1039 {
1040 // some threads are waiting, release the GUI lock if we have it
c5fb56c0 1041 if (wxGuiOwnedByMainThread())
d90895ac
DW
1042 {
1043 wxMutexGuiLeave();
1044 }
1045 //else: some other worker thread is doing GUI
1046 }
1047}
1048
1049bool WXDLLEXPORT wxGuiOwnedByMainThread()
1050{
43543d98 1051 return gs_bGuiOwnedByMainThread;
d90895ac
DW
1052}
1053
9ed0fac8
DW
1054bool WXDLLEXPORT wxIsWaitingForThread()
1055{
43543d98 1056 return gs_bWaitingForThread;
9ed0fac8
DW
1057}
1058
d1bab566
SN
1059// ----------------------------------------------------------------------------
1060// include common implementation code
1061// ----------------------------------------------------------------------------
1062
1063#include "wx/thrimpl.cpp"
1064
0e320a79
DW
1065#endif
1066 // wxUSE_THREADS