wxThread fixes - compilation under Unix temporarily broken, sorry.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1420 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 1999-01-17 22:39:58 +00:00
parent 84a19deccc
commit bf1852e121
3 changed files with 561 additions and 237 deletions

View File

@ -2,7 +2,8 @@
// Name: thread.h
// Purpose: Thread API
// Author: Guilhem Lavaux
// Modified by:
// Modified by: Vadim Zeitlin (modifications partly inspired by omnithreads
// package from Olivetti & Oracle Research Laboratory)
// Created: 04/13/98
// RCS-ID: $Id$
// Copyright: (c) Guilhem Lavaux
@ -13,31 +14,39 @@
#define __THREADH__
#ifdef __GNUG__
#pragma interface "thread.h"
#pragma interface "thread.h"
#endif
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// get the value of wxUSE_THREADS configuration flag
#include "wx/setup.h"
#if wxUSE_THREADS
// Windows headers define it
#ifdef Yield
#undef Yield
#endif
#include "wx/module.h"
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
typedef enum
typedef enum
{
wxMUTEX_NO_ERROR = 0,
wxMUTEX_DEAD_LOCK, // Mutex has been already locked by THE CALLING thread
wxMUTEX_DEAD_LOCK, // Mutex has been already locked by THE CALLING thread
wxMUTEX_BUSY, // Mutex has been already locked by ONE thread
wxMUTEX_UNLOCKED,
wxMUTEX_MISC_ERROR
} wxMutexError;
typedef enum
typedef enum
{
wxTHREAD_NO_ERROR = 0, // No error
wxTHREAD_NO_RESOURCE, // No resource left to create a new thread
@ -46,10 +55,10 @@ typedef enum
wxTHREAD_MISC_ERROR // Some other error
} wxThreadError;
/* defines the interval of priority. */
#define WXTHREAD_MIN_PRIORITY 0
#define WXTHREAD_DEFAULT_PRIORITY 50
#define WXTHREAD_MAX_PRIORITY 100
// defines the interval of priority
#define WXTHREAD_MIN_PRIORITY 0u
#define WXTHREAD_DEFAULT_PRIORITY 50u
#define WXTHREAD_MAX_PRIORITY 100u
// ----------------------------------------------------------------------------
// A mutex object is a synchronization object whose state is set to signaled
@ -61,10 +70,10 @@ typedef enum
// you should consider wxMutexLocker whenever possible instead of directly
// working with wxMutex class - it is safer
class WXDLLEXPORT wxMutexInternal;
class WXDLLEXPORT wxMutex
class WXDLLEXPORT wxMutex
{
public:
// constructor & destructor
// constructor & destructor
wxMutex();
~wxMutex();
@ -121,14 +130,17 @@ private:
// mutexes
// ----------------------------------------------------------------------------
// you should consider wxCriticalSectionLocker whenever possible instead of
// directly working with wxCriticalSection class - it is safer
// in order to avoid any overhead under !MSW make all wxCriticalSection class
// functions inline - but this can't be done under MSW
#ifdef __WXMSW__
class WXDLLEXPORT wxCriticalSectionInternal;
#define WXCRITICAL_INLINE
#else // !MSW
#define WXCRITICAL_INLINE inline
#endif // MSW/!MSW
// you should consider wxCriticalSectionLocker whenever possible instead of
// directly working with wxCriticalSection class - it is safer
class WXDLLEXPORT wxCriticalSection
{
public:
@ -153,6 +165,9 @@ private:
#endif // MSW/!MSW
};
// keep your preprocessor name space clean
#undef WXCRITICAL_INLINE
// wxCriticalSectionLocker is the same to critical sections as wxMutexLocker is
// to th mutexes
class WXDLLEXPORT wxCriticalSectionLocker
@ -176,7 +191,7 @@ private:
// ----------------------------------------------------------------------------
class wxConditionInternal;
class WXDLLEXPORT wxCondition
class WXDLLEXPORT wxCondition
{
public:
// constructor & destructor
@ -200,70 +215,129 @@ private:
// Thread management class
// ----------------------------------------------------------------------------
// FIXME Thread termination model is still unclear. Delete() should probably
// have a timeout after which the thread must be Kill()ed.
// NB: in the function descriptions the words "this thread" mean the thread
// created by the wxThread object while "main thread" is the thread created
// during the process initialization (a.k.a. the GUI thread)
class wxThreadInternal;
class WXDLLEXPORT wxThread
class WXDLLEXPORT wxThread
{
public:
// constructor & destructor.
wxThread();
virtual ~wxThread();
// the return type for the thread function
typedef void *ExitCode;
// Create a new thread, this method should check there is only one thread
// running by object.
wxThreadError Create();
// static functions
// Returns the wxThread object for the calling thread. NULL is returned
// if the caller is the main thread (but it's recommended to use
// IsMain() and only call This() for threads other than the main one
// because NULL is also returned on error). If the thread wasn't
// created with wxThread class, the returned value is undefined.
static wxThread *This();
// Destroys the thread immediately if the defer flag isn't true.
wxThreadError Destroy();
// Returns true if current thread is the main thread.
static bool IsMain();
// Pause a running thread
wxThreadError Pause();
// Release the rest of our time slice leting the other threads run
static void Yield();
// Resume a paused thread
wxThreadError Resume();
// Sleep during the specified period of time in milliseconds
//
// NB: at least under MSW worker threads can not call ::wxSleep()!
static void Sleep(unsigned long milliseconds);
// Switches on the defer flag.
void DeferDestroy(bool on);
// default constructor
wxThread();
// Waits for the termination of the thread.
void *Join();
// function that change the thread state
// create a new thread - call Run() to start it
wxThreadError Create();
// Sets the priority to "prio". (Warning: The priority can only be set before
// the thread is created)
void SetPriority(int prio);
// Get the current priority.
int GetPriority() const;
// starts execution of the thread - from the moment Run() is called the
// execution of wxThread::Entry() may start at any moment, caller
// shouldn't suppose that it starts after (or before) Run() returns.
wxThreadError Run();
// Get the thread ID
unsigned long GetID() const;
// stops the thread if it's running and deletes the wxThread object
// freeing its memory. This function should also be called if the
// Create() or Run() fails to free memory (otherwise it will be done by
// the thread itself when it terminates). The return value is the
// thread exit code if the thread was gracefully terminated, 0 if it
// wasn't running and -1 if an error occured.
ExitCode Delete();
// Returns true if the thread is alive.
bool IsAlive() const;
// Returns true if the thread is running (not paused, not killed).
bool IsRunning() const;
// Returns true if the thread is suspended
bool IsPaused() const { return IsAlive() && !IsRunning(); }
// kills the thread without giving it any chance to clean up - should
// not be used in normal circumstances, use Delete() instead. It is a
// dangerous function that should only be used in the most extreme
// cases! The wxThread object is deleted by Kill() if thread was
// killed (i.e. no errors occured).
wxThreadError Kill();
// Returns true if current thread is the main thread (aka the GUI thread)
static bool IsMain();
// pause a running thread
wxThreadError Pause();
// Called when thread exits.
virtual void OnExit();
// resume a paused thread
wxThreadError Resume();
// priority
// Sets the priority to "prio": see WXTHREAD_XXX_PRIORITY constants
//
// NB: the priority can only be set before the thread is created
void SetPriority(unsigned int prio);
// Get the current priority.
unsigned int GetPriority() const;
// Get the thread ID - a platform dependent number which uniquely
// identifies a thread inside a process
unsigned long GetID() const;
// thread status inquiries
// Returns true if the thread is alive: i.e. running or suspended
bool IsAlive() const;
// Returns true if the thread is running (not paused, not killed).
bool IsRunning() const;
// Returns true if the thread is suspended
bool IsPaused() const { return IsAlive() && !IsRunning(); }
// called when the thread exits - in the context of this thread
//
// NB: this function will not be called if the thread is Kill()ed
virtual void OnExit() { }
protected:
// Returns TRUE if the thread was asked to terminate
bool TestDestroy();
// Returns TRUE if the thread was asked to terminate: this function should
// be called by the thread from time to time, otherwise the main thread
// will be left forever in Delete()!
bool TestDestroy() const;
// Exits from the current thread.
void Exit(void *status = NULL);
// exits from the current thread - can be called only from this thread
void Exit(void *exitcode = 0);
// destructor is private - user code can't delete thread objects, they will
// auto-delete themselves (and thus must be always allocated on the heap).
// Use Delete() or Kill() instead.
//
// NB: derived classes dtors shouldn't be public neither!
virtual ~wxThread();
// entry point for the thread - called by Run() and executes in the context
// of this thread.
virtual void *Entry() = 0;
private:
// Entry point for the thread.
virtual void *Entry() = 0;
// no copy ctor/assignment operator
wxThread(const wxThread&);
wxThread& operator=(const wxThread&);
private:
friend class wxThreadInternal;
friend class wxThreadInternal;
wxThreadInternal *p_internal;
// the (platform-dependent) thread class implementation
wxThreadInternal *p_internal;
// protects access to any methods of wxThreadInternal object
wxCriticalSection m_critsect;
};
// ----------------------------------------------------------------------------
@ -305,6 +379,10 @@ public:
// wakes up the main thread if it's sleeping inside ::GetMessage()
extern void WXDLLEXPORT wxWakeUpMainThread();
// return TRUE if the main thread is waiting for some other to terminate:
// wxApp then should block all "dangerous" messages
extern bool WXDLLEXPORT wxIsWaitingForThread();
#else // !MSW
// implement wxCriticalSection using mutexes
inline wxCriticalSection::wxCriticalSection() { }

View File

@ -42,10 +42,10 @@
#include "wx/time.h"
// Define a new application type
class MyApp: public wxApp
class MyApp : public wxApp
{
public:
bool OnInit(void);
bool OnInit();
};
WX_DEFINE_ARRAY(wxThread *, wxArrayThread);
@ -55,7 +55,7 @@ class MyFrame: public wxFrame
{
public:
// ctor
MyFrame(wxFrame *frame, char *title, int x, int y, int w, int h);
MyFrame(wxFrame *frame, const wxString& title, int x, int y, int w, int h);
// operations
void WriteText(const wxString& text) { m_txtctrl->WriteText(text); }
@ -80,13 +80,15 @@ public:
wxArrayThread m_threads;
private:
void DeleteThread(size_t index);
// crit section protects access to the array below
wxCriticalSection m_critsect;
wxArrayInt m_aToDelete;
wxTextCtrl *m_txtctrl;
// the array of threads which finished (either because they did their work
// or because they were explicitly stopped)
wxArrayInt m_aToDelete;
// just some place to put our messages in
wxTextCtrl *m_txtctrl;
DECLARE_EVENT_TABLE()
};
@ -99,7 +101,8 @@ public:
// thread execution starts here
virtual void *Entry();
// called when the thread exits - whether
// called when the thread exits - whether it terminates normally or is
// stopped with Delete() (but not when it is Kill()ed!)
virtual void OnExit();
// write something to the text control
@ -138,8 +141,6 @@ void *MyThread::Entry()
{
wxString text;
DeferDestroy(TRUE);
text.Printf("Thread 0x%x started.\n", GetID());
WriteText(text);
@ -152,11 +153,8 @@ void *MyThread::Entry()
text.Printf("[%u] Thread 0x%x here.\n", m_count, GetID());
WriteText(text);
#ifdef __WXMSW__
::Sleep(1000);
#else
wxSleep(1);
#endif
// wxSleep() can't be called from non-GUI thread!
wxThread::Sleep(1000);
}
text.Printf("Thread 0x%x finished.\n", GetID());
@ -229,7 +227,8 @@ bool MyApp::OnInit()
}
// My frame constructor
MyFrame::MyFrame(wxFrame *frame, char *title, int x, int y, int w, int h)
MyFrame::MyFrame(wxFrame *frame, const wxString& title,
int x, int y, int w, int h)
: wxFrame(frame, -1, title, wxPoint(x, y), wxSize(w, h))
{
CreateStatusBar();
@ -243,24 +242,31 @@ void MyFrame::OnStartThread(wxCommandEvent& WXUNUSED(event) )
{
MyThread *thread = new MyThread(this);
thread->Create();
if ( thread->Create() != wxTHREAD_NO_ERROR )
{
wxLogError("Can't create thread!");
}
wxCriticalSectionLocker enter(m_critsect);
m_threads.Add(thread);
if ( thread->Run() != wxTHREAD_NO_ERROR )
{
wxLogError("Can't start thread!");
}
}
void MyFrame::OnStopThread(wxCommandEvent& WXUNUSED(event) )
{
int no_thrd = m_threads.Count() - 1;
if ( no_thrd < 0 )
// stop the last thread
if ( m_threads.IsEmpty() )
{
wxLogError("No thread to stop!");
return;
}
DeleteThread(no_thrd);
else
{
m_threads.Last()->Delete();
}
}
void MyFrame::OnResumeThread(wxCommandEvent& WXUNUSED(event) )
@ -268,11 +274,11 @@ void MyFrame::OnResumeThread(wxCommandEvent& WXUNUSED(event) )
wxCriticalSectionLocker enter(m_critsect);
// resume first suspended thread
size_t n = 0;
while ( n < m_threads.Count() && m_threads[n]->IsPaused() )
n--;
size_t n = 0, count = m_threads.Count();
while ( n < count && !m_threads[n]->IsPaused() )
n++;
if ( n < 0 )
if ( n == count )
wxLogError("No thread to resume!");
else
m_threads[n]->Resume();
@ -302,7 +308,11 @@ void MyFrame::OnIdle(wxIdleEvent &event)
size_t nCount = m_aToDelete.Count();
for ( size_t n = 0; n < nCount; n++ )
DeleteThread((size_t)m_aToDelete[n]);
{
// index should be shifted by n because we've already deleted
// n-1 elements from the array
m_threads.Remove((size_t)m_aToDelete[n] - n);
}
m_aToDelete.Empty();
}
@ -320,16 +330,20 @@ void MyFrame::OnIdle(wxIdleEvent &event)
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) )
{
for ( size_t i = 0; i < m_threads.Count(); i++ )
delete m_threads[i];
size_t count = m_threads.Count();
for ( size_t i = 0; i < count; i++ )
{
m_threads[i]->Delete();
}
Close(TRUE);
}
void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
{
wxMessageDialog dialog(this, "wxThread sample (based on minimal)\n"
"Julian Smart, Guilhem Lavaux, Vadim Zeitlin",
wxMessageDialog dialog(this, "wxWindows multithreaded application sample\n"
"(c) 1998 Julian Smart, Guilhem Lavaux\n"
"(c) 1999 Vadim Zeitlin",
"About wxThread sample",
wxOK | wxICON_INFORMATION);
@ -350,9 +364,3 @@ void MyFrame::OnThreadExit(wxThread *thread)
m_aToDelete.Add(index);
}
void MyFrame::DeleteThread(size_t index)
{
delete m_threads[index];
m_threads.Remove(index);
}

View File

@ -38,19 +38,24 @@
#include "wx/module.h"
#include "wx/thread.h"
enum thread_state
// the possible states of the thread ("=>" shows all possible transitions from
// this state)
enum wxThreadState
{
STATE_IDLE = 0,
STATE_RUNNING,
STATE_PAUSED,
STATE_CANCELED,
STATE_EXITED
STATE_NEW, // didn't start execution yet (=> RUNNING)
STATE_RUNNING, // thread is running (=> PAUSED, CANCELED)
STATE_PAUSED, // thread is temporarily suspended (=> RUNNING)
STATE_CANCELED, // thread should terminate a.s.a.p. (=> EXITED)
STATE_EXITED // thread is terminating
};
// ----------------------------------------------------------------------------
// static variables
// ----------------------------------------------------------------------------
// TLS index of the slot where we store the pointer to the current thread
static DWORD s_tlsThisThread = 0xFFFFFFFF;
// id of the main thread - the one which can call GUI functions without first
// calling wxMutexGuiEnter()
static DWORD s_idMainThread = 0;
@ -69,6 +74,9 @@ static wxCriticalSection *s_critsectWaitingForGui = NULL;
// number of threads waiting for GUI in wxMutexGuiEnter()
static size_t s_nWaitingForGui = 0;
// are we waiting for a thread termination?
static bool s_waitingForThread = FALSE;
// ============================================================================
// Windows implementation of thread classes
// ============================================================================
@ -271,185 +279,160 @@ void wxCriticalSection::Leave()
// wxThread implementation
// ----------------------------------------------------------------------------
// wxThreadInternal class
// ----------------------
class wxThreadInternal
{
public:
wxThreadInternal()
{
m_hThread = 0;
m_state = STATE_NEW;
m_priority = WXTHREAD_DEFAULT_PRIORITY;
}
// create a new (suspended) thread (for the given thread object)
bool Create(wxThread *thread);
// suspend/resume/terminate
bool Suspend();
bool Resume();
void Cancel() { m_state = STATE_CANCELED; }
// thread state
void SetState(wxThreadState state) { m_state = state; }
wxThreadState GetState() const { return m_state; }
// thread priority
void SetPriority(unsigned int priority) { m_priority = priority; }
unsigned int GetPriority() const { return m_priority; }
// thread handle and id
HANDLE GetHandle() const { return m_hThread; }
DWORD GetId() const { return m_tid; }
// thread function
static DWORD WinThreadStart(wxThread *thread);
HANDLE hThread;
thread_state state;
int prio, defer;
DWORD tid;
private:
HANDLE m_hThread; // handle of the thread
wxThreadState m_state; // state, see wxThreadState enum
unsigned int m_priority; // thread priority in "wx" units
DWORD m_tid; // thread id
};
DWORD wxThreadInternal::WinThreadStart(wxThread *thread)
{
// store the thread object in the TLS
if ( !::TlsSetValue(s_tlsThisThread, thread) )
{
wxLogSysError(_("Can not start thread: error writing TLS."));
return (DWORD)-1;
}
DWORD ret = (DWORD)thread->Entry();
thread->p_internal->state = STATE_EXITED;
thread->p_internal->SetState(STATE_EXITED);
thread->OnExit();
delete thread;
return ret;
}
wxThreadError wxThread::Create()
bool wxThreadInternal::Create(wxThread *thread)
{
p_internal->hThread = ::CreateThread
(
NULL, // default security
0, // default stack size
(LPTHREAD_START_ROUTINE)
wxThreadInternal::WinThreadStart, // entry point
(void *)this, // parameter
CREATE_SUSPENDED, // flags
&p_internal->tid // [out] thread id
);
m_hThread = ::CreateThread
(
NULL, // default security
0, // default stack size
(LPTHREAD_START_ROUTINE) // thread entry point
wxThreadInternal::WinThreadStart, //
(LPVOID)thread, // parameter
CREATE_SUSPENDED, // flags
&m_tid // [out] thread id
);
if ( p_internal->hThread == NULL )
if ( m_hThread == NULL )
{
wxLogSysError(_("Can't create thread"));
return wxTHREAD_NO_RESOURCE;
return FALSE;
}
int win_prio, prio = p_internal->prio;
if (prio <= 20)
win_prio = THREAD_PRIORITY_LOWEST;
else if (prio <= 40)
win_prio = THREAD_PRIORITY_BELOW_NORMAL;
else if (prio <= 60)
win_prio = THREAD_PRIORITY_NORMAL;
else if (prio <= 80)
win_prio = THREAD_PRIORITY_ABOVE_NORMAL;
else if (prio <= 100)
win_prio = THREAD_PRIORITY_HIGHEST;
// translate wxWindows priority to the Windows one
int win_priority;
if (m_priority <= 20)
win_priority = THREAD_PRIORITY_LOWEST;
else if (m_priority <= 40)
win_priority = THREAD_PRIORITY_BELOW_NORMAL;
else if (m_priority <= 60)
win_priority = THREAD_PRIORITY_NORMAL;
else if (m_priority <= 80)
win_priority = THREAD_PRIORITY_ABOVE_NORMAL;
else if (m_priority <= 100)
win_priority = THREAD_PRIORITY_HIGHEST;
else
{
wxFAIL_MSG("invalid value of thread priority parameter");
win_prio = THREAD_PRIORITY_NORMAL;
win_priority = THREAD_PRIORITY_NORMAL;
}
if ( SetThreadPriority(p_internal->hThread, win_prio) == 0 )
if ( ::SetThreadPriority(m_hThread, win_priority) == 0 )
{
wxLogSysError(_("Can't set thread priority"));
}
return Resume();
return TRUE;
}
wxThreadError wxThread::Destroy()
bool wxThreadInternal::Suspend()
{
if ( p_internal->state != STATE_RUNNING )
return wxTHREAD_NOT_RUNNING;
if ( p_internal->defer )
{
// soft termination: just set the flag and wait until the thread
// auto terminates
p_internal->state = STATE_CANCELED;
}
else
{
// kill the thread
OnExit();
if ( ::TerminateThread(p_internal->hThread, 0) == 0 )
{
wxLogLastError("TerminateThread");
}
}
return wxTHREAD_NO_ERROR;
}
wxThreadError wxThread::Pause()
{
DWORD nSuspendCount = ::SuspendThread(p_internal->hThread);
DWORD nSuspendCount = ::SuspendThread(m_hThread);
if ( nSuspendCount == (DWORD)-1 )
{
wxLogSysError(_("Can not suspend thread %x"), p_internal->hThread);
wxLogSysError(_("Can not suspend thread %x"), m_hThread);
return wxTHREAD_MISC_ERROR; // no idea what might provoke this error...
return FALSE;
}
p_internal->state = STATE_PAUSED;
m_state = STATE_PAUSED;
return wxTHREAD_NO_ERROR;
return TRUE;
}
wxThreadError wxThread::Resume()
bool wxThreadInternal::Resume()
{
DWORD nSuspendCount = ::ResumeThread(p_internal->hThread);
DWORD nSuspendCount = ::ResumeThread(m_hThread);
if ( nSuspendCount == (DWORD)-1 )
{
wxLogSysError(_("Can not resume thread %x"), p_internal->hThread);
wxLogSysError(_("Can not resume thread %x"), m_hThread);
return wxTHREAD_MISC_ERROR; // no idea what might provoke this error...
return FALSE;
}
p_internal->state = STATE_RUNNING;
m_state = STATE_RUNNING;
return wxTHREAD_NO_ERROR;
return TRUE;
}
void wxThread::Exit(void *status)
// static functions
// ----------------
wxThread *wxThread::This()
{
p_internal->state = STATE_EXITED;
ExitThread((DWORD)status);
}
wxThread *thread = (wxThread *)::TlsGetValue(s_tlsThisThread);
void wxThread::SetPriority(int prio)
{
p_internal->prio = prio;
}
// be careful, 0 may be a valid return value as well
if ( !thread && (::GetLastError() != NO_ERROR) )
{
wxLogSysError(_("Couldn't get the current thread pointer"));
int wxThread::GetPriority() const
{
return p_internal->prio;
}
// return NULL...
}
void wxThread::DeferDestroy(bool on)
{
p_internal->defer = on;
}
bool wxThread::TestDestroy()
{
return p_internal->state == STATE_CANCELED;
}
void *wxThread::Join()
{
DWORD exit_code;
if (p_internal->state == STATE_IDLE)
return NULL;
// FIXME this dead locks... wxThread class design must be changed
#if 0
WaitForSingleObject(p_internal->hThread, INFINITE);
#else
::TerminateThread(p_internal->hThread, 0);
#endif // 0
GetExitCodeThread(p_internal->hThread, &exit_code);
CloseHandle(p_internal->hThread);
p_internal->state = STATE_IDLE;
return (void *)exit_code;
}
unsigned long wxThread::GetID() const
{
return (unsigned long)p_internal->tid;
}
bool wxThread::IsRunning() const
{
return (p_internal->state == STATE_RUNNING);
}
bool wxThread::IsAlive() const
{
return (p_internal->state == STATE_RUNNING);
return thread;
}
bool wxThread::IsMain()
@ -457,26 +440,243 @@ bool wxThread::IsMain()
return ::GetCurrentThreadId() == s_idMainThread;
}
void wxThread::Yield()
{
// 0 argument to Sleep() is special
::Sleep(0);
}
void wxThread::Sleep(unsigned long milliseconds)
{
::Sleep(milliseconds);
}
// create/start thread
// -------------------
wxThreadError wxThread::Create()
{
if ( !p_internal->Create(this) )
return wxTHREAD_NO_RESOURCE;
return wxTHREAD_NO_ERROR;
}
wxThreadError wxThread::Run()
{
wxCriticalSectionLocker lock(m_critsect);
if ( p_internal->GetState() != STATE_NEW )
{
// actually, it may be almost any state at all, not only STATE_RUNNING
return wxTHREAD_RUNNING;
}
return Resume();
}
// suspend/resume thread
// ---------------------
wxThreadError wxThread::Pause()
{
wxCriticalSectionLocker lock(m_critsect);
return p_internal->Suspend() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
}
wxThreadError wxThread::Resume()
{
wxCriticalSectionLocker lock(m_critsect);
return p_internal->Resume() ? wxTHREAD_NO_ERROR : wxTHREAD_MISC_ERROR;
}
// stopping thread
// ---------------
wxThread::ExitCode wxThread::Delete()
{
ExitCode rc = 0;
// Delete() is always safe to call, so consider all possible states
if ( IsPaused() )
Resume();
if ( IsRunning() )
{
if ( IsMain() )
{
// set flag for wxIsWaitingForThread()
s_waitingForThread = TRUE;
wxBeginBusyCursor();
}
HANDLE hThread;
{
wxCriticalSectionLocker lock(m_critsect);
p_internal->Cancel();
hThread = p_internal->GetHandle();
}
// we can't just wait for the thread to terminate because it might be
// calling some GUI functions and so it will never terminate before we
// process the Windows messages that result from these functions
DWORD result;
do
{
result = ::MsgWaitForMultipleObjects
(
1, // number of objects to wait for
&hThread, // the objects
FALSE, // don't wait for all objects
INFINITE, // no timeout
QS_ALLEVENTS // return as soon as there are any events
);
switch ( result )
{
case 0xFFFFFFFF:
// error
wxLogSysError(_("Can not wait for thread termination"));
Kill();
return (ExitCode)-1;
case WAIT_OBJECT_0:
// thread we're waiting for terminated
break;
case WAIT_OBJECT_0 + 1:
// new message arrived, process it
if ( !wxTheApp->DoMessage() )
{
// WM_QUIT received: kill the thread
Kill();
return (ExitCode)-1;
}
if ( IsMain() )
{
// give the thread we're waiting for chance to exit
// from the GUI call it might have been in
if ( (s_nWaitingForGui > 0) && wxGuiOwnedByMainThread() )
{
wxMutexGuiLeave();
}
}
break;
default:
wxFAIL_MSG("unexpected result of MsgWaitForMultipleObject");
}
} while ( result != WAIT_OBJECT_0 );
if ( IsMain() )
{
s_waitingForThread = FALSE;
wxEndBusyCursor();
}
if ( !::GetExitCodeThread(hThread, (LPDWORD)&rc) )
{
wxLogLastError("GetExitCodeThread");
rc = (ExitCode)-1;
}
wxASSERT_MSG( (LPVOID)rc != (LPVOID)STILL_ACTIVE,
"thread must be already terminated." );
::CloseHandle(hThread);
}
return rc;
}
wxThreadError wxThread::Kill()
{
if ( !IsRunning() )
return wxTHREAD_NOT_RUNNING;
if ( !::TerminateThread(p_internal->GetHandle(), (DWORD)-1) )
{
wxLogSysError(_("Couldn't terminate thread"));
return wxTHREAD_MISC_ERROR;
}
delete this;
return wxTHREAD_NO_ERROR;
}
void wxThread::Exit(void *status)
{
delete this;
::ExitThread((DWORD)status);
wxFAIL_MSG("Couldn't return from ExitThread()!");
}
void wxThread::SetPriority(unsigned int prio)
{
wxCriticalSectionLocker lock(m_critsect);
p_internal->SetPriority(prio);
}
unsigned int wxThread::GetPriority() const
{
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
return p_internal->GetPriority();
}
unsigned long wxThread::GetID() const
{
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
return (unsigned long)p_internal->GetId();
}
bool wxThread::IsRunning() const
{
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
return p_internal->GetState() == STATE_RUNNING;
}
bool wxThread::IsAlive() const
{
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
return (p_internal->GetState() == STATE_RUNNING) ||
(p_internal->GetState() == STATE_PAUSED);
}
bool wxThread::TestDestroy() const
{
wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect);
return p_internal->GetState() == STATE_CANCELED;
}
wxThread::wxThread()
{
p_internal = new wxThreadInternal();
p_internal->defer = FALSE;
p_internal->prio = WXTHREAD_DEFAULT_PRIORITY;
p_internal->state = STATE_IDLE;
}
wxThread::~wxThread()
{
Destroy();
Join();
delete p_internal;
}
void wxThread::OnExit()
{
}
// ----------------------------------------------------------------------------
// Automatic initialization for thread module
// ----------------------------------------------------------------------------
@ -495,11 +695,39 @@ IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule)
bool wxThreadModule::OnInit()
{
// allocate TLS index for storing the pointer to the current thread
s_tlsThisThread = ::TlsAlloc();
if ( s_tlsThisThread == 0xFFFFFFFF )
{
// in normal circumstances it will only happen if all other
// TLS_MINIMUM_AVAILABLE (>= 64) indices are already taken - in other
// words, this should never happen
wxLogSysError(_("Thread module initialization failed: "
"impossible to allocate index in thread "
"local storage"));
return FALSE;
}
// main thread doesn't have associated wxThread object, so store 0 in the
// TLS instead
if ( !::TlsSetValue(s_tlsThisThread, (LPVOID)0) )
{
::TlsFree(s_tlsThisThread);
s_tlsThisThread = 0xFFFFFFFF;
wxLogSysError(_("Thread module initialization failed: "
"can not store value in thread local storage"));
return FALSE;
}
s_critsectWaitingForGui = new wxCriticalSection();
s_critsectGui = new wxCriticalSection();
s_critsectGui->Enter();
// no error return for GetCurrentThreadId()
s_idMainThread = ::GetCurrentThreadId();
return TRUE;
@ -507,6 +735,11 @@ bool wxThreadModule::OnInit()
void wxThreadModule::OnExit()
{
if ( !::TlsFree(s_tlsThisThread) )
{
wxLogLastError("TlsFree failed.");
}
if ( s_critsectGui )
{
s_critsectGui->Leave();
@ -612,4 +845,9 @@ void WXDLLEXPORT wxWakeUpMainThread()
}
}
bool WXDLLEXPORT wxIsWaitingForThread()
{
return s_waitingForThread;
}
#endif // wxUSE_THREADS