X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f6bcfd974ef26faf6f91a62cac09827e09463fd1..0fe5e8fea017ecb73f8aaa8ceb745feb269b3f79:/src/msw/thread.cpp diff --git a/src/msw/thread.cpp b/src/msw/thread.cpp index e701abb39b..b654353bfc 100644 --- a/src/msw/thread.cpp +++ b/src/msw/thread.cpp @@ -45,21 +45,42 @@ #define _MT #endif +#if defined(__BORLANDC__) + #if !defined(__MT__) + // I can't set -tWM in the IDE (anyone?) so have to do this + #define __MT__ + #endif + + #if !defined(__MFC_COMPAT__) + // Needed to know about _beginthreadex etc.. + #define __MFC_COMPAT__ + #endif +#endif // BC++ + +// define wxUSE_BEGIN_THREAD if the compiler has _beginthreadex() function +// which should be used instead of Win32 ::CreateThread() if possible #if defined(__VISUALC__) || \ (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) || \ - (defined(__GNUG__) && defined(__MSVCRT__)) - -#if defined(__BORLANDC__) && !defined(__MT__) -// I can't set -tWM in the IDE (anyone?) so have to do this -#define __MT__ -#endif + (defined(__GNUG__) && defined(__MSVCRT__)) || \ + defined(__WATCOMC__) -#if defined(__BORLANDC__) && !defined(__MFC_COMPAT__) -// Needed to know about _beginthreadex etc.. -#define __MFC_COMPAT__ + #undef wxUSE_BEGIN_THREAD + #define wxUSE_BEGIN_THREAD #endif +#ifdef wxUSE_BEGIN_THREAD + // this is where _beginthreadex() is declared #include + + // the return type of the thread function entry point + typedef unsigned THREAD_RETVAL; + + // the calling convention of the thread function entry point + #define THREAD_CALLCONV __stdcall +#else + // the settings for CreateThread() + typedef DWORD THREAD_RETVAL; + #define THREAD_CALLCONV WINAPI #endif // ---------------------------------------------------------------------------- @@ -211,44 +232,83 @@ class wxConditionInternal public: wxConditionInternal() { - event = ::CreateEvent( - NULL, // default secutiry - FALSE, // not manual reset - FALSE, // nonsignaled initially - NULL // nameless event - ); - if ( !event ) + m_hEvent = ::CreateEvent( + NULL, // default secutiry + FALSE, // not manual reset + FALSE, // nonsignaled initially + NULL // nameless event + ); + if ( !m_hEvent ) { wxLogSysError(_("Can not create event object.")); } - waiters = 0; + + // nobody waits for us yet + m_nWaiters = 0; } bool Wait(DWORD timeout) { - waiters++; + // as m_nWaiters variable is accessed from multiple waiting threads + // (and possibly from the broadcasting thread), we need to change its + // value atomically + ::InterlockedIncrement(&m_nWaiters); - // FIXME this should be MsgWaitForMultipleObjects() as well probably - DWORD rc = ::WaitForSingleObject(event, timeout); + // FIXME this should be MsgWaitForMultipleObjects() as we want to keep + // processing Windows messages while waiting (or don't we?) + DWORD rc = ::WaitForSingleObject(m_hEvent, timeout); - waiters--; + ::InterlockedDecrement(&m_nWaiters); return rc != WAIT_TIMEOUT; } + void Signal() + { + // set the event to signaled: if a thread is already waiting on it, it + // will be woken up, otherwise the event will remain in the signaled + // state until someone waits on it. In any case, the system will return + // it to a non signalled state afterwards. If multiple threads are + // waiting, only one will be woken up. + if ( !::SetEvent(m_hEvent) ) + { + wxLogLastError(wxT("SetEvent")); + } + } + + void Broadcast() + { + // we need to save the original value as m_nWaiters is goign to be + // decreased by the signalled thread resulting in the loop being + // executed less times than needed + LONG nWaiters = m_nWaiters; + + // this works because all these threads are already waiting and so each + // SetEvent() inside Signal() is really a PulseEvent() because the + // event state is immediately returned to non-signaled + for ( LONG n = 0; n < nWaiters; n++ ) + { + Signal(); + } + } + ~wxConditionInternal() { - if ( event ) + if ( m_hEvent ) { - if ( !::CloseHandle(event) ) + if ( !::CloseHandle(m_hEvent) ) { wxLogLastError(wxT("CloseHandle(event)")); } } } - HANDLE event; - int waiters; +private: + // the Win32 synchronization object corresponding to this event + HANDLE m_hEvent; + + // number of threads waiting for this condition + LONG m_nWaiters; }; wxCondition::wxCondition() @@ -274,26 +334,12 @@ bool wxCondition::Wait(unsigned long sec, void wxCondition::Signal() { - // set the event to signaled: if a thread is already waiting on it, it will - // be woken up, otherwise the event will remain in the signaled state until - // someone waits on it. In any case, the system will return it to a non - // signalled state afterwards. If multiple threads are waiting, only one - // will be woken up. - if ( !::SetEvent(m_internal->event) ) - { - wxLogLastError(wxT("SetEvent")); - } + m_internal->Signal(); } void wxCondition::Broadcast() { - // this works because all these threads are already waiting and so each - // SetEvent() inside Signal() is really a PulseEvent() because the event - // state is immediately returned to non-signaled - for ( int i = 0; i < m_internal->waiters; i++ ) - { - Signal(); - } + m_internal->Broadcast(); } // ---------------------------------------------------------------------------- @@ -302,8 +348,14 @@ void wxCondition::Broadcast() wxCriticalSection::wxCriticalSection() { - wxASSERT_MSG( sizeof(CRITICAL_SECTION) <= sizeof(m_buffer), +#ifdef __WXDEBUG__ + // Done this way to stop warnings during compilation about statement + // always being false + int csSize = sizeof(CRITICAL_SECTION); + int bSize = sizeof(m_buffer); + wxASSERT_MSG( csSize <= bSize, _T("must increase buffer size in wx/thread.h") ); +#endif ::InitializeCriticalSection((CRITICAL_SECTION *)m_buffer); } @@ -359,7 +411,7 @@ public: } // create a new (suspended) thread (for the given thread object) - bool Create(wxThread *thread); + bool Create(wxThread *thread, unsigned int stackSize); // suspend/resume/terminate bool Suspend(); @@ -379,7 +431,7 @@ public: DWORD GetId() const { return m_tid; } // thread function - static DWORD WinThreadStart(wxThread *thread); + static THREAD_RETVAL THREAD_CALLCONV WinThreadStart(void *thread); private: HANDLE m_hThread; // handle of the thread @@ -388,16 +440,17 @@ private: DWORD m_tid; // thread id }; -DWORD wxThreadInternal::WinThreadStart(wxThread *thread) +THREAD_RETVAL THREAD_CALLCONV wxThreadInternal::WinThreadStart(void *param) { - DWORD rc; + THREAD_RETVAL rc; bool wasCancelled; // first of all, check whether we hadn't been cancelled already and don't // start the user code at all then + wxThread *thread = (wxThread *)param; if ( thread->m_internal->GetState() == STATE_EXITED ) { - rc = (DWORD)-1; + rc = (THREAD_RETVAL)-1; wasCancelled = TRUE; } else // do run thread @@ -410,7 +463,7 @@ DWORD wxThreadInternal::WinThreadStart(wxThread *thread) return (DWORD)-1; } - rc = (DWORD)thread->Entry(); + rc = (THREAD_RETVAL)thread->Entry(); // enter m_critsect before changing the thread state thread->m_critsect.Enter(); @@ -461,28 +514,35 @@ void wxThreadInternal::SetPriority(unsigned int priority) } } -bool wxThreadInternal::Create(wxThread *thread) +bool wxThreadInternal::Create(wxThread *thread, unsigned int stackSize) { // for compilers which have it, we should use C RTL function for thread // creation instead of Win32 API one because otherwise we will have memory // leaks if the thread uses C RTL (and most threads do) -#if defined(__VISUALC__) || \ - (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) || \ - (defined(__GNUG__) && defined(__MSVCRT__)) - typedef unsigned (__stdcall *RtlThreadStart)(void *); - - m_hThread = (HANDLE)_beginthreadex(NULL, 0, - (RtlThreadStart) - wxThreadInternal::WinThreadStart, - thread, CREATE_SUSPENDED, - (unsigned int *)&m_tid); +#ifdef wxUSE_BEGIN_THREAD + + // Watcom is reported to not like 0 stack size (which means "use default" + // for the other compilers and is also the default value for stackSize) +#ifdef __WATCOMC__ + if ( !stackSize ) + stackSize = 10240; +#endif // __WATCOMC__ + + m_hThread = (HANDLE)_beginthreadex + ( + NULL, // default security + stackSize, + wxThreadInternal::WinThreadStart, // entry point + thread, + CREATE_SUSPENDED, + (unsigned int *)&m_tid + ); #else // compiler doesn't have _beginthreadex m_hThread = ::CreateThread ( NULL, // default security - 0, // default stack size - (LPTHREAD_START_ROUTINE) // thread entry point - wxThreadInternal::WinThreadStart, // + stackSize, // stack size + wxThreadInternal::WinThreadStart, // thread entry point (LPVOID)thread, // parameter CREATE_SUSPENDED, // flags &m_tid // [out] thread id @@ -587,6 +647,11 @@ int wxThread::GetCPUCount() return si.dwNumberOfProcessors; } +unsigned long wxThread::GetCurrentId() +{ + return (unsigned long)::GetCurrentThreadId(); +} + bool wxThread::SetConcurrency(size_t level) { wxASSERT_MSG( IsMain(), _T("should only be called from the main thread") ); @@ -700,11 +765,11 @@ wxThread::~wxThread() // create/start thread // ------------------- -wxThreadError wxThread::Create() +wxThreadError wxThread::Create(unsigned int stackSize) { wxCriticalSectionLocker lock(m_critsect); - if ( !m_internal->Create(this) ) + if ( !m_internal->Create(this, stackSize) ) return wxTHREAD_NO_RESOURCE; return wxTHREAD_NO_ERROR; @@ -954,9 +1019,7 @@ void wxThread::Exit(ExitCode status) delete this; } -#if defined(__VISUALC__) || \ - (defined(__BORLANDC__) && (__BORLANDC__ >= 0x500)) || \ - (defined(__GNUG__) && defined(__MSVCRT__)) +#ifdef wxUSE_BEGIN_THREAD _endthreadex((unsigned)status); #else // !VC++ ::ExitThread((DWORD)status); @@ -1126,7 +1189,7 @@ void WXDLLEXPORT wxMutexGuiLeave() } else { - // decrement the number of waiters now + // decrement the number of threads waiting for GUI access now wxASSERT_MSG( gs_nWaitingForGui > 0, wxT("calling wxMutexGuiLeave() without entering it first?") ); @@ -1190,3 +1253,5 @@ bool WXDLLEXPORT wxIsWaitingForThread() } #endif // wxUSE_THREADS + +// vi:sts=4:sw=4:et