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