/src/corelib/thread/qwaitcondition_win.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 233 lines · 146 code · 35 blank · 52 comment · 17 complexity · 9c70dd16a61653904ae8eb2ce909a3ea MD5 · raw file

  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
  4. ** All rights reserved.
  5. ** Contact: Nokia Corporation (qt-info@nokia.com)
  6. **
  7. ** This file is part of the QtCore module of the Qt Toolkit.
  8. **
  9. ** $QT_BEGIN_LICENSE:LGPL$
  10. ** GNU Lesser General Public License Usage
  11. ** This file may be used under the terms of the GNU Lesser General Public
  12. ** License version 2.1 as published by the Free Software Foundation and
  13. ** appearing in the file LICENSE.LGPL included in the packaging of this
  14. ** file. Please review the following information to ensure the GNU Lesser
  15. ** General Public License version 2.1 requirements will be met:
  16. ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  17. **
  18. ** In addition, as a special exception, Nokia gives you certain additional
  19. ** rights. These rights are described in the Nokia Qt LGPL Exception
  20. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  21. **
  22. ** GNU General Public License Usage
  23. ** Alternatively, this file may be used under the terms of the GNU General
  24. ** Public License version 3.0 as published by the Free Software Foundation
  25. ** and appearing in the file LICENSE.GPL included in the packaging of this
  26. ** file. Please review the following information to ensure the GNU General
  27. ** Public License version 3.0 requirements will be met:
  28. ** http://www.gnu.org/copyleft/gpl.html.
  29. **
  30. ** Other Usage
  31. ** Alternatively, this file may be used in accordance with the terms and
  32. ** conditions contained in a signed written agreement between you and Nokia.
  33. **
  34. **
  35. **
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. #include "qwaitcondition.h"
  42. #include "qnamespace.h"
  43. #include "qmutex.h"
  44. #include "qreadwritelock.h"
  45. #include "qlist.h"
  46. #include "qalgorithms.h"
  47. #include "qt_windows.h"
  48. #ifndef QT_NO_THREAD
  49. #define Q_MUTEX_T void*
  50. #include <private/qmutex_p.h>
  51. #include <private/qreadwritelock_p.h>
  52. QT_BEGIN_NAMESPACE
  53. //***********************************************************************
  54. // QWaitConditionPrivate
  55. // **********************************************************************
  56. class QWaitConditionEvent
  57. {
  58. public:
  59. inline QWaitConditionEvent() : priority(0), wokenUp(false)
  60. {
  61. event = CreateEvent(NULL, TRUE, FALSE, NULL);
  62. }
  63. inline ~QWaitConditionEvent() { CloseHandle(event); }
  64. int priority;
  65. bool wokenUp;
  66. HANDLE event;
  67. };
  68. typedef QList<QWaitConditionEvent *> EventQueue;
  69. class QWaitConditionPrivate
  70. {
  71. public:
  72. QMutex mtx;
  73. EventQueue queue;
  74. EventQueue freeQueue;
  75. QWaitConditionEvent *pre();
  76. bool wait(QWaitConditionEvent *wce, unsigned long time);
  77. void post(QWaitConditionEvent *wce, bool ret);
  78. };
  79. QWaitConditionEvent *QWaitConditionPrivate::pre()
  80. {
  81. mtx.lock();
  82. QWaitConditionEvent *wce =
  83. freeQueue.isEmpty() ? new QWaitConditionEvent : freeQueue.takeFirst();
  84. wce->priority = GetThreadPriority(GetCurrentThread());
  85. wce->wokenUp = false;
  86. // insert 'wce' into the queue (sorted by priority)
  87. int index = 0;
  88. for (; index < queue.size(); ++index) {
  89. QWaitConditionEvent *current = queue.at(index);
  90. if (current->priority < wce->priority)
  91. break;
  92. }
  93. queue.insert(index, wce);
  94. mtx.unlock();
  95. return wce;
  96. }
  97. bool QWaitConditionPrivate::wait(QWaitConditionEvent *wce, unsigned long time)
  98. {
  99. // wait for the event
  100. bool ret = false;
  101. switch (WaitForSingleObject(wce->event, time)) {
  102. default: break;
  103. case WAIT_OBJECT_0:
  104. ret = true;
  105. break;
  106. }
  107. return ret;
  108. }
  109. void QWaitConditionPrivate::post(QWaitConditionEvent *wce, bool ret)
  110. {
  111. mtx.lock();
  112. // remove 'wce' from the queue
  113. queue.removeAll(wce);
  114. ResetEvent(wce->event);
  115. freeQueue.append(wce);
  116. // wakeups delivered after the timeout should be forwarded to the next waiter
  117. if (!ret && wce->wokenUp && !queue.isEmpty()) {
  118. QWaitConditionEvent *other = queue.first();
  119. SetEvent(other->event);
  120. other->wokenUp = true;
  121. }
  122. mtx.unlock();
  123. }
  124. //***********************************************************************
  125. // QWaitCondition implementation
  126. //***********************************************************************
  127. QWaitCondition::QWaitCondition()
  128. {
  129. d = new QWaitConditionPrivate;
  130. }
  131. QWaitCondition::~QWaitCondition()
  132. {
  133. if (!d->queue.isEmpty()) {
  134. qWarning("QWaitCondition: Destroyed while threads are still waiting");
  135. qDeleteAll(d->queue);
  136. }
  137. qDeleteAll(d->freeQueue);
  138. delete d;
  139. }
  140. bool QWaitCondition::wait(QMutex *mutex, unsigned long time)
  141. {
  142. if (!mutex)
  143. return false;
  144. if (mutex->d->recursive) {
  145. qWarning("QWaitCondition::wait: Cannot wait on recursive mutexes");
  146. return false;
  147. }
  148. QWaitConditionEvent *wce = d->pre();
  149. mutex->unlock();
  150. bool returnValue = d->wait(wce, time);
  151. mutex->lock();
  152. d->post(wce, returnValue);
  153. return returnValue;
  154. }
  155. bool QWaitCondition::wait(QReadWriteLock *readWriteLock, unsigned long time)
  156. {
  157. if (!readWriteLock || readWriteLock->d->accessCount == 0)
  158. return false;
  159. if (readWriteLock->d->accessCount < -1) {
  160. qWarning("QWaitCondition: cannot wait on QReadWriteLocks with recursive lockForWrite()");
  161. return false;
  162. }
  163. QWaitConditionEvent *wce = d->pre();
  164. int previousAccessCount = readWriteLock->d->accessCount;
  165. readWriteLock->unlock();
  166. bool returnValue = d->wait(wce, time);
  167. if (previousAccessCount < 0)
  168. readWriteLock->lockForWrite();
  169. else
  170. readWriteLock->lockForRead();
  171. d->post(wce, returnValue);
  172. return returnValue;
  173. }
  174. void QWaitCondition::wakeOne()
  175. {
  176. // wake up the first waiting thread in the queue
  177. QMutexLocker locker(&d->mtx);
  178. for (int i = 0; i < d->queue.size(); ++i) {
  179. QWaitConditionEvent *current = d->queue.at(i);
  180. if (current->wokenUp)
  181. continue;
  182. SetEvent(current->event);
  183. current->wokenUp = true;
  184. break;
  185. }
  186. }
  187. void QWaitCondition::wakeAll()
  188. {
  189. // wake up the all threads in the queue
  190. QMutexLocker locker(&d->mtx);
  191. for (int i = 0; i < d->queue.size(); ++i) {
  192. QWaitConditionEvent *current = d->queue.at(i);
  193. SetEvent(current->event);
  194. current->wokenUp = true;
  195. }
  196. }
  197. QT_END_NAMESPACE
  198. #endif // QT_NO_THREAD