From: Vadim Zeitlin Date: Sat, 6 Mar 1999 00:04:53 +0000 (+0000) Subject: this code is now common (src/unix) X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/cf6c13a14fc3797171d5e90c211b229095adfe97 this code is now common (src/unix) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1866 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/src/gtk/threadgui.inc b/src/gtk/threadgui.inc deleted file mode 100644 index 1717b172f6..0000000000 --- a/src/gtk/threadgui.inc +++ /dev/null @@ -1,80 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: threadgui.inc -// Purpose: GUI thread manager for GTK -// Author: Original from Wolfram Gloger/Guilhem Lavaux -// Modified by: -// Created: 04/22/98 -// RCS-ID: $Id$ -// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998) -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include -#include - -// for select() -#include -#include -#ifdef __sgi -#include -#endif - -#include - -///////////////////////////////////////////////////////////////////////////// -// Static variables -///////////////////////////////////////////////////////////////////////////// - -static int p_thrd_pipe[2] = { -1, -1 }; -// WorkProc in GTK -static gint p_thrd_inid; - -#define THREAD_SEND_EXIT_MSG(ptr) write(p_thrd_pipe[1], &ptr, sizeof(ptr)); - -static void -ThreadExitProc(gpointer WXUNUSED(client), gint fid, - GdkInputCondition WXUNUSED(cond)) -{ - wxThread* ptr; - - // printf( "thread exit proc.\n" ); - - if (fid != p_thrd_pipe[0]) - return; - - if (read(fid, &ptr, sizeof(ptr)) == sizeof(ptr)) - { - // printf( "calling OnExit %p\n", ptr); - ptr->OnExit(); - } - else - { - // printf( "this should never happen\n" ); - } -} - -// Global initialization -static void wxThreadGuiInit() -{ - pipe(p_thrd_pipe); - p_thrd_inid = gdk_input_add(p_thrd_pipe[0], GDK_INPUT_READ, - ThreadExitProc, 0); -} - -// Global cleanup -static void wxThreadGuiExit() -{ - gdk_input_remove(p_thrd_inid); - close(p_thrd_pipe[0]); - close(p_thrd_pipe[1]); -} - -void wxMutexGuiEnter() -{ - gs_mutexGui->Lock(); -} - -void wxMutexGuiLeave() -{ - gs_mutexGui->Unlock(); -} diff --git a/src/gtk/threadpsx.cpp b/src/gtk/threadpsx.cpp deleted file mode 100644 index faf1421929..0000000000 --- a/src/gtk/threadpsx.cpp +++ /dev/null @@ -1,753 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: threadpsx.cpp -// Purpose: wxThread (Posix) Implementation -// Author: Original from Wolfram Gloger/Guilhem Lavaux -// Modified by: -// Created: 04/22/98 -// RCS-ID: $Id$ -// Copyright: (c) Wolfram Gloger (1996, 1997) -// Guilhem Lavaux (1998) -// Robert Roebling (1999) -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#ifdef __GNUG__ - #pragma implementation "thread.h" -#endif - -#include -#include -#include -#include - -#ifdef __linux__ - #include -#endif - -#include "wx/thread.h" -#include "wx/module.h" -#include "wx/utils.h" -#include "wx/log.h" -#include "wx/intl.h" -#include "wx/dynarray.h" - -#include "gdk/gdk.h" -#include "gtk/gtk.h" - -enum thread_state -{ - STATE_NEW, // didn't start execution yet (=> RUNNING) - STATE_RUNNING, - STATE_PAUSED, - STATE_CANCELED, - STATE_EXITED -}; - -WX_DEFINE_ARRAY(wxThread *, wxArrayThread); - -// ----------------------------------------------------------------------------- -// global data -// ----------------------------------------------------------------------------- - -// we keep the list of all threads created by the application to be able to -// terminate them on exit if there are some left - otherwise the process would -// be left in memory -static wxArrayThread gs_allThreads; - -// the id of the main thread -static pthread_t gs_tidMain; - -// the key for the pointer to the associated wxThread object -static pthread_key_t gs_keySelf; - -// this mutex must be acquired before any call to a GUI function -static wxMutex *gs_mutexGui; - -//-------------------------------------------------------------------- -// common GUI thread code -//-------------------------------------------------------------------- - -#include "threadgui.inc" - -//-------------------------------------------------------------------- -// wxMutex (Posix implementation) -//-------------------------------------------------------------------- - -class wxMutexInternal -{ -public: - pthread_mutex_t p_mutex; -}; - -wxMutex::wxMutex() -{ - p_internal = new wxMutexInternal; - pthread_mutex_init( &(p_internal->p_mutex), (const pthread_mutexattr_t*) NULL ); - m_locked = 0; -} - -wxMutex::~wxMutex() -{ - if (m_locked > 0) - wxLogDebug("Freeing a locked mutex (%d locks)", m_locked); - - pthread_mutex_destroy( &(p_internal->p_mutex) ); - delete p_internal; -} - -wxMutexError wxMutex::Lock() -{ - int err = pthread_mutex_lock( &(p_internal->p_mutex) ); - if (err == EDEADLK) - { - wxLogDebug("Locking this mutex would lead to deadlock!"); - - return wxMUTEX_DEAD_LOCK; - } - - m_locked++; - - return wxMUTEX_NO_ERROR; -} - -wxMutexError wxMutex::TryLock() -{ - if (m_locked) - { - return wxMUTEX_BUSY; - } - - int err = pthread_mutex_trylock( &(p_internal->p_mutex) ); - switch (err) - { - case EBUSY: return wxMUTEX_BUSY; - } - - m_locked++; - - return wxMUTEX_NO_ERROR; -} - -wxMutexError wxMutex::Unlock() -{ - if (m_locked > 0) - { - m_locked--; - } - else - { - wxLogDebug("Unlocking not locked mutex."); - - return wxMUTEX_UNLOCKED; - } - - pthread_mutex_unlock( &(p_internal->p_mutex) ); - - return wxMUTEX_NO_ERROR; -} - -//-------------------------------------------------------------------- -// wxCondition (Posix implementation) -//-------------------------------------------------------------------- - -class wxConditionInternal -{ -public: - pthread_cond_t p_condition; -}; - -wxCondition::wxCondition() -{ - p_internal = new wxConditionInternal; - pthread_cond_init( &(p_internal->p_condition), (const pthread_condattr_t *) NULL ); -} - -wxCondition::~wxCondition() -{ - pthread_cond_destroy( &(p_internal->p_condition) ); - - delete p_internal; -} - -void wxCondition::Wait(wxMutex& mutex) -{ - pthread_cond_wait( &(p_internal->p_condition), &(mutex.p_internal->p_mutex) ); -} - -bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec) -{ - struct timespec tspec; - - tspec.tv_sec = time(0L)+sec; - tspec.tv_nsec = nsec; - return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT); -} - -void wxCondition::Signal() -{ - pthread_cond_signal( &(p_internal->p_condition) ); -} - -void wxCondition::Broadcast() -{ - pthread_cond_broadcast( &(p_internal->p_condition) ); -} - -//-------------------------------------------------------------------- -// wxThread (Posix implementation) -//-------------------------------------------------------------------- - -class wxThreadInternal -{ -public: - wxThreadInternal(); - ~wxThreadInternal(); - - // thread entry function - static void *PthreadStart(void *ptr); - - // thread actions - // start the thread - wxThreadError Run(); - // ask the thread to terminate - void Cancel(); - // wake up threads waiting for our termination - void SignalExit(); - // go to sleep until Resume() is called - void Pause(); - // resume the thread - void Resume(); - - // accessors - // priority - int GetPriority() const { return m_prio; } - void SetPriority(int prio) { m_prio = prio; } - // state - thread_state GetState() const { return m_state; } - void SetState(thread_state state) { m_state = state; } - // id - pthread_t GetId() const { return thread_id; } - // "cancelled" flag - bool WasCancelled() const { return m_cancelled; } - -//private: -- should be! - pthread_t thread_id; - -private: - thread_state m_state; // see thread_state enum - int m_prio; // in wxWindows units: from 0 to 100 - - // set when the thread should terminate - bool m_cancelled; - - // this (mutex, cond) pair is used to synchronize the main thread and this - // thread in several situations: - // 1. The thread function blocks until condition is signaled by Run() when - // it's initially created - this allows create thread in "suspended" - // state - // 2. The Delete() function blocks until the condition is signaled when the - // thread exits. - wxMutex m_mutex; - wxCondition m_cond; - - // another (mutex, cond) pair for Pause()/Resume() usage - // - // VZ: it's possible that we might reuse the mutex and condition from above - // for this too, but as I'm not at all sure that it won't create subtle - // problems with race conditions between, say, Pause() and Delete() I - // prefer this may be a bit less efficient but much safer solution - wxMutex m_mutexSuspend; - wxCondition m_condSuspend; -}; - -void *wxThreadInternal::PthreadStart(void *ptr) -{ - wxThread *thread = (wxThread *)ptr; - wxThreadInternal *pthread = thread->p_internal; - - if ( pthread_setspecific(gs_keySelf, thread) != 0 ) - { - wxLogError(_("Can not start thread: error writing TLS.")); - - return (void *)-1; - } - - // wait for the condition to be signaled from Run() - // mutex state: currently locked by the thread which created us - pthread->m_cond.Wait(pthread->m_mutex); - - // mutex state: locked again on exit of Wait() - - // call the main entry - void* status = thread->Entry(); - - // terminate the thread - thread->Exit(status); - - wxFAIL_MSG("wxThread::Exit() can't return."); - - return NULL; -} - -wxThreadInternal::wxThreadInternal() -{ - m_state = STATE_NEW; - m_cancelled = FALSE; - - // this mutex is locked during almost all thread lifetime - it will only be - // unlocked in the very end - m_mutex.Lock(); - - // this mutex is used in Pause()/Resume() and is also locked all the time - // unless the thread is paused - m_mutexSuspend.Lock(); -} - -wxThreadInternal::~wxThreadInternal() -{ - m_mutexSuspend.Unlock(); - - // note that m_mutex will be unlocked by the thread which waits for our - // termination -} - -wxThreadError wxThreadInternal::Run() -{ - wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING, - "thread may only be started once after successful Create()" ); - - // the mutex was locked on Create(), so we will be able to lock it again - // only when the thread really starts executing and enters the wait - - // otherwise we might signal the condition before anybody is waiting for it - wxMutexLocker lock(m_mutex); - m_cond.Signal(); - - m_state = STATE_RUNNING; - - return wxTHREAD_NO_ERROR; - - // now the mutex is unlocked back - but just to allow Wait() function to - // terminate by relocking it, so the net result is that the worker thread - // starts executing and the mutex is still locked -} - -void wxThreadInternal::Cancel() -{ - // if the thread we're waiting for is waiting for the GUI mutex, we will - // deadlock so make sure we release it temporarily - if ( wxThread::IsMain() ) - wxMutexGuiLeave(); - - // nobody ever writes this variable so it's safe to not use any - // synchronization here - m_cancelled = TRUE; - - // entering Wait() releases the mutex thus allowing SignalExit() to acquire - // it and to signal us its termination - m_cond.Wait(m_mutex); - - // mutex is still in the locked state - relocked on exit from Wait(), so - // unlock it - we don't need it any more, the thread has already terminated - m_mutex.Unlock(); - - // reacquire GUI mutex - if ( wxThread::IsMain() ) - wxMutexGuiEnter(); -} - -void wxThreadInternal::SignalExit() -{ - // as mutex is currently locked, this will block until some other thread - // (normally the same which created this one) unlocks it by entering Wait() - m_mutex.Lock(); - - // wake up all the threads waiting for our termination - m_cond.Broadcast(); - - // after this call mutex will be finally unlocked - m_mutex.Unlock(); -} - -void wxThreadInternal::Pause() -{ - wxCHECK_RET( m_state == STATE_PAUSED, - "thread must first be paused with wxThread::Pause()." ); - - // wait until the condition is signaled from Resume() - m_condSuspend.Wait(m_mutexSuspend); -} - -void wxThreadInternal::Resume() -{ - wxCHECK_RET( m_state == STATE_PAUSED, - "can't resume thread which is not suspended." ); - - // we will be able to lock this mutex only when Pause() starts waiting - wxMutexLocker lock(m_mutexSuspend); - m_condSuspend.Signal(); - - SetState(STATE_RUNNING); -} - -// ----------------------------------------------------------------------------- -// static functions -// ----------------------------------------------------------------------------- - -wxThread *wxThread::This() -{ - return (wxThread *)pthread_getspecific(gs_keySelf); -} - -bool wxThread::IsMain() -{ - return (bool)pthread_equal(pthread_self(), gs_tidMain); -} - -void wxThread::Yield() -{ -#ifdef HAVE_SCHED_YIELD - sched_yield(); -#else // !HAVE_SCHED_YIELD - // may be it will have the desired effect? - Sleep(0); -#endif // HAVE_SCHED_YIELD -} - -void wxThread::Sleep(unsigned long milliseconds) -{ - wxUsleep(milliseconds); -} - -// ----------------------------------------------------------------------------- -// creating thread -// ----------------------------------------------------------------------------- - -wxThread::wxThread() -{ - // add this thread to the global list of all threads - gs_allThreads.Add(this); - - p_internal = new wxThreadInternal(); -} - -wxThreadError wxThread::Create() -{ - if (p_internal->GetState() != STATE_NEW) - return wxTHREAD_RUNNING; - - // set up the thread attribute: right now, we only set thread priority - pthread_attr_t attr; - pthread_attr_init(&attr); - -#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS - int prio; - if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 ) - { - wxLogError(_("Can not retrieve thread scheduling policy.")); - } - - int min_prio = sched_get_priority_min(prio), - max_prio = sched_get_priority_max(prio); - - if ( min_prio == -1 || max_prio == -1 ) - { - wxLogError(_("Can not get priority range for scheduling policy %d."), - prio); - } - else - { - struct sched_param sp; - pthread_attr_getschedparam(&attr, &sp); - sp.sched_priority = min_prio + - (p_internal->GetPriority()*(max_prio-min_prio))/100; - pthread_attr_setschedparam(&attr, &sp); - } -#endif // HAVE_THREAD_PRIORITY_FUNCTIONS - - // create the new OS thread object - int rc = pthread_create(&p_internal->thread_id, &attr, - wxThreadInternal::PthreadStart, (void *)this); - pthread_attr_destroy(&attr); - - if ( rc != 0 ) - { - p_internal->SetState(STATE_EXITED); - return wxTHREAD_NO_RESOURCE; - } - - return wxTHREAD_NO_ERROR; -} - -wxThreadError wxThread::Run() -{ - return p_internal->Run(); -} - -// ----------------------------------------------------------------------------- -// misc accessors -// ----------------------------------------------------------------------------- - -void wxThread::SetPriority(unsigned int prio) -{ - wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY <= (int)prio) && - ((int)prio <= (int)WXTHREAD_MAX_PRIORITY), - "invalid thread priority" ); - - wxCriticalSectionLocker lock(m_critsect); - - switch ( p_internal->GetState() ) - { - case STATE_NEW: - // thread not yet started, priority will be set when it is - p_internal->SetPriority(prio); - break; - - case STATE_RUNNING: - case STATE_PAUSED: -#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS - { - struct sched_param sparam; - sparam.sched_priority = prio; - - if ( pthread_setschedparam(p_internal->GetId(), - SCHED_OTHER, &sparam) != 0 ) - { - wxLogError(_("Failed to set thread priority %d."), prio); - } - } -#endif // HAVE_THREAD_PRIORITY_FUNCTIONS - break; - - case STATE_EXITED: - default: - wxFAIL_MSG("impossible to set thread priority in this state"); - } -} - -unsigned int wxThread::GetPriority() const -{ - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - - return p_internal->GetPriority(); -} - -unsigned long wxThread::GetID() const -{ - return (unsigned long)p_internal->thread_id; -} - -// ----------------------------------------------------------------------------- -// pause/resume -// ----------------------------------------------------------------------------- - -wxThreadError wxThread::Pause() -{ - wxCriticalSectionLocker lock(m_critsect); - - if ( p_internal->GetState() != STATE_RUNNING ) - { - wxLogDebug("Can't pause thread which is not running."); - - return wxTHREAD_NOT_RUNNING; - } - - p_internal->SetState(STATE_PAUSED); - - return wxTHREAD_NO_ERROR; -} - -wxThreadError wxThread::Resume() -{ - wxCriticalSectionLocker lock(m_critsect); - - if ( p_internal->GetState() == STATE_PAUSED ) - { - p_internal->Resume(); - - return wxTHREAD_NO_ERROR; - } - else - { - wxLogDebug("Attempt to resume a thread which is not paused."); - - return wxTHREAD_MISC_ERROR; - } -} - -// ----------------------------------------------------------------------------- -// exiting thread -// ----------------------------------------------------------------------------- - -wxThread::ExitCode wxThread::Delete() -{ - m_critsect.Enter(); - thread_state state = p_internal->GetState(); - m_critsect.Leave(); - - switch ( state ) - { - case STATE_NEW: - case STATE_EXITED: - // nothing to do - break; - - case STATE_PAUSED: - // resume the thread first - Resume(); - - // fall through - - default: - // set the flag telling to the thread to stop and wait - p_internal->Cancel(); - } - - return NULL; -} - -wxThreadError wxThread::Kill() -{ - switch ( p_internal->GetState() ) - { - case STATE_NEW: - case STATE_EXITED: - return wxTHREAD_NOT_RUNNING; - - default: -#ifdef HAVE_PTHREAD_CANCEL - if ( pthread_cancel(p_internal->GetId()) != 0 ) -#endif - { - wxLogError(_("Failed to terminate a thread.")); - - return wxTHREAD_MISC_ERROR; - } - - return wxTHREAD_NO_ERROR; - } -} - -void wxThread::Exit(void *status) -{ - // first call user-level clean up code - OnExit(); - - // next wake up the threads waiting for us (OTOH, this function won't return - // until someone waited for us!) - p_internal->SignalExit(); - - p_internal->SetState(STATE_EXITED); - - // delete both C++ thread object and terminate the OS thread object - delete this; - pthread_exit(status); -} - -// also test whether we were paused -bool wxThread::TestDestroy() -{ - wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect); - - if ( p_internal->GetState() == STATE_PAUSED ) - { - // leave the crit section or the other threads will stop too if they try - // to call any of (seemingly harmless) IsXXX() functions while we sleep - m_critsect.Leave(); - - p_internal->Pause(); - - // enter it back before it's finally left in lock object dtor - m_critsect.Enter(); - } - - return p_internal->WasCancelled(); -} - -wxThread::~wxThread() -{ - // remove this thread from the global array - gs_allThreads.Remove(this); -} - -// ----------------------------------------------------------------------------- -// state tests -// ----------------------------------------------------------------------------- - -bool wxThread::IsRunning() const -{ - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - - return p_internal->GetState() == STATE_RUNNING; -} - -bool wxThread::IsAlive() const -{ - wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect); - - switch ( p_internal->GetState() ) - { - case STATE_RUNNING: - case STATE_PAUSED: - return TRUE; - - default: - return FALSE; - } -} - -//-------------------------------------------------------------------- -// wxThreadModule -//-------------------------------------------------------------------- - -class wxThreadModule : public wxModule -{ -public: - virtual bool OnInit(); - virtual void OnExit(); - -private: - DECLARE_DYNAMIC_CLASS(wxThreadModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) - -bool wxThreadModule::OnInit() -{ - if ( pthread_key_create(&gs_keySelf, NULL /* dtor function */) != 0 ) - { - wxLogError(_("Thread module initialization failed: " - "failed to create pthread key.")); - - return FALSE; - } - - gs_mutexGui = new wxMutex(); - wxThreadGuiInit(); - gs_tidMain = pthread_self(); - gs_mutexGui->Lock(); - - return TRUE; -} - -void wxThreadModule::OnExit() -{ - wxASSERT_MSG( wxThread::IsMain(), "only main thread can be here" ); - - // terminate any threads left - size_t count = gs_allThreads.GetCount(); - if ( count != 0u ) - wxLogDebug("Some threads were not terminated by the application."); - - for ( size_t n = 0u; n < count; n++ ) - { - gs_allThreads[n]->Delete(); - } - - // destroy GUI mutex - gs_mutexGui->Unlock(); - wxThreadGuiExit(); - delete gs_mutexGui; - - // and free TLD slot - (void)pthread_key_delete(gs_keySelf); -} diff --git a/src/gtk1/threadgui.inc b/src/gtk1/threadgui.inc deleted file mode 100644 index 1717b172f6..0000000000 --- a/src/gtk1/threadgui.inc +++ /dev/null @@ -1,80 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: threadgui.inc -// Purpose: GUI thread manager for GTK -// Author: Original from Wolfram Gloger/Guilhem Lavaux -// Modified by: -// Created: 04/22/98 -// RCS-ID: $Id$ -// Copyright: (c) Wolfram Gloger (1996, 1997); Guilhem Lavaux (1998) -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include -#include - -// for select() -#include -#include -#ifdef __sgi -#include -#endif - -#include - -///////////////////////////////////////////////////////////////////////////// -// Static variables -///////////////////////////////////////////////////////////////////////////// - -static int p_thrd_pipe[2] = { -1, -1 }; -// WorkProc in GTK -static gint p_thrd_inid; - -#define THREAD_SEND_EXIT_MSG(ptr) write(p_thrd_pipe[1], &ptr, sizeof(ptr)); - -static void -ThreadExitProc(gpointer WXUNUSED(client), gint fid, - GdkInputCondition WXUNUSED(cond)) -{ - wxThread* ptr; - - // printf( "thread exit proc.\n" ); - - if (fid != p_thrd_pipe[0]) - return; - - if (read(fid, &ptr, sizeof(ptr)) == sizeof(ptr)) - { - // printf( "calling OnExit %p\n", ptr); - ptr->OnExit(); - } - else - { - // printf( "this should never happen\n" ); - } -} - -// Global initialization -static void wxThreadGuiInit() -{ - pipe(p_thrd_pipe); - p_thrd_inid = gdk_input_add(p_thrd_pipe[0], GDK_INPUT_READ, - ThreadExitProc, 0); -} - -// Global cleanup -static void wxThreadGuiExit() -{ - gdk_input_remove(p_thrd_inid); - close(p_thrd_pipe[0]); - close(p_thrd_pipe[1]); -} - -void wxMutexGuiEnter() -{ - gs_mutexGui->Lock(); -} - -void wxMutexGuiLeave() -{ - gs_mutexGui->Unlock(); -} diff --git a/src/gtk1/threadpsx.cpp b/src/gtk1/threadpsx.cpp deleted file mode 100644 index faf1421929..0000000000 --- a/src/gtk1/threadpsx.cpp +++ /dev/null @@ -1,753 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: threadpsx.cpp -// Purpose: wxThread (Posix) Implementation -// Author: Original from Wolfram Gloger/Guilhem Lavaux -// Modified by: -// Created: 04/22/98 -// RCS-ID: $Id$ -// Copyright: (c) Wolfram Gloger (1996, 1997) -// Guilhem Lavaux (1998) -// Robert Roebling (1999) -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#ifdef __GNUG__ - #pragma implementation "thread.h" -#endif - -#include -#include -#include -#include - -#ifdef __linux__ - #include -#endif - -#include "wx/thread.h" -#include "wx/module.h" -#include "wx/utils.h" -#include "wx/log.h" -#include "wx/intl.h" -#include "wx/dynarray.h" - -#include "gdk/gdk.h" -#include "gtk/gtk.h" - -enum thread_state -{ - STATE_NEW, // didn't start execution yet (=> RUNNING) - STATE_RUNNING, - STATE_PAUSED, - STATE_CANCELED, - STATE_EXITED -}; - -WX_DEFINE_ARRAY(wxThread *, wxArrayThread); - -// ----------------------------------------------------------------------------- -// global data -// ----------------------------------------------------------------------------- - -// we keep the list of all threads created by the application to be able to -// terminate them on exit if there are some left - otherwise the process would -// be left in memory -static wxArrayThread gs_allThreads; - -// the id of the main thread -static pthread_t gs_tidMain; - -// the key for the pointer to the associated wxThread object -static pthread_key_t gs_keySelf; - -// this mutex must be acquired before any call to a GUI function -static wxMutex *gs_mutexGui; - -//-------------------------------------------------------------------- -// common GUI thread code -//-------------------------------------------------------------------- - -#include "threadgui.inc" - -//-------------------------------------------------------------------- -// wxMutex (Posix implementation) -//-------------------------------------------------------------------- - -class wxMutexInternal -{ -public: - pthread_mutex_t p_mutex; -}; - -wxMutex::wxMutex() -{ - p_internal = new wxMutexInternal; - pthread_mutex_init( &(p_internal->p_mutex), (const pthread_mutexattr_t*) NULL ); - m_locked = 0; -} - -wxMutex::~wxMutex() -{ - if (m_locked > 0) - wxLogDebug("Freeing a locked mutex (%d locks)", m_locked); - - pthread_mutex_destroy( &(p_internal->p_mutex) ); - delete p_internal; -} - -wxMutexError wxMutex::Lock() -{ - int err = pthread_mutex_lock( &(p_internal->p_mutex) ); - if (err == EDEADLK) - { - wxLogDebug("Locking this mutex would lead to deadlock!"); - - return wxMUTEX_DEAD_LOCK; - } - - m_locked++; - - return wxMUTEX_NO_ERROR; -} - -wxMutexError wxMutex::TryLock() -{ - if (m_locked) - { - return wxMUTEX_BUSY; - } - - int err = pthread_mutex_trylock( &(p_internal->p_mutex) ); - switch (err) - { - case EBUSY: return wxMUTEX_BUSY; - } - - m_locked++; - - return wxMUTEX_NO_ERROR; -} - -wxMutexError wxMutex::Unlock() -{ - if (m_locked > 0) - { - m_locked--; - } - else - { - wxLogDebug("Unlocking not locked mutex."); - - return wxMUTEX_UNLOCKED; - } - - pthread_mutex_unlock( &(p_internal->p_mutex) ); - - return wxMUTEX_NO_ERROR; -} - -//-------------------------------------------------------------------- -// wxCondition (Posix implementation) -//-------------------------------------------------------------------- - -class wxConditionInternal -{ -public: - pthread_cond_t p_condition; -}; - -wxCondition::wxCondition() -{ - p_internal = new wxConditionInternal; - pthread_cond_init( &(p_internal->p_condition), (const pthread_condattr_t *) NULL ); -} - -wxCondition::~wxCondition() -{ - pthread_cond_destroy( &(p_internal->p_condition) ); - - delete p_internal; -} - -void wxCondition::Wait(wxMutex& mutex) -{ - pthread_cond_wait( &(p_internal->p_condition), &(mutex.p_internal->p_mutex) ); -} - -bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec) -{ - struct timespec tspec; - - tspec.tv_sec = time(0L)+sec; - tspec.tv_nsec = nsec; - return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT); -} - -void wxCondition::Signal() -{ - pthread_cond_signal( &(p_internal->p_condition) ); -} - -void wxCondition::Broadcast() -{ - pthread_cond_broadcast( &(p_internal->p_condition) ); -} - -//-------------------------------------------------------------------- -// wxThread (Posix implementation) -//-------------------------------------------------------------------- - -class wxThreadInternal -{ -public: - wxThreadInternal(); - ~wxThreadInternal(); - - // thread entry function - static void *PthreadStart(void *ptr); - - // thread actions - // start the thread - wxThreadError Run(); - // ask the thread to terminate - void Cancel(); - // wake up threads waiting for our termination - void SignalExit(); - // go to sleep until Resume() is called - void Pause(); - // resume the thread - void Resume(); - - // accessors - // priority - int GetPriority() const { return m_prio; } - void SetPriority(int prio) { m_prio = prio; } - // state - thread_state GetState() const { return m_state; } - void SetState(thread_state state) { m_state = state; } - // id - pthread_t GetId() const { return thread_id; } - // "cancelled" flag - bool WasCancelled() const { return m_cancelled; } - -//private: -- should be! - pthread_t thread_id; - -private: - thread_state m_state; // see thread_state enum - int m_prio; // in wxWindows units: from 0 to 100 - - // set when the thread should terminate - bool m_cancelled; - - // this (mutex, cond) pair is used to synchronize the main thread and this - // thread in several situations: - // 1. The thread function blocks until condition is signaled by Run() when - // it's initially created - this allows create thread in "suspended" - // state - // 2. The Delete() function blocks until the condition is signaled when the - // thread exits. - wxMutex m_mutex; - wxCondition m_cond; - - // another (mutex, cond) pair for Pause()/Resume() usage - // - // VZ: it's possible that we might reuse the mutex and condition from above - // for this too, but as I'm not at all sure that it won't create subtle - // problems with race conditions between, say, Pause() and Delete() I - // prefer this may be a bit less efficient but much safer solution - wxMutex m_mutexSuspend; - wxCondition m_condSuspend; -}; - -void *wxThreadInternal::PthreadStart(void *ptr) -{ - wxThread *thread = (wxThread *)ptr; - wxThreadInternal *pthread = thread->p_internal; - - if ( pthread_setspecific(gs_keySelf, thread) != 0 ) - { - wxLogError(_("Can not start thread: error writing TLS.")); - - return (void *)-1; - } - - // wait for the condition to be signaled from Run() - // mutex state: currently locked by the thread which created us - pthread->m_cond.Wait(pthread->m_mutex); - - // mutex state: locked again on exit of Wait() - - // call the main entry - void* status = thread->Entry(); - - // terminate the thread - thread->Exit(status); - - wxFAIL_MSG("wxThread::Exit() can't return."); - - return NULL; -} - -wxThreadInternal::wxThreadInternal() -{ - m_state = STATE_NEW; - m_cancelled = FALSE; - - // this mutex is locked during almost all thread lifetime - it will only be - // unlocked in the very end - m_mutex.Lock(); - - // this mutex is used in Pause()/Resume() and is also locked all the time - // unless the thread is paused - m_mutexSuspend.Lock(); -} - -wxThreadInternal::~wxThreadInternal() -{ - m_mutexSuspend.Unlock(); - - // note that m_mutex will be unlocked by the thread which waits for our - // termination -} - -wxThreadError wxThreadInternal::Run() -{ - wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING, - "thread may only be started once after successful Create()" ); - - // the mutex was locked on Create(), so we will be able to lock it again - // only when the thread really starts executing and enters the wait - - // otherwise we might signal the condition before anybody is waiting for it - wxMutexLocker lock(m_mutex); - m_cond.Signal(); - - m_state = STATE_RUNNING; - - return wxTHREAD_NO_ERROR; - - // now the mutex is unlocked back - but just to allow Wait() function to - // terminate by relocking it, so the net result is that the worker thread - // starts executing and the mutex is still locked -} - -void wxThreadInternal::Cancel() -{ - // if the thread we're waiting for is waiting for the GUI mutex, we will - // deadlock so make sure we release it temporarily - if ( wxThread::IsMain() ) - wxMutexGuiLeave(); - - // nobody ever writes this variable so it's safe to not use any - // synchronization here - m_cancelled = TRUE; - - // entering Wait() releases the mutex thus allowing SignalExit() to acquire - // it and to signal us its termination - m_cond.Wait(m_mutex); - - // mutex is still in the locked state - relocked on exit from Wait(), so - // unlock it - we don't need it any more, the thread has already terminated - m_mutex.Unlock(); - - // reacquire GUI mutex - if ( wxThread::IsMain() ) - wxMutexGuiEnter(); -} - -void wxThreadInternal::SignalExit() -{ - // as mutex is currently locked, this will block until some other thread - // (normally the same which created this one) unlocks it by entering Wait() - m_mutex.Lock(); - - // wake up all the threads waiting for our termination - m_cond.Broadcast(); - - // after this call mutex will be finally unlocked - m_mutex.Unlock(); -} - -void wxThreadInternal::Pause() -{ - wxCHECK_RET( m_state == STATE_PAUSED, - "thread must first be paused with wxThread::Pause()." ); - - // wait until the condition is signaled from Resume() - m_condSuspend.Wait(m_mutexSuspend); -} - -void wxThreadInternal::Resume() -{ - wxCHECK_RET( m_state == STATE_PAUSED, - "can't resume thread which is not suspended." ); - - // we will be able to lock this mutex only when Pause() starts waiting - wxMutexLocker lock(m_mutexSuspend); - m_condSuspend.Signal(); - - SetState(STATE_RUNNING); -} - -// ----------------------------------------------------------------------------- -// static functions -// ----------------------------------------------------------------------------- - -wxThread *wxThread::This() -{ - return (wxThread *)pthread_getspecific(gs_keySelf); -} - -bool wxThread::IsMain() -{ - return (bool)pthread_equal(pthread_self(), gs_tidMain); -} - -void wxThread::Yield() -{ -#ifdef HAVE_SCHED_YIELD - sched_yield(); -#else // !HAVE_SCHED_YIELD - // may be it will have the desired effect? - Sleep(0); -#endif // HAVE_SCHED_YIELD -} - -void wxThread::Sleep(unsigned long milliseconds) -{ - wxUsleep(milliseconds); -} - -// ----------------------------------------------------------------------------- -// creating thread -// ----------------------------------------------------------------------------- - -wxThread::wxThread() -{ - // add this thread to the global list of all threads - gs_allThreads.Add(this); - - p_internal = new wxThreadInternal(); -} - -wxThreadError wxThread::Create() -{ - if (p_internal->GetState() != STATE_NEW) - return wxTHREAD_RUNNING; - - // set up the thread attribute: right now, we only set thread priority - pthread_attr_t attr; - pthread_attr_init(&attr); - -#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS - int prio; - if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 ) - { - wxLogError(_("Can not retrieve thread scheduling policy.")); - } - - int min_prio = sched_get_priority_min(prio), - max_prio = sched_get_priority_max(prio); - - if ( min_prio == -1 || max_prio == -1 ) - { - wxLogError(_("Can not get priority range for scheduling policy %d."), - prio); - } - else - { - struct sched_param sp; - pthread_attr_getschedparam(&attr, &sp); - sp.sched_priority = min_prio + - (p_internal->GetPriority()*(max_prio-min_prio))/100; - pthread_attr_setschedparam(&attr, &sp); - } -#endif // HAVE_THREAD_PRIORITY_FUNCTIONS - - // create the new OS thread object - int rc = pthread_create(&p_internal->thread_id, &attr, - wxThreadInternal::PthreadStart, (void *)this); - pthread_attr_destroy(&attr); - - if ( rc != 0 ) - { - p_internal->SetState(STATE_EXITED); - return wxTHREAD_NO_RESOURCE; - } - - return wxTHREAD_NO_ERROR; -} - -wxThreadError wxThread::Run() -{ - return p_internal->Run(); -} - -// ----------------------------------------------------------------------------- -// misc accessors -// ----------------------------------------------------------------------------- - -void wxThread::SetPriority(unsigned int prio) -{ - wxCHECK_RET( ((int)WXTHREAD_MIN_PRIORITY <= (int)prio) && - ((int)prio <= (int)WXTHREAD_MAX_PRIORITY), - "invalid thread priority" ); - - wxCriticalSectionLocker lock(m_critsect); - - switch ( p_internal->GetState() ) - { - case STATE_NEW: - // thread not yet started, priority will be set when it is - p_internal->SetPriority(prio); - break; - - case STATE_RUNNING: - case STATE_PAUSED: -#ifdef HAVE_THREAD_PRIORITY_FUNCTIONS - { - struct sched_param sparam; - sparam.sched_priority = prio; - - if ( pthread_setschedparam(p_internal->GetId(), - SCHED_OTHER, &sparam) != 0 ) - { - wxLogError(_("Failed to set thread priority %d."), prio); - } - } -#endif // HAVE_THREAD_PRIORITY_FUNCTIONS - break; - - case STATE_EXITED: - default: - wxFAIL_MSG("impossible to set thread priority in this state"); - } -} - -unsigned int wxThread::GetPriority() const -{ - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - - return p_internal->GetPriority(); -} - -unsigned long wxThread::GetID() const -{ - return (unsigned long)p_internal->thread_id; -} - -// ----------------------------------------------------------------------------- -// pause/resume -// ----------------------------------------------------------------------------- - -wxThreadError wxThread::Pause() -{ - wxCriticalSectionLocker lock(m_critsect); - - if ( p_internal->GetState() != STATE_RUNNING ) - { - wxLogDebug("Can't pause thread which is not running."); - - return wxTHREAD_NOT_RUNNING; - } - - p_internal->SetState(STATE_PAUSED); - - return wxTHREAD_NO_ERROR; -} - -wxThreadError wxThread::Resume() -{ - wxCriticalSectionLocker lock(m_critsect); - - if ( p_internal->GetState() == STATE_PAUSED ) - { - p_internal->Resume(); - - return wxTHREAD_NO_ERROR; - } - else - { - wxLogDebug("Attempt to resume a thread which is not paused."); - - return wxTHREAD_MISC_ERROR; - } -} - -// ----------------------------------------------------------------------------- -// exiting thread -// ----------------------------------------------------------------------------- - -wxThread::ExitCode wxThread::Delete() -{ - m_critsect.Enter(); - thread_state state = p_internal->GetState(); - m_critsect.Leave(); - - switch ( state ) - { - case STATE_NEW: - case STATE_EXITED: - // nothing to do - break; - - case STATE_PAUSED: - // resume the thread first - Resume(); - - // fall through - - default: - // set the flag telling to the thread to stop and wait - p_internal->Cancel(); - } - - return NULL; -} - -wxThreadError wxThread::Kill() -{ - switch ( p_internal->GetState() ) - { - case STATE_NEW: - case STATE_EXITED: - return wxTHREAD_NOT_RUNNING; - - default: -#ifdef HAVE_PTHREAD_CANCEL - if ( pthread_cancel(p_internal->GetId()) != 0 ) -#endif - { - wxLogError(_("Failed to terminate a thread.")); - - return wxTHREAD_MISC_ERROR; - } - - return wxTHREAD_NO_ERROR; - } -} - -void wxThread::Exit(void *status) -{ - // first call user-level clean up code - OnExit(); - - // next wake up the threads waiting for us (OTOH, this function won't return - // until someone waited for us!) - p_internal->SignalExit(); - - p_internal->SetState(STATE_EXITED); - - // delete both C++ thread object and terminate the OS thread object - delete this; - pthread_exit(status); -} - -// also test whether we were paused -bool wxThread::TestDestroy() -{ - wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect); - - if ( p_internal->GetState() == STATE_PAUSED ) - { - // leave the crit section or the other threads will stop too if they try - // to call any of (seemingly harmless) IsXXX() functions while we sleep - m_critsect.Leave(); - - p_internal->Pause(); - - // enter it back before it's finally left in lock object dtor - m_critsect.Enter(); - } - - return p_internal->WasCancelled(); -} - -wxThread::~wxThread() -{ - // remove this thread from the global array - gs_allThreads.Remove(this); -} - -// ----------------------------------------------------------------------------- -// state tests -// ----------------------------------------------------------------------------- - -bool wxThread::IsRunning() const -{ - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - - return p_internal->GetState() == STATE_RUNNING; -} - -bool wxThread::IsAlive() const -{ - wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect); - - switch ( p_internal->GetState() ) - { - case STATE_RUNNING: - case STATE_PAUSED: - return TRUE; - - default: - return FALSE; - } -} - -//-------------------------------------------------------------------- -// wxThreadModule -//-------------------------------------------------------------------- - -class wxThreadModule : public wxModule -{ -public: - virtual bool OnInit(); - virtual void OnExit(); - -private: - DECLARE_DYNAMIC_CLASS(wxThreadModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) - -bool wxThreadModule::OnInit() -{ - if ( pthread_key_create(&gs_keySelf, NULL /* dtor function */) != 0 ) - { - wxLogError(_("Thread module initialization failed: " - "failed to create pthread key.")); - - return FALSE; - } - - gs_mutexGui = new wxMutex(); - wxThreadGuiInit(); - gs_tidMain = pthread_self(); - gs_mutexGui->Lock(); - - return TRUE; -} - -void wxThreadModule::OnExit() -{ - wxASSERT_MSG( wxThread::IsMain(), "only main thread can be here" ); - - // terminate any threads left - size_t count = gs_allThreads.GetCount(); - if ( count != 0u ) - wxLogDebug("Some threads were not terminated by the application."); - - for ( size_t n = 0u; n < count; n++ ) - { - gs_allThreads[n]->Delete(); - } - - // destroy GUI mutex - gs_mutexGui->Unlock(); - wxThreadGuiExit(); - delete gs_mutexGui; - - // and free TLD slot - (void)pthread_key_delete(gs_keySelf); -} diff --git a/src/motif/thread.cpp b/src/motif/thread.cpp deleted file mode 100644 index e0b042cff0..0000000000 --- a/src/motif/thread.cpp +++ /dev/null @@ -1,747 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: threadpsx.cpp -// Purpose: wxThread (Posix) Implementation -// Author: Original from Wolfram Gloger/Guilhem Lavaux -// Modified by: -// Created: 04/22/98 -// RCS-ID: $Id$ -// Copyright: (c) Wolfram Gloger (1996, 1997) -// Guilhem Lavaux (1998) -// Robert Roebling (1999) -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#ifdef __GNUG__ - #pragma implementation "thread.h" -#endif - -#include -#include -#include -#include - -#ifdef __linux__ - #include -#endif - -#include "wx/thread.h" -#include "wx/module.h" -#include "wx/utils.h" -#include "wx/log.h" -#include "wx/intl.h" -#include "wx/dynarray.h" - -enum thread_state -{ - STATE_NEW, // didn't start execution yet (=> RUNNING) - STATE_RUNNING, - STATE_PAUSED, - STATE_CANCELED, - STATE_EXITED -}; - -WX_DEFINE_ARRAY(wxThread *, wxArrayThread); - -// ----------------------------------------------------------------------------- -// global data -// ----------------------------------------------------------------------------- - -// we keep the list of all threads created by the application to be able to -// terminate them on exit if there are some left - otherwise the process would -// be left in memory -static wxArrayThread gs_allThreads; - -// the id of the main thread -static pthread_t gs_tidMain; - -// the key for the pointer to the associated wxThread object -static pthread_key_t gs_keySelf; - -// this mutex must be acquired before any call to a GUI function -static wxMutex *gs_mutexGui; - -//-------------------------------------------------------------------- -// common GUI thread code -//-------------------------------------------------------------------- - -//-------------------------------------------------------------------- -// wxMutex (Posix implementation) -//-------------------------------------------------------------------- - -class wxMutexInternal -{ -public: - pthread_mutex_t p_mutex; -}; - -wxMutex::wxMutex() -{ - p_internal = new wxMutexInternal; - pthread_mutex_init( &(p_internal->p_mutex), (const pthread_mutexattr_t*) NULL ); - m_locked = 0; -} - -wxMutex::~wxMutex() -{ - if (m_locked > 0) - wxLogDebug("Freeing a locked mutex (%d locks)", m_locked); - - pthread_mutex_destroy( &(p_internal->p_mutex) ); - delete p_internal; -} - -wxMutexError wxMutex::Lock() -{ - int err = pthread_mutex_lock( &(p_internal->p_mutex) ); - if (err == EDEADLK) - { - wxLogDebug("Locking this mutex would lead to deadlock!"); - - return wxMUTEX_DEAD_LOCK; - } - - m_locked++; - - return wxMUTEX_NO_ERROR; -} - -wxMutexError wxMutex::TryLock() -{ - if (m_locked) - { - return wxMUTEX_BUSY; - } - - int err = pthread_mutex_trylock( &(p_internal->p_mutex) ); - switch (err) - { - case EBUSY: return wxMUTEX_BUSY; - } - - m_locked++; - - return wxMUTEX_NO_ERROR; -} - -wxMutexError wxMutex::Unlock() -{ - if (m_locked > 0) - { - m_locked--; - } - else - { - wxLogDebug("Unlocking not locked mutex."); - - return wxMUTEX_UNLOCKED; - } - - pthread_mutex_unlock( &(p_internal->p_mutex) ); - - return wxMUTEX_NO_ERROR; -} - -//-------------------------------------------------------------------- -// wxCondition (Posix implementation) -//-------------------------------------------------------------------- - -class wxConditionInternal -{ -public: - pthread_cond_t p_condition; -}; - -wxCondition::wxCondition() -{ - p_internal = new wxConditionInternal; - pthread_cond_init( &(p_internal->p_condition), (const pthread_condattr_t *) NULL ); -} - -wxCondition::~wxCondition() -{ - pthread_cond_destroy( &(p_internal->p_condition) ); - - delete p_internal; -} - -void wxCondition::Wait(wxMutex& mutex) -{ - pthread_cond_wait( &(p_internal->p_condition), &(mutex.p_internal->p_mutex) ); -} - -bool wxCondition::Wait(wxMutex& mutex, unsigned long sec, unsigned long nsec) -{ - struct timespec tspec; - - tspec.tv_sec = time(0L)+sec; - tspec.tv_nsec = nsec; - return (pthread_cond_timedwait(&(p_internal->p_condition), &(mutex.p_internal->p_mutex), &tspec) != ETIMEDOUT); -} - -void wxCondition::Signal() -{ - pthread_cond_signal( &(p_internal->p_condition) ); -} - -void wxCondition::Broadcast() -{ - pthread_cond_broadcast( &(p_internal->p_condition) ); -} - -//-------------------------------------------------------------------- -// wxThread (Posix implementation) -//-------------------------------------------------------------------- - -class wxThreadInternal -{ -public: - wxThreadInternal(); - ~wxThreadInternal(); - - // thread entry function - static void *PthreadStart(void *ptr); - - // thread actions - // start the thread - wxThreadError Run(); - // ask the thread to terminate - void Cancel(); - // wake up threads waiting for our termination - void SignalExit(); - // go to sleep until Resume() is called - void Pause(); - // resume the thread - void Resume(); - - // accessors - // priority - int GetPriority() const { return m_prio; } - void SetPriority(int prio) { m_prio = prio; } - // state - thread_state GetState() const { return m_state; } - void SetState(thread_state state) { m_state = state; } - // id - pthread_t GetId() const { return thread_id; } - // "cancelled" flag - bool WasCancelled() const { return m_cancelled; } - -//private: -- should be! - pthread_t thread_id; - -private: - thread_state m_state; // see thread_state enum - int m_prio; // in wxWindows units: from 0 to 100 - - // set when the thread should terminate - bool m_cancelled; - - // this (mutex, cond) pair is used to synchronize the main thread and this - // thread in several situations: - // 1. The thread function blocks until condition is signaled by Run() when - // it's initially created - this allows create thread in "suspended" - // state - // 2. The Delete() function blocks until the condition is signaled when the - // thread exits. - wxMutex m_mutex; - wxCondition m_cond; - - // another (mutex, cond) pair for Pause()/Resume() usage - // - // VZ: it's possible that we might reuse the mutex and condition from above - // for this too, but as I'm not at all sure that it won't create subtle - // problems with race conditions between, say, Pause() and Delete() I - // prefer this may be a bit less efficient but much safer solution - wxMutex m_mutexSuspend; - wxCondition m_condSuspend; -}; - -void *wxThreadInternal::PthreadStart(void *ptr) -{ - wxThread *thread = (wxThread *)ptr; - wxThreadInternal *pthread = thread->p_internal; - - if ( pthread_setspecific(gs_keySelf, thread) != 0 ) - { - wxLogError(_("Can not start thread: error writing TLS.")); - - return (void *)-1; - } - - // wait for the condition to be signaled from Run() - // mutex state: currently locked by the thread which created us - pthread->m_cond.Wait(pthread->m_mutex); - - // mutex state: locked again on exit of Wait() - - // call the main entry - void* status = thread->Entry(); - - // terminate the thread - thread->Exit(status); - - wxFAIL_MSG("wxThread::Exit() can't return."); - - return NULL; -} - -wxThreadInternal::wxThreadInternal() -{ - m_state = STATE_NEW; - m_cancelled = FALSE; - - // this mutex is locked during almost all thread lifetime - it will only be - // unlocked in the very end - m_mutex.Lock(); - - // this mutex is used in Pause()/Resume() and is also locked all the time - // unless the thread is paused - m_mutexSuspend.Lock(); -} - -wxThreadInternal::~wxThreadInternal() -{ - m_mutexSuspend.Unlock(); - - // note that m_mutex will be unlocked by the thread which waits for our - // termination -} - -wxThreadError wxThreadInternal::Run() -{ - wxCHECK_MSG( GetState() == STATE_NEW, wxTHREAD_RUNNING, - "thread may only be started once after successful Create()" ); - - // the mutex was locked on Create(), so we will be able to lock it again - // only when the thread really starts executing and enters the wait - - // otherwise we might signal the condition before anybody is waiting for it - wxMutexLocker lock(m_mutex); - m_cond.Signal(); - - m_state = STATE_RUNNING; - - return wxTHREAD_NO_ERROR; - - // now the mutex is unlocked back - but just to allow Wait() function to - // terminate by relocking it, so the net result is that the worker thread - // starts executing and the mutex is still locked -} - -void wxThreadInternal::Cancel() -{ - // if the thread we're waiting for is waiting for the GUI mutex, we will - // deadlock so make sure we release it temporarily - if ( wxThread::IsMain() ) - wxMutexGuiLeave(); - - // nobody ever writes this variable so it's safe to not use any - // synchronization here - m_cancelled = TRUE; - - // entering Wait() releases the mutex thus allowing SignalExit() to acquire - // it and to signal us its termination - m_cond.Wait(m_mutex); - - // mutex is still in the locked state - relocked on exit from Wait(), so - // unlock it - we don't need it any more, the thread has already terminated - m_mutex.Unlock(); - - // reacquire GUI mutex - if ( wxThread::IsMain() ) - wxMutexGuiEnter(); -} - -void wxThreadInternal::SignalExit() -{ - // as mutex is currently locked, this will block until some other thread - // (normally the same which created this one) unlocks it by entering Wait() - m_mutex.Lock(); - - // wake up all the threads waiting for our termination - m_cond.Broadcast(); - - // after this call mutex will be finally unlocked - m_mutex.Unlock(); -} - -void wxThreadInternal::Pause() -{ - wxCHECK_RET( m_state == STATE_PAUSED, - "thread must first be paused with wxThread::Pause()." ); - - // wait until the condition is signaled from Resume() - m_condSuspend.Wait(m_mutexSuspend); -} - -void wxThreadInternal::Resume() -{ - wxCHECK_RET( m_state == STATE_PAUSED, - "can't resume thread which is not suspended." ); - - // we will be able to lock this mutex only when Pause() starts waiting - wxMutexLocker lock(m_mutexSuspend); - m_condSuspend.Signal(); - - SetState(STATE_RUNNING); -} - -// ----------------------------------------------------------------------------- -// static functions -// ----------------------------------------------------------------------------- - -wxThread *wxThread::This() -{ - return (wxThread *)pthread_getspecific(gs_keySelf); -} - -bool wxThread::IsMain() -{ - return (bool)pthread_equal(pthread_self(), gs_tidMain); -} - -void wxThread::Yield() -{ - sched_yield(); -} - -void wxThread::Sleep(unsigned long milliseconds) -{ - wxUsleep(milliseconds); -} - -// ----------------------------------------------------------------------------- -// creating thread -// ----------------------------------------------------------------------------- - -wxThread::wxThread() -{ - // add this thread to the global list of all threads - gs_allThreads.Add(this); - - p_internal = new wxThreadInternal(); -} - -wxThreadError wxThread::Create() -{ - if (p_internal->GetState() != STATE_NEW) - return wxTHREAD_RUNNING; - - // set up the thread attribute: right now, we only set thread priority - pthread_attr_t attr; - pthread_attr_init(&attr); - - int prio; - if ( pthread_attr_getschedpolicy(&attr, &prio) != 0 ) - { - wxLogError(_("Can not retrieve thread scheduling policy.")); - } - - int min_prio = sched_get_priority_min(prio), - max_prio = sched_get_priority_max(prio); - - if ( min_prio == -1 || max_prio == -1 ) - { - wxLogError(_("Can not get priority range for scheduling policy %d."), - prio); - } - else - { - struct sched_param sp; - pthread_attr_getschedparam(&attr, &sp); - sp.sched_priority = min_prio + - (p_internal->GetPriority()*(max_prio-min_prio))/100; - pthread_attr_setschedparam(&attr, &sp); - } - - // create the new OS thread object - int rc = pthread_create(&p_internal->thread_id, &attr, - wxThreadInternal::PthreadStart, - (void *)this); - pthread_attr_destroy(&attr); - - if ( rc != 0 ) - { - p_internal->SetState(STATE_EXITED); - return wxTHREAD_NO_RESOURCE; - } - - return wxTHREAD_NO_ERROR; -} - -wxThreadError wxThread::Run() -{ - return p_internal->Run(); -} - -// ----------------------------------------------------------------------------- -// misc accessors -// ----------------------------------------------------------------------------- - -void wxThread::SetPriority(unsigned int prio) -{ - wxCHECK_RET( (WXTHREAD_MIN_PRIORITY <= prio) && - (prio <= WXTHREAD_MAX_PRIORITY), "invalid thread priority" ); - - wxCriticalSectionLocker lock(m_critsect); - - switch ( p_internal->GetState() ) - { - case STATE_NEW: - // thread not yet started, priority will be set when it is - p_internal->SetPriority(prio); - break; - - case STATE_RUNNING: - case STATE_PAUSED: - { - struct sched_param sparam; - sparam.sched_priority = prio; - - if ( pthread_setschedparam(p_internal->GetId(), - SCHED_OTHER, &sparam) != 0 ) - { - wxLogError(_("Failed to set thread priority %d."), prio); - } - } - break; - - case STATE_EXITED: - default: - wxFAIL_MSG("impossible to set thread priority in this state"); - } -} - -unsigned int wxThread::GetPriority() const -{ - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - - return p_internal->GetPriority(); -} - -unsigned long wxThread::GetID() const -{ - return (unsigned long)p_internal->thread_id; -} - -// ----------------------------------------------------------------------------- -// pause/resume -// ----------------------------------------------------------------------------- - -wxThreadError wxThread::Pause() -{ - wxCriticalSectionLocker lock(m_critsect); - - if ( p_internal->GetState() != STATE_RUNNING ) - { - wxLogDebug("Can't pause thread which is not running."); - - return wxTHREAD_NOT_RUNNING; - } - - p_internal->SetState(STATE_PAUSED); - - return wxTHREAD_NO_ERROR; -} - -wxThreadError wxThread::Resume() -{ - wxCriticalSectionLocker lock(m_critsect); - - if ( p_internal->GetState() == STATE_PAUSED ) - { - p_internal->Resume(); - - return wxTHREAD_NO_ERROR; - } - else - { - wxLogDebug("Attempt to resume a thread which is not paused."); - - return wxTHREAD_MISC_ERROR; - } -} - -// ----------------------------------------------------------------------------- -// exiting thread -// ----------------------------------------------------------------------------- - -wxThread::ExitCode wxThread::Delete() -{ - m_critsect.Enter(); - thread_state state = p_internal->GetState(); - m_critsect.Leave(); - - switch ( state ) - { - case STATE_NEW: - case STATE_EXITED: - // nothing to do - break; - - case STATE_PAUSED: - // resume the thread first - Resume(); - - // fall through - - default: - // set the flag telling to the thread to stop and wait - p_internal->Cancel(); - } - - return NULL; -} - -wxThreadError wxThread::Kill() -{ - switch ( p_internal->GetState() ) - { - case STATE_NEW: - case STATE_EXITED: - return wxTHREAD_NOT_RUNNING; - - default: - if ( pthread_cancel(p_internal->GetId()) != 0 ) - { - wxLogError(_("Failed to terminate a thread.")); - - return wxTHREAD_MISC_ERROR; - } - - return wxTHREAD_NO_ERROR; - } -} - -void wxThread::Exit(void *status) -{ - // first call user-level clean up code - OnExit(); - - // next wake up the threads waiting for us (OTOH, this function won't return - // until someone waited for us!) - p_internal->SignalExit(); - - p_internal->SetState(STATE_EXITED); - - // delete both C++ thread object and terminate the OS thread object - delete this; - pthread_exit(status); -} - -// also test whether we were paused -bool wxThread::TestDestroy() -{ - wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect); - - if ( p_internal->GetState() == STATE_PAUSED ) - { - // leave the crit section or the other threads will stop too if they try - // to call any of (seemingly harmless) IsXXX() functions while we sleep - m_critsect.Leave(); - - p_internal->Pause(); - - // enter it back before it's finally left in lock object dtor - m_critsect.Enter(); - } - - return p_internal->WasCancelled(); -} - -wxThread::~wxThread() -{ - // remove this thread from the global array - gs_allThreads.Remove(this); -} - -// ----------------------------------------------------------------------------- -// state tests -// ----------------------------------------------------------------------------- - -bool wxThread::IsRunning() const -{ - wxCriticalSectionLocker lock((wxCriticalSection &)m_critsect); - - return p_internal->GetState() == STATE_RUNNING; -} - -bool wxThread::IsAlive() const -{ - wxCriticalSectionLocker lock((wxCriticalSection&)m_critsect); - - switch ( p_internal->GetState() ) - { - case STATE_RUNNING: - case STATE_PAUSED: - return TRUE; - - default: - return FALSE; - } -} - -//-------------------------------------------------------------------- -// wxThreadModule -//-------------------------------------------------------------------- - -class wxThreadModule : public wxModule -{ -public: - virtual bool OnInit(); - virtual void OnExit(); - -private: - DECLARE_DYNAMIC_CLASS(wxThreadModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxThreadModule, wxModule) - -bool wxThreadModule::OnInit() -{ - if ( pthread_key_create(&gs_keySelf, NULL /* dtor function */) != 0 ) - { - wxLogError(_("Thread module initialization failed: " - "failed to create pthread key.")); - - return FALSE; - } - - gs_mutexGui = new wxMutex(); - //wxThreadGuiInit(); - gs_tidMain = pthread_self(); - gs_mutexGui->Lock(); - - return TRUE; -} - -void wxThreadModule::OnExit() -{ - wxASSERT_MSG( wxThread::IsMain(), "only main thread can be here" ); - - // terminate any threads left - size_t count = gs_allThreads.GetCount(); - if ( count != 0u ) - wxLogDebug("Some threads were not terminated by the application."); - - for ( size_t n = 0u; n < count; n++ ) - { - gs_allThreads[n]->Delete(); - } - - // destroy GUI mutex - gs_mutexGui->Unlock(); - //wxThreadGuiExit(); - delete gs_mutexGui; - - // and free TLD slot - (void)pthread_key_delete(gs_keySelf); -} - -void wxMutexGuiEnter() -{ - gs_mutexGui->Lock(); -} - -void wxMutexGuiLeave() -{ - gs_mutexGui->Unlock(); -} diff --git a/src/motif/utilsexc.cpp b/src/motif/utilsexc.cpp deleted file mode 100644 index 8603963d6f..0000000000 --- a/src/motif/utilsexc.cpp +++ /dev/null @@ -1,245 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: utilsexec.cpp -// Purpose: Execution-related utilities -// Author: Julian Smart -// Modified by: -// Created: 17/09/98 -// RCS-ID: $Id$ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#ifdef __GNUG__ -// #pragma implementation -#endif - -#include "wx/utils.h" -#include "wx/app.h" -#include "wx/process.h" - -#include -#include -#include -#include - -#ifdef VMS -/*steve*/ -#ifdef __HIDE_FORBIDDEN_NAMES -#undefine __HIDE_FORBIDDEN_NAMES -#endif -#include -#ifdef VAX -/*because 'noshare' is not valid in vax C++*/ -#define CC$VAXCSHR 1 -#endif -#include -#define unlink DELETE - -#else - -#if defined(__AIX__) || defined(__xlC__) -#include -#include -#else -#ifndef __DATA_GENERAL__ -#include -#endif -#endif - -#include -#include -#include -#include - -#endif - -#ifdef __SVR4__ -#include -#endif - -#ifdef __SOLARIS__ -// somehow missing from sys/wait.h but in the system's docs -extern "C" -{ - pid_t wait4(pid_t pid, int *statusp, int options, struct rusage - *rusage); -} -#endif - -#include -#include - -#include - -struct wxLocalProcessData -{ - int pid, end_process; - wxProcess *process; -}; - -#ifdef __SOLARIS__ -// somehow missing from sys/wait.h but in the system's docs -extern "C" -{ - pid_t wait4(pid_t pid, int *statusp, int options, struct rusage - *rusage); -} -#endif - -void wxUsleep(unsigned long milliseconds) -{ -#if defined(HAVE_NANOSLEEP) - timespec tmReq; - tmReq.tv_sec = milliseconds / 1000; - tmReq.tv_nsec = (milliseconds % 1000) * 1000 * 1000; - - // we're not interested in remaining time nor in return value - (void)nanosleep(&tmReq, (timespec *)NULL); -#elif defined(HAVE_USLEEP) - // uncomment this if you feel brave or if you are sure that your version - // of Solaris has a safe usleep() function but please notice that usleep() - // is known to lead to crashes in MT programs in Solaris 2.[67] and is not - // documented as MT-Safe - #if defined(__SUN__) && defined(wxUSE_THREADS) - #error "usleep() cannot be used in MT programs under Solaris." - #endif // Sun - - usleep(milliseconds * 1000); // usleep(3) wants microseconds -#else // !sleep function - #error "usleep() or nanosleep() function required for wxUsleep" -#endif // sleep function -} - -void xt_notify_end_process(XtPointer client, int *fid, - XtInputId *id) -{ - wxLocalProcessData *process_data = (wxLocalProcessData *)client; - - int pid; - - pid = (process_data->pid > 0) ? process_data->pid : -(process_data->pid); - - /* wait4 is not part of any standard, use at own risk - * not sure what wait4 does, but wait3 seems to be closest, whats a digit ;-) - * --- offer@sgi.com */ -#if !defined(__HPUX__) && !defined(__sgi) && !defined(__SGI__) && !defined(__ALPHA__) && !defined(__SUNCC__) - wait4(process_data->pid, NULL, 0, NULL); -#else - wait3((int *) NULL, 0, (rusage *) NULL); -#endif - - XtRemoveInput(*id); - if (process_data->process) - process_data->process->OnTerminate(process_data->pid, 0); // What should 'status' be? - - process_data->end_process = TRUE; - /* - if (process_data->pid > 0) // synchronous - delete process_data; - else - process_data->pid = 0; - */ - delete process_data; -} - -long wxExecute(char **argv, bool sync, wxProcess *handler) -{ -#ifdef VMS - return(0); -#else - if (*argv == NULL) - return 0; // Nothing??? - - int proc_link[2]; - if (pipe(proc_link)) - return 0; - - /* fork the process */ -#if defined(sun) || defined(__ultrix) || defined(__bsdi__) - pid_t pid = vfork (); -#else - pid_t pid = fork (); -#endif - - if (pid == -1) - { - return 0; - } - else if (pid == 0) - { - /* GUILHEM: Close all fds when sync == 0 */ - if (sync == 0) - for (int fd=0;fdend_process = 0; - process_data->process = handler; - process_data->pid = (sync) ? pid : -pid; - - close(proc_link[1]); - XtAppAddInput((XtAppContext) wxTheApp->GetAppContext(), proc_link[0], - (XtPointer *) XtInputReadMask, - (XtInputCallbackProc) xt_notify_end_process, - (XtPointer) process_data); - - if (sync) - { - while (!process_data->end_process) - XtAppProcessEvent((XtAppContext) wxTheApp->GetAppContext(), XtIMAll); - - if (WIFEXITED(process_data->end_process) != 0) - { - return WEXITSTATUS(process_data->end_process); - } - } - - return pid; -#endif - // end VMS -} - -long wxExecute (const wxString& command, bool sync, wxProcess* handler) -{ -#ifdef VMS - return(0); -#else - if (command.IsNull() || command == "") - return 0; // Nothing to do - - // Run a program the recomended way under X (XView) - int argc = 0; - char *argv[127]; - char tmp[1024]; - const char *IFS = " \t\n"; - - // Build argument vector - strncpy (tmp, (const char*) command, sizeof (tmp) / sizeof (char) - 1); - tmp[sizeof (tmp) / sizeof (char) - 1] = '\0'; - argv[argc++] = strtok (tmp, IFS); - while ((argv[argc++] = strtok (NULL, IFS)) != NULL) - /* loop */ ; - - return wxExecute(argv, sync, handler); -#endif - // VMS -}