1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/palmos/thread.cpp
3// Purpose:     wxThread Implementation
4// Author:      William Osborne - minimal working wxPalmOS port
5// Modified by:
6// Created:     10/13/04
7// RCS-ID:      $Id: thread.cpp 40943 2006-08-31 19:31:43Z ABX $
8// Copyright:   (c) William Osborne
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ----------------------------------------------------------------------------
13// headers
14// ----------------------------------------------------------------------------
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#if defined(__BORLANDC__)
20    #pragma hdrstop
21#endif
22
23#if wxUSE_THREADS
24
25#include "wx/thread.h"
26
27#ifndef WX_PRECOMP
28    #include "wx/intl.h"
29    #include "wx/app.h"
30    #include "wx/module.h"
31#endif
32
33#include "wx/apptrait.h"
34
35#include "wx/palmos/private.h"
36#include "wx/palmos/missing.h"
37
38// must have this symbol defined to get _beginthread/_endthread declarations
39#ifndef _MT
40    #define _MT
41#endif
42
43#if defined(__BORLANDC__)
44    #if !defined(__MT__)
45        // I can't set -tWM in the IDE (anyone?) so have to do this
46        #define __MT__
47    #endif
48
49    #if !defined(__MFC_COMPAT__)
50        // Needed to know about _beginthreadex etc..
51        #define __MFC_COMPAT__
52    #endif
53#endif // BC++
54
55// define wxUSE_BEGIN_THREAD if the compiler has _beginthreadex() function
56// which should be used instead of Win32 ::CreateThread() if possible
57#if defined(__VISUALC__) || \
58    (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) || \
59    (defined(__GNUG__) && defined(__MSVCRT__)) || \
60    defined(__WATCOMC__) || defined(__MWERKS__)
61
62#ifndef __WXWINCE__
63    #undef wxUSE_BEGIN_THREAD
64    #define wxUSE_BEGIN_THREAD
65#endif
66
67#endif
68
69#ifdef wxUSE_BEGIN_THREAD
70    // the return type of the thread function entry point
71    typedef unsigned THREAD_RETVAL;
72
73    // the calling convention of the thread function entry point
74    #define THREAD_CALLCONV __stdcall
75#else
76    // the settings for CreateThread()
77    typedef DWORD THREAD_RETVAL;
78    #define THREAD_CALLCONV WINAPI
79#endif
80
81// ----------------------------------------------------------------------------
82// constants
83// ----------------------------------------------------------------------------
84
85// the possible states of the thread ("=>" shows all possible transitions from
86// this state)
87enum wxThreadState
88{
89    STATE_NEW,          // didn't start execution yet (=> RUNNING)
90    STATE_RUNNING,      // thread is running (=> PAUSED, CANCELED)
91    STATE_PAUSED,       // thread is temporarily suspended (=> RUNNING)
92    STATE_CANCELED,     // thread should terminate a.s.a.p. (=> EXITED)
93    STATE_EXITED        // thread is terminating
94};
95
96// ----------------------------------------------------------------------------
97// this module globals
98// ----------------------------------------------------------------------------
99
100// TLS index of the slot where we store the pointer to the current thread
101static DWORD gs_tlsThisThread = 0xFFFFFFFF;
102
103// id of the main thread - the one which can call GUI functions without first
104// calling wxMutexGuiEnter()
105static DWORD gs_idMainThread = 0;
106
107// if it's false, some secondary thread is holding the GUI lock
108static bool gs_bGuiOwnedByMainThread = true;
109
110// critical section which controls access to all GUI functions: any secondary
111// thread (i.e. except the main one) must enter this crit section before doing
112// any GUI calls
113static wxCriticalSection *gs_critsectGui = NULL;
114
115// critical section which protects gs_nWaitingForGui variable
116static wxCriticalSection *gs_critsectWaitingForGui = NULL;
117
118// critical section which serializes WinThreadStart() and WaitForTerminate()
119// (this is a potential bottleneck, we use a single crit sect for all threads
120// in the system, but normally time spent inside it should be quite short)
121static wxCriticalSection *gs_critsectThreadDelete = NULL;
122
123// number of threads waiting for GUI in wxMutexGuiEnter()
124static size_t gs_nWaitingForGui = 0;
125
126// are we waiting for a thread termination?
127static bool gs_waitingForThread = false;
128
129// ============================================================================
130// Windows implementation of thread and related classes
131// ============================================================================
132
133// ----------------------------------------------------------------------------
134// wxCriticalSection
135// ----------------------------------------------------------------------------
136
137wxCriticalSection::wxCriticalSection()
138{
139}
140
141wxCriticalSection::~wxCriticalSection()
142{
143}
144
145void wxCriticalSection::Enter()
146{
147}
148
149void wxCriticalSection::Leave()
150{
151}
152
153// ----------------------------------------------------------------------------
154// wxMutex
155// ----------------------------------------------------------------------------
156
157class wxMutexInternal
158{
159public:
160    wxMutexInternal(wxMutexType mutexType);
161    ~wxMutexInternal();
162
163    bool IsOk() const { return m_mutex != NULL; }
164
165    wxMutexError Lock() { return LockTimeout(INFINITE); }
166    wxMutexError TryLock() { return LockTimeout(0); }
167    wxMutexError Unlock();
168
169private:
170    wxMutexError LockTimeout(DWORD milliseconds);
171
172    HANDLE m_mutex;
173
174    DECLARE_NO_COPY_CLASS(wxMutexInternal)
175};
176
177// all mutexes are recursive under Win32 so we don't use mutexType
178wxMutexInternal::wxMutexInternal(wxMutexType WXUNUSED(mutexType))
179{
180}
181
182wxMutexInternal::~wxMutexInternal()
183{
184}
185
186wxMutexError wxMutexInternal::LockTimeout(DWORD milliseconds)
187{
188    return wxMUTEX_NO_ERROR;
189}
190
191wxMutexError wxMutexInternal::Unlock()
192{
193    return wxMUTEX_NO_ERROR;
194}
195
196// --------------------------------------------------------------------------
197// wxSemaphore
198// --------------------------------------------------------------------------
199
200// a trivial wrapper around Win32 semaphore
201class wxSemaphoreInternal
202{
203public:
204    wxSemaphoreInternal(int initialcount, int maxcount);
205    ~wxSemaphoreInternal();
206
207    bool IsOk() const { return m_semaphore != NULL; }
208
209    wxSemaError Wait() { return WaitTimeout(INFINITE); }
210
211    wxSemaError TryWait()
212    {
213        wxSemaError rc = WaitTimeout(0);
214        if ( rc == wxSEMA_TIMEOUT )
215            rc = wxSEMA_BUSY;
216
217        return rc;
218    }
219
220    wxSemaError WaitTimeout(unsigned long milliseconds);
221
222    wxSemaError Post();
223
224private:
225    HANDLE m_semaphore;
226
227    DECLARE_NO_COPY_CLASS(wxSemaphoreInternal)
228};
229
230wxSemaphoreInternal::wxSemaphoreInternal(int initialcount, int maxcount)
231{
232}
233
234wxSemaphoreInternal::~wxSemaphoreInternal()
235{
236}
237
238wxSemaError wxSemaphoreInternal::WaitTimeout(unsigned long milliseconds)
239{
240    return wxSEMA_NO_ERROR;
241}
242
243wxSemaError wxSemaphoreInternal::Post()
244{
245    return wxSEMA_NO_ERROR;
246}
247
248// ----------------------------------------------------------------------------
249// wxThread implementation
250// ----------------------------------------------------------------------------
251
252// wxThreadInternal class
253// ----------------------
254
255class wxThreadInternal
256{
257public:
258    wxThreadInternal(wxThread *thread)
259    {
260        m_thread = thread;
261        m_hThread = 0;
262        m_state = STATE_NEW;
263        m_priority = WXTHREAD_DEFAULT_PRIORITY;
264        m_nRef = 1;
265    }
266
267    ~wxThreadInternal()
268    {
269        Free();
270    }
271
272    void Free()
273    {
274        if ( m_hThread )
275        {
276            if ( !::CloseHandle(m_hThread) )
277            {
278                wxLogLastError(wxT("CloseHandle(thread)"));
279            }
280
281            m_hThread = 0;
282        }
283    }
284
285    // create a new (suspended) thread (for the given thread object)
286    bool Create(wxThread *thread, unsigned int stackSize);
287
288    // wait for the thread to terminate, either by itself, or by asking it
289    // (politely, this is not Kill()!) to do it
290    wxThreadError WaitForTerminate(wxCriticalSection& cs,
291                                   wxThread::ExitCode *pRc,
292                                   wxThread *threadToDelete = NULL);
293
294    // kill the thread unconditionally
295    wxThreadError Kill();
296
297    // suspend/resume/terminate
298    bool Suspend();
299    bool Resume();
300    void Cancel() { m_state = STATE_CANCELED; }
301
302    // thread state
303    void SetState(wxThreadState state) { m_state = state; }
304    wxThreadState GetState() const { return m_state; }
305
306    // thread priority
307    void SetPriority(unsigned int priority);
308    unsigned int GetPriority() const { return m_priority; }
309
310    // thread handle and id
311    HANDLE GetHandle() const { return m_hThread; }
312    DWORD  GetId() const { return m_tid; }
313
314    // thread function
315    static THREAD_RETVAL THREAD_CALLCONV WinThreadStart(void *thread);
316
317    void KeepAlive()
318    {
319        if ( m_thread->IsDetached() )
320            ::InterlockedIncrement(&m_nRef);
321    }
322
323    void LetDie()
324    {
325        if ( m_thread->IsDetached() && !::InterlockedDecrement(&m_nRef) )
326            delete m_thread;
327    }
328
329private:
330    // the thread we're associated with
331    wxThread *m_thread;
332
333    HANDLE        m_hThread;    // handle of the thread
334    wxThreadState m_state;      // state, see wxThreadState enum
335    unsigned int  m_priority;   // thread priority in "wx" units
336    DWORD         m_tid;        // thread id
337
338    // number of threads which need this thread to remain alive, when the count
339    // reaches 0 we kill the owning wxThread -- and die ourselves with it
340    LONG m_nRef;
341
342    DECLARE_NO_COPY_CLASS(wxThreadInternal)
343};
344
345// small class which keeps a thread alive during its lifetime
346class wxThreadKeepAlive
347{
348public:
349    wxThreadKeepAlive(wxThreadInternal& thrImpl) : m_thrImpl(thrImpl)
350        { m_thrImpl.KeepAlive(); }
351    ~wxThreadKeepAlive()
352        { m_thrImpl.LetDie(); }
353
354private:
355    wxThreadInternal& m_thrImpl;
356};
357
358
359THREAD_RETVAL THREAD_CALLCONV wxThreadInternal::WinThreadStart(void *param)
360{
361    THREAD_RETVAL rc;
362
363    return rc;
364}
365
366void wxThreadInternal::SetPriority(unsigned int priority)
367{
368}
369
370bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize)
371{
372    return false;
373}
374
375wxThreadError wxThreadInternal::Kill()
376{
377    return wxTHREAD_NO_ERROR;
378}
379
380wxThreadError
381wxThreadInternal::WaitForTerminate(wxCriticalSection& cs,
382                                   wxThread::ExitCode *pRc,
383                                   wxThread *threadToDelete)
384{
385    return wxTHREAD_NO_ERROR;
386}
387
388bool wxThreadInternal::Suspend()
389{
390    return true;
391}
392
393bool wxThreadInternal::Resume()
394{
395    return true;
396}
397
398// static functions
399// ----------------
400
401wxThread *wxThread::This()
402{
403    return NULL;
404}
405
406bool wxThread::IsMain()
407{
408    return true;
409}
410
411void wxThread::Yield()
412{
413}
414
415void wxThread::Sleep(unsigned long milliseconds)
416{
417}
418
419int wxThread::GetCPUCount()
420{
421    return 1;
422}
423
424unsigned long wxThread::GetCurrentId()
425{
426    return 0;
427}
428
429bool wxThread::SetConcurrency(size_t level)
430{
431    return true;
432}
433
434// ctor and dtor
435// -------------
436
437wxThread::wxThread(wxThreadKind kind)
438{
439}
440
441wxThread::~wxThread()
442{
443}
444
445// create/start thread
446// -------------------
447
448wxThreadError wxThread::Create(unsigned int stackSize)
449{
450    return wxTHREAD_NO_ERROR;
451}
452
453wxThreadError wxThread::Run()
454{
455    return wxTHREAD_RUNNING;
456}
457
458// suspend/resume thread
459// ---------------------
460
461wxThreadError wxThread::Pause()
462{
463    return wxTHREAD_NO_ERROR;
464}
465
466wxThreadError wxThread::Resume()
467{
468    return wxTHREAD_NO_ERROR;
469}
470
471// stopping thread
472// ---------------
473
474wxThread::ExitCode wxThread::Wait()
475{
476    return 0;
477}
478
479wxThreadError wxThread::Delete(ExitCode *pRc)
480{
481    return wxTHREAD_NO_ERROR;
482}
483
484wxThreadError wxThread::Kill()
485{
486    return wxTHREAD_NO_ERROR;
487}
488
489void wxThread::Exit(ExitCode status)
490{
491}
492
493// priority setting
494// ----------------
495
496void wxThread::SetPriority(unsigned int prio)
497{
498}
499
500unsigned int wxThread::GetPriority() const
501{
502    return 1;
503}
504
505unsigned long wxThread::GetId() const
506{
507    return 0;
508}
509
510bool wxThread::IsRunning() const
511{
512    return true;
513}
514
515bool wxThread::IsAlive() const
516{
517    return true;
518}
519
520bool wxThread::IsPaused() const
521{
522    return false;
523}
524
525bool wxThread::TestDestroy()
526{
527    return true;
528}
529
530// ----------------------------------------------------------------------------
531// Automatic initialization for thread module
532// ----------------------------------------------------------------------------
533
534class wxThreadModule : public wxModule
535{
536public:
537    virtual bool OnInit();
538    virtual void OnExit();
539
540private:
541    DECLARE_DYNAMIC_CLASS(wxThreadModule)
542};
543
544IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
545
546bool wxThreadModule::OnInit()
547{
548    return true;
549}
550
551void wxThreadModule::OnExit()
552{
553}
554
555// ----------------------------------------------------------------------------
556// under Windows, these functions are implemented using a critical section and
557// not a mutex, so the names are a bit confusing
558// ----------------------------------------------------------------------------
559
560void WXDLLIMPEXP_BASE wxMutexGuiEnter()
561{
562}
563
564void WXDLLIMPEXP_BASE wxMutexGuiLeave()
565{
566}
567
568void WXDLLIMPEXP_BASE wxMutexGuiLeaveOrEnter()
569{
570}
571
572bool WXDLLIMPEXP_BASE wxGuiOwnedByMainThread()
573{
574    return true;
575}
576
577// wake up the main thread if it's in ::GetMessage()
578void WXDLLIMPEXP_BASE wxWakeUpMainThread()
579{
580}
581
582bool WXDLLIMPEXP_BASE wxIsWaitingForThread()
583{
584    return false;
585}
586
587// ----------------------------------------------------------------------------
588// include common implementation code
589// ----------------------------------------------------------------------------
590
591#include "wx/thrimpl.cpp"
592
593#endif // wxUSE_THREADS
594