]> git.saurik.com Git - wxWidgets.git/blame - src/os2/thread.cpp
wxMessageBox off the main thread lost result code.
[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 6// Created: 04/22/98
d1bab566 7// Copyright: (c) Stefan Neis (2003)
65571936 8// Licence: wxWindows licence
0e320a79
DW
9/////////////////////////////////////////////////////////////////////////////
10
d90895ac
DW
11// ----------------------------------------------------------------------------
12// headers
13// ----------------------------------------------------------------------------
0e320a79 14
d90895ac
DW
15// For compilers that support precompilation, includes "wx.h".
16#include "wx/wxprec.h"
0e320a79
DW
17
18#if wxUSE_THREADS
19
88a7a4e1
WS
20#include "wx/thread.h"
21
22#ifndef WX_PRECOMP
23 #include "wx/intl.h"
e4db172a 24 #include "wx/log.h"
670f9935 25 #include "wx/app.h"
02761f6c 26 #include "wx/module.h"
88a7a4e1 27#endif //WX_PRECOMP
d90895ac 28
737928c2 29#include "wx/apptrait.h"
19193a2c 30#include "wx/utils.h"
88a7a4e1
WS
31
32#include <stdio.h>
d90895ac 33
c5fb56c0
DW
34#define INCL_DOSSEMAPHORES
35#define INCL_DOSPROCESS
d1bab566 36#define INCL_DOSMISC
c5fb56c0
DW
37#define INCL_ERRORS
38#include <os2.h>
2b5f62a0 39#ifndef __EMX__
c5fb56c0 40#include <bseerr.h>
2b5f62a0 41#endif
d90895ac
DW
42// the possible states of the thread ("=>" shows all possible transitions from
43// this state)
44enum wxThreadState
45{
46 STATE_NEW, // didn't start execution yet (=> RUNNING)
47 STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
48 STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
49 STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
50 STATE_EXITED // thread is terminating
0e320a79
DW
51};
52
d90895ac 53// ----------------------------------------------------------------------------
d1bab566 54// this module's globals
d90895ac 55// ----------------------------------------------------------------------------
0e320a79 56
d90895ac
DW
57// id of the main thread - the one which can call GUI functions without first
58// calling wxMutexGuiEnter()
f9226383 59wxThreadIdType wxThread::ms_idMainThread = 0;
c5fb56c0
DW
60wxMutex* p_wxMainMutex;
61
62// OS2 substitute for Tls pointer the current parent thread object
77ffb593 63wxThread* m_pThread; // pointer to the wxWidgets thread object
d90895ac 64
6670f564
WS
65// if it's false, some secondary thread is holding the GUI lock
66static bool gs_bGuiOwnedByMainThread = true;
0e320a79 67
d90895ac
DW
68// critical section which controls access to all GUI functions: any secondary
69// thread (i.e. except the main one) must enter this crit section before doing
70// any GUI calls
43543d98 71static wxCriticalSection *gs_pCritsectGui = NULL;
d90895ac
DW
72
73// critical section which protects s_nWaitingForGui variable
43543d98 74static wxCriticalSection *gs_pCritsectWaitingForGui = NULL;
d90895ac
DW
75
76// number of threads waiting for GUI in wxMutexGuiEnter()
43543d98 77static size_t gs_nWaitingForGui = 0;
d90895ac
DW
78
79// are we waiting for a thread termination?
6670f564 80static bool gs_bWaitingForThread = false;
d90895ac
DW
81
82// ============================================================================
d1bab566 83// OS/2 implementation of thread and related classes
d90895ac
DW
84// ============================================================================
85
86// ----------------------------------------------------------------------------
87// wxMutex implementation
88// ----------------------------------------------------------------------------
89class wxMutexInternal
90{
0e320a79 91public:
d1bab566
SN
92 wxMutexInternal(wxMutexType mutexType);
93 ~wxMutexInternal();
94
95 bool IsOk() const { return m_vMutex != NULL; }
96
97 wxMutexError Lock() { return LockTimeout(SEM_INDEFINITE_WAIT); }
ee864b6d
SN
98 wxMutexError Lock(unsigned long ms) { return LockTimeout(ms); }
99 wxMutexError TryLock();
d1bab566
SN
100 wxMutexError Unlock();
101
102private:
103 wxMutexError LockTimeout(ULONG ulMilliseconds);
c5fb56c0 104 HMTX m_vMutex;
0e320a79
DW
105};
106
d1bab566
SN
107// all mutexes are "pseudo-"recursive under OS2 so we don't use mutexType
108// (Calls to DosRequestMutexSem and DosReleaseMutexSem can be nested, but
109// the request count for a semaphore cannot exceed 65535. If an attempt is
110// made to exceed this number, ERROR_TOO_MANY_SEM_REQUESTS is returned.)
6670f564 111wxMutexInternal::wxMutexInternal(wxMutexType WXUNUSED(eMutexType))
0e320a79 112{
6670f564 113 APIRET ulrc = ::DosCreateMutexSem(NULL, &m_vMutex, 0L, FALSE);
c5fb56c0 114 if (ulrc != 0)
d90895ac 115 {
4c51a665 116 wxLogSysError(_("Cannot create mutex."));
d1bab566 117 m_vMutex = NULL;
d90895ac 118 }
0e320a79
DW
119}
120
d1bab566 121wxMutexInternal::~wxMutexInternal()
0e320a79 122{
d1bab566
SN
123 if (m_vMutex)
124 {
125 if (::DosCloseMutexSem(m_vMutex))
43b2d5e7 126 {
9a83f860 127 wxLogLastError(wxT("DosCloseMutexSem(mutex)"));
43b2d5e7 128 }
d1bab566 129 }
0e320a79
DW
130}
131
ee864b6d
SN
132wxMutexError wxMutexInternal::TryLock()
133{
134 const wxMutexError rc = LockTimeout( SEM_IMMEDIATE_RETURN );
135
136 // we have a special return code for timeout in this case
137 return rc == wxMUTEX_TIMEOUT ? wxMUTEX_BUSY : rc;
138}
139
d1bab566 140wxMutexError wxMutexInternal::LockTimeout(ULONG ulMilliseconds)
0e320a79 141{
c5fb56c0
DW
142 APIRET ulrc;
143
d1bab566 144 ulrc = ::DosRequestMutexSem(m_vMutex, ulMilliseconds);
d90895ac 145
c5fb56c0 146 switch (ulrc)
d90895ac 147 {
d1bab566 148 case ERROR_TIMEOUT:
ee864b6d 149 return wxMUTEX_TIMEOUT;
c5fb56c0 150 case ERROR_TOO_MANY_SEM_REQUESTS:
d90895ac
DW
151 return wxMUTEX_BUSY;
152
c5fb56c0 153 case NO_ERROR:
d90895ac
DW
154 // ok
155 break;
156
c5fb56c0
DW
157 case ERROR_INVALID_HANDLE:
158 case ERROR_INTERRUPT:
159 case ERROR_SEM_OWNER_DIED:
d90895ac
DW
160 wxLogSysError(_("Couldn't acquire a mutex lock"));
161 return wxMUTEX_MISC_ERROR;
162
d90895ac
DW
163 default:
164 wxFAIL_MSG(wxT("impossible return value in wxMutex::Lock"));
d1bab566
SN
165 return wxMUTEX_MISC_ERROR;
166 }
0e320a79
DW
167 return wxMUTEX_NO_ERROR;
168}
169
d1bab566 170wxMutexError wxMutexInternal::Unlock()
0e320a79 171{
c5fb56c0
DW
172 APIRET ulrc;
173
d1bab566 174 ulrc = ::DosReleaseMutexSem(m_vMutex);
c5fb56c0 175 if (ulrc != 0)
d90895ac
DW
176 {
177 wxLogSysError(_("Couldn't release a mutex"));
178 return wxMUTEX_MISC_ERROR;
179 }
0e320a79
DW
180 return wxMUTEX_NO_ERROR;
181}
182
d1bab566
SN
183// --------------------------------------------------------------------------
184// wxSemaphore
185// --------------------------------------------------------------------------
d90895ac 186
d1bab566
SN
187// a trivial wrapper around OS2 event semaphore
188class wxSemaphoreInternal
d90895ac 189{
0e320a79 190public:
d1bab566
SN
191 wxSemaphoreInternal(int initialcount, int maxcount);
192 ~wxSemaphoreInternal();
d01cc696 193
d1bab566 194 bool IsOk() const { return m_vEvent != NULL; }
d01cc696 195
d1bab566
SN
196 wxSemaError Wait() { return WaitTimeout(SEM_INDEFINITE_WAIT); }
197 wxSemaError TryWait() { return WaitTimeout(SEM_IMMEDIATE_RETURN); }
198 wxSemaError WaitTimeout(unsigned long milliseconds);
d01cc696 199
d1bab566 200 wxSemaError Post();
d01cc696 201
d1bab566
SN
202private:
203 HEV m_vEvent;
204 HMTX m_vMutex;
205 int m_count;
206 int m_maxcount;
0e320a79
DW
207};
208
d1bab566 209wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
0e320a79 210{
d1bab566
SN
211 APIRET ulrc;
212 if ( maxcount == 0 )
d90895ac 213 {
d1bab566
SN
214 // make it practically infinite
215 maxcount = INT_MAX;
d90895ac 216 }
0e320a79 217
d1bab566
SN
218 m_count = initialcount;
219 m_maxcount = maxcount;
220 ulrc = ::DosCreateMutexSem(NULL, &m_vMutex, 0L, FALSE);
221 if (ulrc != 0)
47df2b8c 222 {
9a83f860 223 wxLogLastError(wxT("DosCreateMutexSem()"));
d1bab566
SN
224 m_vMutex = NULL;
225 m_vEvent = NULL;
226 return;
47df2b8c 227 }
d1bab566
SN
228 ulrc = ::DosCreateEventSem(NULL, &m_vEvent, 0L, FALSE);
229 if ( ulrc != 0)
47df2b8c 230 {
9a83f860 231 wxLogLastError(wxT("DosCreateEventSem()"));
d1bab566
SN
232 ::DosCloseMutexSem(m_vMutex);
233 m_vMutex = NULL;
234 m_vEvent = NULL;
47df2b8c 235 }
d1bab566
SN
236 if (initialcount)
237 ::DosPostEventSem(m_vEvent);
0e320a79
DW
238}
239
d1bab566 240wxSemaphoreInternal::~wxSemaphoreInternal()
0e320a79 241{
d1bab566 242 if ( m_vEvent )
d90895ac 243 {
d1bab566 244 if ( ::DosCloseEventSem(m_vEvent) )
d90895ac 245 {
9a83f860 246 wxLogLastError(wxT("DosCloseEventSem(semaphore)"));
d90895ac 247 }
d1bab566
SN
248 if ( ::DosCloseMutexSem(m_vMutex) )
249 {
9a83f860 250 wxLogLastError(wxT("DosCloseMutexSem(semaphore)"));
d1bab566
SN
251 }
252 else
253 m_vEvent = NULL;
47df2b8c 254 }
0e320a79
DW
255}
256
d1bab566 257wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long ulMilliseconds)
892b89f3 258{
d1bab566
SN
259 APIRET ulrc;
260 do {
261 ulrc = ::DosWaitEventSem(m_vEvent, ulMilliseconds );
262 switch ( ulrc )
263 {
264 case NO_ERROR:
265 break;
266
267 case ERROR_TIMEOUT:
268 if (ulMilliseconds == SEM_IMMEDIATE_RETURN)
269 return wxSEMA_BUSY;
270 else
271 return wxSEMA_TIMEOUT;
272
273 default:
9a83f860 274 wxLogLastError(wxT("DosWaitEventSem(semaphore)"));
d1bab566
SN
275 return wxSEMA_MISC_ERROR;
276 }
277 ulrc = :: DosRequestMutexSem(m_vMutex, ulMilliseconds);
278 switch ( ulrc )
279 {
280 case NO_ERROR:
281 // ok
282 break;
283
284 case ERROR_TIMEOUT:
285 case ERROR_TOO_MANY_SEM_REQUESTS:
286 if (ulMilliseconds == SEM_IMMEDIATE_RETURN)
287 return wxSEMA_BUSY;
288 else
289 return wxSEMA_TIMEOUT;
290
291 default:
292 wxFAIL_MSG(wxT("DosRequestMutexSem(mutex)"));
293 return wxSEMA_MISC_ERROR;
294 }
295 bool OK = false;
296 if (m_count > 0)
297 {
298 m_count--;
299 OK = true;
300 }
301 else
302 {
303 ULONG ulPostCount;
304 ::DosResetEventSem(m_vEvent, &ulPostCount);
305 }
306 ::DosReleaseMutexSem(m_vMutex);
307 if (OK)
308 return wxSEMA_NO_ERROR;
309 } while (ulMilliseconds == SEM_INDEFINITE_WAIT);
310
311 if (ulMilliseconds == SEM_IMMEDIATE_RETURN)
312 return wxSEMA_BUSY;
313 return wxSEMA_TIMEOUT;
892b89f3
DW
314}
315
d1bab566 316wxSemaError wxSemaphoreInternal::Post()
892b89f3 317{
d1bab566
SN
318 APIRET ulrc;
319 ulrc = ::DosRequestMutexSem(m_vMutex, SEM_INDEFINITE_WAIT);
320 if (ulrc != NO_ERROR)
321 return wxSEMA_MISC_ERROR;
322 bool OK = false;
323 if (m_count < m_maxcount)
324 {
325 m_count++;
326 ulrc = ::DosPostEventSem(m_vEvent);
327 OK = true;
328 }
329 ::DosReleaseMutexSem(m_vMutex);
330 if (!OK)
331 return wxSEMA_OVERFLOW;
332 if ( ulrc != NO_ERROR && ulrc != ERROR_ALREADY_POSTED )
333 {
9a83f860 334 wxLogLastError(wxT("DosPostEventSem(semaphore)"));
892b89f3 335
d1bab566
SN
336 return wxSEMA_MISC_ERROR;
337 }
892b89f3 338
d1bab566 339 return wxSEMA_NO_ERROR;
892b89f3
DW
340}
341
d90895ac
DW
342// ----------------------------------------------------------------------------
343// wxThread implementation
344// ----------------------------------------------------------------------------
345
346// wxThreadInternal class
347// ----------------------
348
349class wxThreadInternal
350{
351public:
c5fb56c0 352 inline wxThreadInternal()
d90895ac
DW
353 {
354 m_hThread = 0;
c5fb56c0 355 m_eState = STATE_NEW;
90e95e61 356 m_nPriority = wxPRIORITY_DEFAULT;
d90895ac
DW
357 }
358
d01cc696
DW
359 ~wxThreadInternal()
360 {
d1bab566 361 m_hThread = 0;
d01cc696
DW
362 }
363
d90895ac 364 // create a new (suspended) thread (for the given thread object)
793c7f9b
DW
365 bool Create( wxThread* pThread
366 ,unsigned int uStackSize
367 );
d90895ac
DW
368
369 // suspend/resume/terminate
370 bool Suspend();
371 bool Resume();
c5fb56c0 372 inline void Cancel() { m_eState = STATE_CANCELED; }
d90895ac
DW
373
374 // thread state
c5fb56c0
DW
375 inline void SetState(wxThreadState eState) { m_eState = eState; }
376 inline wxThreadState GetState() const { return m_eState; }
d90895ac
DW
377
378 // thread priority
d01cc696 379 void SetPriority(unsigned int nPriority);
c5fb56c0 380 inline unsigned int GetPriority() const { return m_nPriority; }
d90895ac
DW
381
382 // thread handle and id
c5fb56c0
DW
383 inline TID GetHandle() const { return m_hThread; }
384 TID GetId() const { return m_hThread; }
d90895ac
DW
385
386 // thread function
f877815e 387 static void OS2ThreadStart(void* pParam);
d90895ac
DW
388
389private:
c5fb56c0
DW
390 // Threads in OS/2 have only an ID, so m_hThread is both it's handle and ID
391 // PM also has no real Tls mechanism to index pointers by so we'll just
77ffb593 392 // keep track of the wxWidgets parent object here.
c5fb56c0
DW
393 TID m_hThread; // handle and ID of the thread
394 wxThreadState m_eState; // state, see wxThreadState enum
395 unsigned int m_nPriority; // thread priority in "wx" units
d90895ac
DW
396};
397
55034339 398void wxThreadInternal::OS2ThreadStart( void * pParam )
d90895ac 399{
55034339 400 DWORD dwRet;
d1bab566 401 bool bWasCancelled;
d90895ac 402
f877815e
SN
403 wxThread *pThread = (wxThread *)pParam;
404
405 // first of all, wait for the thread to be started.
406 pThread->m_critsect.Enter();
407 pThread->m_critsect.Leave();
408 // Now check whether we hadn't been cancelled already and don't
409 // start the user code at all in this case.
d1bab566
SN
410 if ( pThread->m_internal->GetState() == STATE_EXITED )
411 {
412 dwRet = (DWORD)-1;
6670f564 413 bWasCancelled = true;
d1bab566
SN
414 }
415 else // do run thread
416 {
737928c2
SN
417 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
418 unsigned long ulHab;
17b35e1d
SN
419 if (traits)
420 traits->InitializeGui(ulHab);
52784696 421 dwRet = (DWORD)pThread->CallEntry();
17b35e1d
SN
422 if (traits)
423 traits->TerminateGui(ulHab);
d01cc696 424
17b35e1d
SN
425 // enter m_critsect before changing the thread state
426 pThread->m_critsect.Enter();
d01cc696 427
17b35e1d 428 bWasCancelled = pThread->m_internal->GetState() == STATE_CANCELED;
d01cc696 429
17b35e1d
SN
430 pThread->m_internal->SetState(STATE_EXITED);
431 pThread->m_critsect.Leave();
d1bab566 432 }
c5fb56c0 433 pThread->OnExit();
d90895ac 434
d01cc696
DW
435 // if the thread was cancelled (from Delete()), then it the handle is still
436 // needed there
437 if (pThread->IsDetached() && !bWasCancelled)
438 {
439 // auto delete
43543d98 440 delete pThread;
d01cc696
DW
441 }
442 //else: the joinable threads handle will be closed when Wait() is done
f877815e 443 return;
d90895ac
DW
444}
445
d01cc696
DW
446void wxThreadInternal::SetPriority(
447 unsigned int nPriority
c5fb56c0 448)
d90895ac 449{
77ffb593 450 // translate wxWidgets priority to the PM one
d1bab566
SN
451 ULONG ulOS2_PriorityClass;
452 ULONG ulOS2_SubPriority;
43543d98 453 ULONG ulrc;
c5fb56c0 454
d01cc696 455 m_nPriority = nPriority;
d1bab566
SN
456 if (m_nPriority <= 25)
457 ulOS2_PriorityClass = PRTYC_IDLETIME;
458 else if (m_nPriority <= 50)
459 ulOS2_PriorityClass = PRTYC_REGULAR;
460 else if (m_nPriority <= 75)
461 ulOS2_PriorityClass = PRTYC_TIMECRITICAL;
c5fb56c0 462 else if (m_nPriority <= 100)
d1bab566 463 ulOS2_PriorityClass = PRTYC_FOREGROUNDSERVER;
d90895ac
DW
464 else
465 {
466 wxFAIL_MSG(wxT("invalid value of thread priority parameter"));
d1bab566 467 ulOS2_PriorityClass = PRTYC_REGULAR;
d90895ac 468 }
d1bab566 469 ulOS2_SubPriority = (ULONG) (((m_nPriority - 1) % 25 + 1) * 31.0 / 25);
c5fb56c0 470 ulrc = ::DosSetPriority( PRTYS_THREAD
d1bab566
SN
471 ,ulOS2_PriorityClass
472 ,ulOS2_SubPriority
c5fb56c0
DW
473 ,(ULONG)m_hThread
474 );
475 if (ulrc != 0)
d90895ac
DW
476 {
477 wxLogSysError(_("Can't set thread priority"));
478 }
d01cc696
DW
479}
480
6670f564
WS
481bool wxThreadInternal::Create( wxThread* pThread,
482 unsigned int uStackSize)
d01cc696 483{
6670f564 484 int tid;
17b35e1d 485
f877815e 486 if (!uStackSize)
6670f564
WS
487 uStackSize = 131072;
488
f877815e
SN
489 pThread->m_critsect.Enter();
490 tid = _beginthread(wxThreadInternal::OS2ThreadStart,
17b35e1d 491 NULL, uStackSize, pThread);
f877815e 492 if(tid == -1)
d01cc696
DW
493 {
494 wxLogSysError(_("Can't create thread"));
495
6670f564 496 return false;
d01cc696 497 }
f877815e 498 m_hThread = tid;
90e95e61 499 if (m_nPriority != wxPRIORITY_DEFAULT)
d01cc696
DW
500 {
501 SetPriority(m_nPriority);
502 }
1dfc3cda 503
6670f564 504 return true;
d90895ac
DW
505}
506
507bool wxThreadInternal::Suspend()
508{
6670f564 509 ULONG ulrc = ::DosSuspendThread(m_hThread);
d90895ac 510
c5fb56c0
DW
511 if (ulrc != 0)
512 {
4c51a665 513 wxLogSysError(_("Cannot suspend thread %lu"), m_hThread);
6670f564 514 return false;
d90895ac 515 }
c5fb56c0 516 m_eState = STATE_PAUSED;
6670f564
WS
517
518 return true;
d90895ac
DW
519}
520
521bool wxThreadInternal::Resume()
522{
6670f564 523 ULONG ulrc = ::DosResumeThread(m_hThread);
d90895ac 524
c5fb56c0
DW
525 if (ulrc != 0)
526 {
4c51a665 527 wxLogSysError(_("Cannot resume thread %lu"), m_hThread);
6670f564 528 return false;
d90895ac 529 }
d1bab566
SN
530
531 // don't change the state from STATE_EXITED because it's special and means
532 // we are going to terminate without running any user code - if we did it,
533 // the codei n Delete() wouldn't work
534 if ( m_eState != STATE_EXITED )
535 {
536 m_eState = STATE_RUNNING;
537 }
538
6670f564 539 return true;
d90895ac
DW
540}
541
542// static functions
543// ----------------
544
545wxThread *wxThread::This()
546{
c5fb56c0
DW
547 wxThread* pThread = m_pThread;
548 return pThread;
d90895ac
DW
549}
550
d90895ac
DW
551#ifdef Yield
552 #undef Yield
553#endif
554
555void wxThread::Yield()
556{
d90895ac
DW
557 ::DosSleep(0);
558}
559
d1bab566
SN
560int wxThread::GetCPUCount()
561{
562 ULONG CPUCount;
563 APIRET ulrc;
564 ulrc = ::DosQuerySysInfo(26, 26, (void *)&CPUCount, sizeof(ULONG));
565 // QSV_NUMPROCESSORS(26) is typically not defined in header files
566
567 if (ulrc != 0)
568 CPUCount = 1;
569
570 return CPUCount;
571}
572
f9226383 573wxThreadIdType wxThread::GetCurrentId()
d1bab566
SN
574{
575 PTIB ptib;
576 PPIB ppib;
577
578 ::DosGetInfoBlocks(&ptib, &ppib);
f9226383 579 return (wxThreadIdType) ptib->tib_ptib2->tib2_ultid;
d1bab566
SN
580}
581
582bool wxThread::SetConcurrency(size_t level)
583{
9a83f860 584 wxASSERT_MSG( IsMain(), wxT("should only be called from the main thread") );
d1bab566
SN
585
586 // ok only for the default one
587 if ( level == 0 )
588 return 0;
589
590 // Don't know how to realize this on OS/2.
591 return level == 1;
592}
593
d01cc696
DW
594// ctor and dtor
595// -------------
596
597wxThread::wxThread(wxThreadKind kind)
598{
599 m_internal = new wxThreadInternal();
600
601 m_isDetached = kind == wxTHREAD_DETACHED;
602}
603
604wxThread::~wxThread()
605{
606 delete m_internal;
607}
608
d90895ac
DW
609// create/start thread
610// -------------------
611
793c7f9b
DW
612wxThreadError wxThread::Create(
613 unsigned int uStackSize
614)
0e320a79 615{
d1bab566
SN
616 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
617
793c7f9b 618 if ( !m_internal->Create(this, uStackSize) )
d90895ac
DW
619 return wxTHREAD_NO_RESOURCE;
620
0e320a79
DW
621 return wxTHREAD_NO_ERROR;
622}
623
d90895ac 624wxThreadError wxThread::Run()
0e320a79 625{
c5fb56c0 626 wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
d90895ac 627
2e57ca64
VS
628 // Create the thread if it wasn't created yet with an explicit
629 // Create() call:
630 if ( !m_internal->GetHandle() )
631 {
632 if ( !m_internal->Create(this, 0) )
633 return wxTHREAD_NO_RESOURCE;
634 }
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
b95a7c31 671wxThread::ExitCode wxThread::Wait(wxThreadWait waitMode)
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,
9a83f860 676 wxT("can't wait for detached thread") );
d01cc696 677 ExitCode rc = (ExitCode)-1;
b95a7c31 678 (void)Delete(&rc, waitMode);
d01cc696
DW
679 return(rc);
680}
681
b95a7c31 682wxThreadError wxThread::Delete(ExitCode *pRc, wxThreadWait WXUNUSED(waitMode))
d01cc696
DW
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
f9226383 936 wxThread::ms_idMainThread = wxThread::GetCurrentId();
d90895ac 937
6670f564 938 return true;
d90895ac
DW
939}
940
941void wxThreadModule::OnExit()
942{
43543d98 943 if (gs_pCritsectGui)
d90895ac 944 {
43543d98 945 gs_pCritsectGui->Leave();
f6bcfd97 946#if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
43543d98 947 delete gs_pCritsectGui;
f6bcfd97 948#endif
43543d98 949 gs_pCritsectGui = NULL;
d90895ac
DW
950 }
951
f6bcfd97 952#if (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )))
43543d98 953 wxDELETE(gs_pCritsectWaitingForGui);
f6bcfd97 954#endif
d90895ac
DW
955}
956
957// ----------------------------------------------------------------------------
c5fb56c0 958// Helper functions
d90895ac
DW
959// ----------------------------------------------------------------------------
960
d1bab566 961// wake up the main thread if it's in ::GetMessage()
c5fb56c0 962void WXDLLEXPORT wxWakeUpMainThread()
d90895ac 963{
8e5052fa 964#if 0
d1bab566
SN
965 if ( !::WinPostQueueMsg(wxTheApp->m_hMq, WM_NULL, 0, 0) )
966 {
967 // should never happen
968 wxLogLastError(wxT("WinPostMessage(WM_NULL)"));
969 }
8e5052fa 970#endif
d90895ac
DW
971}
972
d254213e 973void wxMutexGuiEnterImpl()
28a75c29
SN
974{
975 // this would dead lock everything...
976 wxASSERT_MSG( !wxThread::IsMain(),
977 wxT("main thread doesn't want to block in wxMutexGuiEnter()!") );
978
979 // the order in which we enter the critical sections here is crucial!!
980
981 // set the flag telling to the main thread that we want to do some GUI
982 {
983 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
984
985 gs_nWaitingForGui++;
986 }
987
988 wxWakeUpMainThread();
989
990 // now we may block here because the main thread will soon let us in
991 // (during the next iteration of OnIdle())
992 gs_pCritsectGui->Enter();
993}
994
d254213e 995void wxMutexGuiLeaveImpl()
d90895ac 996{
43543d98 997 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
d90895ac
DW
998
999 if ( wxThread::IsMain() )
1000 {
6670f564 1001 gs_bGuiOwnedByMainThread = false;
d90895ac
DW
1002 }
1003 else
1004 {
1005 // decrement the number of waiters now
43543d98 1006 wxASSERT_MSG(gs_nWaitingForGui > 0,
d90895ac
DW
1007 wxT("calling wxMutexGuiLeave() without entering it first?") );
1008
43543d98 1009 gs_nWaitingForGui--;
d90895ac
DW
1010
1011 wxWakeUpMainThread();
1012 }
1013
43543d98 1014 gs_pCritsectGui->Leave();
d90895ac
DW
1015}
1016
1017void WXDLLEXPORT wxMutexGuiLeaveOrEnter()
1018{
1019 wxASSERT_MSG( wxThread::IsMain(),
1020 wxT("only main thread may call wxMutexGuiLeaveOrEnter()!") );
1021
43543d98 1022 wxCriticalSectionLocker enter(*gs_pCritsectWaitingForGui);
d90895ac 1023
43543d98 1024 if (gs_nWaitingForGui == 0)
d90895ac
DW
1025 {
1026 // no threads are waiting for GUI - so we may acquire the lock without
1027 // any danger (but only if we don't already have it)
c5fb56c0 1028 if (!wxGuiOwnedByMainThread())
d90895ac 1029 {
43543d98 1030 gs_pCritsectGui->Enter();
d90895ac 1031
6670f564 1032 gs_bGuiOwnedByMainThread = true;
d90895ac
DW
1033 }
1034 //else: already have it, nothing to do
1035 }
1036 else
1037 {
1038 // some threads are waiting, release the GUI lock if we have it
c5fb56c0 1039 if (wxGuiOwnedByMainThread())
d90895ac
DW
1040 {
1041 wxMutexGuiLeave();
1042 }
1043 //else: some other worker thread is doing GUI
1044 }
1045}
1046
1047bool WXDLLEXPORT wxGuiOwnedByMainThread()
1048{
43543d98 1049 return gs_bGuiOwnedByMainThread;
d90895ac
DW
1050}
1051
9ed0fac8
DW
1052bool WXDLLEXPORT wxIsWaitingForThread()
1053{
43543d98 1054 return gs_bWaitingForThread;
9ed0fac8
DW
1055}
1056
d1bab566
SN
1057// ----------------------------------------------------------------------------
1058// include common implementation code
1059// ----------------------------------------------------------------------------
1060
1061#include "wx/thrimpl.cpp"
1062
0e320a79
DW
1063#endif
1064 // wxUSE_THREADS