thrimpl.cpp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: wx/thrimpl.cpp
  3. // Purpose: common part of wxThread Implementations
  4. // Author: Vadim Zeitlin
  5. // Modified by:
  6. // Created: 04.06.02 (extracted from src/*/thread.cpp files)
  7. // Copyright: (c) Vadim Zeitlin (2002)
  8. // Licence: wxWindows licence
  9. /////////////////////////////////////////////////////////////////////////////
  10. // this file is supposed to be included only by the various thread.cpp
  11. // ----------------------------------------------------------------------------
  12. // wxMutex
  13. // ----------------------------------------------------------------------------
  14. wxMutex::wxMutex(wxMutexType mutexType)
  15. {
  16. m_internal = new wxMutexInternal(mutexType);
  17. if ( !m_internal->IsOk() )
  18. {
  19. delete m_internal;
  20. m_internal = NULL;
  21. }
  22. }
  23. wxMutex::~wxMutex()
  24. {
  25. delete m_internal;
  26. }
  27. bool wxMutex::IsOk() const
  28. {
  29. return m_internal != NULL;
  30. }
  31. wxMutexError wxMutex::Lock()
  32. {
  33. wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
  34. wxT("wxMutex::Lock(): not initialized") );
  35. return m_internal->Lock();
  36. }
  37. wxMutexError wxMutex::LockTimeout(unsigned long ms)
  38. {
  39. wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
  40. wxT("wxMutex::Lock(): not initialized") );
  41. return m_internal->Lock(ms);
  42. }
  43. wxMutexError wxMutex::TryLock()
  44. {
  45. wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
  46. wxT("wxMutex::TryLock(): not initialized") );
  47. return m_internal->TryLock();
  48. }
  49. wxMutexError wxMutex::Unlock()
  50. {
  51. wxCHECK_MSG( m_internal, wxMUTEX_INVALID,
  52. wxT("wxMutex::Unlock(): not initialized") );
  53. return m_internal->Unlock();
  54. }
  55. // --------------------------------------------------------------------------
  56. // wxConditionInternal
  57. // --------------------------------------------------------------------------
  58. // Win32 and OS/2 don't have explicit support for the POSIX condition
  59. // variables and their events/event semaphores have quite different semantics,
  60. // so we reimplement the conditions from scratch using the mutexes and
  61. // semaphores
  62. #if defined(__WINDOWS__) || defined(__OS2__) || defined(__EMX__)
  63. class wxConditionInternal
  64. {
  65. public:
  66. wxConditionInternal(wxMutex& mutex);
  67. bool IsOk() const { return m_mutex.IsOk() && m_semaphore.IsOk(); }
  68. wxCondError Wait();
  69. wxCondError WaitTimeout(unsigned long milliseconds);
  70. wxCondError Signal();
  71. wxCondError Broadcast();
  72. private:
  73. // the number of threads currently waiting for this condition
  74. LONG m_numWaiters;
  75. // the critical section protecting m_numWaiters
  76. wxCriticalSection m_csWaiters;
  77. wxMutex& m_mutex;
  78. wxSemaphore m_semaphore;
  79. wxDECLARE_NO_COPY_CLASS(wxConditionInternal);
  80. };
  81. wxConditionInternal::wxConditionInternal(wxMutex& mutex)
  82. : m_mutex(mutex)
  83. {
  84. // another thread can't access it until we return from ctor, so no need to
  85. // protect access to m_numWaiters here
  86. m_numWaiters = 0;
  87. }
  88. wxCondError wxConditionInternal::Wait()
  89. {
  90. // increment the number of waiters
  91. {
  92. wxCriticalSectionLocker lock(m_csWaiters);
  93. m_numWaiters++;
  94. }
  95. m_mutex.Unlock();
  96. // after unlocking the mutex other threads may Signal() us, but it is ok
  97. // now as we had already incremented m_numWaiters so Signal() will post the
  98. // semaphore and decrement m_numWaiters back even if it is called before we
  99. // start to Wait()
  100. const wxSemaError err = m_semaphore.Wait();
  101. m_mutex.Lock();
  102. if ( err == wxSEMA_NO_ERROR )
  103. {
  104. // m_numWaiters was decremented by Signal()
  105. return wxCOND_NO_ERROR;
  106. }
  107. // but in case of an error we need to do it manually
  108. {
  109. wxCriticalSectionLocker lock(m_csWaiters);
  110. m_numWaiters--;
  111. }
  112. return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
  113. }
  114. wxCondError wxConditionInternal::WaitTimeout(unsigned long milliseconds)
  115. {
  116. {
  117. wxCriticalSectionLocker lock(m_csWaiters);
  118. m_numWaiters++;
  119. }
  120. m_mutex.Unlock();
  121. wxSemaError err = m_semaphore.WaitTimeout(milliseconds);
  122. m_mutex.Lock();
  123. if ( err == wxSEMA_NO_ERROR )
  124. return wxCOND_NO_ERROR;
  125. if ( err == wxSEMA_TIMEOUT )
  126. {
  127. // a potential race condition exists here: it happens when a waiting
  128. // thread times out but doesn't have time to decrement m_numWaiters yet
  129. // before Signal() is called in another thread
  130. //
  131. // to handle this particular case, check the semaphore again after
  132. // acquiring m_csWaiters lock -- this will catch the signals missed
  133. // during this window
  134. wxCriticalSectionLocker lock(m_csWaiters);
  135. err = m_semaphore.WaitTimeout(0);
  136. if ( err == wxSEMA_NO_ERROR )
  137. return wxCOND_NO_ERROR;
  138. // we need to decrement m_numWaiters ourselves as it wasn't done by
  139. // Signal()
  140. m_numWaiters--;
  141. return err == wxSEMA_TIMEOUT ? wxCOND_TIMEOUT : wxCOND_MISC_ERROR;
  142. }
  143. // undo m_numWaiters++ above in case of an error
  144. {
  145. wxCriticalSectionLocker lock(m_csWaiters);
  146. m_numWaiters--;
  147. }
  148. return wxCOND_MISC_ERROR;
  149. }
  150. wxCondError wxConditionInternal::Signal()
  151. {
  152. wxCriticalSectionLocker lock(m_csWaiters);
  153. if ( m_numWaiters > 0 )
  154. {
  155. // increment the semaphore by 1
  156. if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
  157. return wxCOND_MISC_ERROR;
  158. m_numWaiters--;
  159. }
  160. return wxCOND_NO_ERROR;
  161. }
  162. wxCondError wxConditionInternal::Broadcast()
  163. {
  164. wxCriticalSectionLocker lock(m_csWaiters);
  165. while ( m_numWaiters > 0 )
  166. {
  167. if ( m_semaphore.Post() != wxSEMA_NO_ERROR )
  168. return wxCOND_MISC_ERROR;
  169. m_numWaiters--;
  170. }
  171. return wxCOND_NO_ERROR;
  172. }
  173. #endif // __WINDOWS__ || __OS2__ || __EMX__
  174. // ----------------------------------------------------------------------------
  175. // wxCondition
  176. // ----------------------------------------------------------------------------
  177. wxCondition::wxCondition(wxMutex& mutex)
  178. {
  179. m_internal = new wxConditionInternal(mutex);
  180. if ( !m_internal->IsOk() )
  181. {
  182. delete m_internal;
  183. m_internal = NULL;
  184. }
  185. }
  186. wxCondition::~wxCondition()
  187. {
  188. delete m_internal;
  189. }
  190. bool wxCondition::IsOk() const
  191. {
  192. return m_internal != NULL;
  193. }
  194. wxCondError wxCondition::Wait()
  195. {
  196. wxCHECK_MSG( m_internal, wxCOND_INVALID,
  197. wxT("wxCondition::Wait(): not initialized") );
  198. return m_internal->Wait();
  199. }
  200. wxCondError wxCondition::WaitTimeout(unsigned long milliseconds)
  201. {
  202. wxCHECK_MSG( m_internal, wxCOND_INVALID,
  203. wxT("wxCondition::Wait(): not initialized") );
  204. return m_internal->WaitTimeout(milliseconds);
  205. }
  206. wxCondError wxCondition::Signal()
  207. {
  208. wxCHECK_MSG( m_internal, wxCOND_INVALID,
  209. wxT("wxCondition::Signal(): not initialized") );
  210. return m_internal->Signal();
  211. }
  212. wxCondError wxCondition::Broadcast()
  213. {
  214. wxCHECK_MSG( m_internal, wxCOND_INVALID,
  215. wxT("wxCondition::Broadcast(): not initialized") );
  216. return m_internal->Broadcast();
  217. }
  218. // --------------------------------------------------------------------------
  219. // wxSemaphore
  220. // --------------------------------------------------------------------------
  221. wxSemaphore::wxSemaphore(int initialcount, int maxcount)
  222. {
  223. m_internal = new wxSemaphoreInternal( initialcount, maxcount );
  224. if ( !m_internal->IsOk() )
  225. {
  226. delete m_internal;
  227. m_internal = NULL;
  228. }
  229. }
  230. wxSemaphore::~wxSemaphore()
  231. {
  232. delete m_internal;
  233. }
  234. bool wxSemaphore::IsOk() const
  235. {
  236. return m_internal != NULL;
  237. }
  238. wxSemaError wxSemaphore::Wait()
  239. {
  240. wxCHECK_MSG( m_internal, wxSEMA_INVALID,
  241. wxT("wxSemaphore::Wait(): not initialized") );
  242. return m_internal->Wait();
  243. }
  244. wxSemaError wxSemaphore::TryWait()
  245. {
  246. wxCHECK_MSG( m_internal, wxSEMA_INVALID,
  247. wxT("wxSemaphore::TryWait(): not initialized") );
  248. return m_internal->TryWait();
  249. }
  250. wxSemaError wxSemaphore::WaitTimeout(unsigned long milliseconds)
  251. {
  252. wxCHECK_MSG( m_internal, wxSEMA_INVALID,
  253. wxT("wxSemaphore::WaitTimeout(): not initialized") );
  254. return m_internal->WaitTimeout(milliseconds);
  255. }
  256. wxSemaError wxSemaphore::Post()
  257. {
  258. wxCHECK_MSG( m_internal, wxSEMA_INVALID,
  259. wxT("wxSemaphore::Post(): not initialized") );
  260. return m_internal->Post();
  261. }
  262. // ----------------------------------------------------------------------------
  263. // wxThread
  264. // ----------------------------------------------------------------------------
  265. #include "wx/utils.h"
  266. #include "wx/private/threadinfo.h"
  267. #include "wx/scopeguard.h"
  268. void wxThread::Sleep(unsigned long milliseconds)
  269. {
  270. wxMilliSleep(milliseconds);
  271. }
  272. void *wxThread::CallEntry()
  273. {
  274. wxON_BLOCK_EXIT0(wxThreadSpecificInfo::ThreadCleanUp);
  275. return Entry();
  276. }