ctkEASyncDeliverTasks.tpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /*=============================================================================
  2. Library: CTK
  3. Copyright (c) German Cancer Research Center,
  4. Division of Medical and Biological Informatics
  5. Licensed under the Apache License, Version 2.0 (the "License");
  6. you may not use this file except in compliance with the License.
  7. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. =============================================================================*/
  15. #include "ctkEASyncThread_p.h"
  16. #include <dispatch/ctkEADefaultThreadPool_p.h>
  17. #include <dispatch/ctkEASyncMasterThread_p.h>
  18. #include <util/ctkEARendezvous_p.h>
  19. #include <util/ctkEATimeoutException_p.h>
  20. #include <QDateTime>
  21. template<class HandlerTask>
  22. class _TimeoutRunnable : public ctkEARunnable
  23. {
  24. public:
  25. ctkEARendezvous timerBarrier;
  26. ctkEARendezvous startBarrier;
  27. _TimeoutRunnable(ctkEARendezvous* cascadingBarrier, HandlerTask* task)
  28. : cascadingBarrier(cascadingBarrier), task(task)
  29. {
  30. }
  31. void run()
  32. {
  33. ctkEASyncThread* myThread = qobject_cast<ctkEASyncThread*>(QThread::currentThread());
  34. Q_ASSERT(myThread != 0);
  35. myThread->init(&timerBarrier, cascadingBarrier);
  36. try
  37. {
  38. // notify the outer thread to start the timer
  39. startBarrier.waitForRendezvous();
  40. // execute the task
  41. task->execute();
  42. // stop the timer
  43. timerBarrier.waitForRendezvous();
  44. }
  45. catch (const std::logic_error& )
  46. {
  47. // this can happen on shutdown, so we ignore it
  48. }
  49. catch (...)
  50. {
  51. myThread->uninit();
  52. throw;
  53. }
  54. myThread->uninit();
  55. }
  56. private:
  57. ctkEARendezvous* cascadingBarrier;
  58. HandlerTask* task;
  59. };
  60. template<class HandlerTask>
  61. class _RunInSyncMaster : public QRunnable
  62. {
  63. public:
  64. _RunInSyncMaster(ctkEASyncDeliverTasks<HandlerTask>* handlerTasks,
  65. const QList<HandlerTask>& tasks)
  66. : handlerTasks(handlerTasks), tasks(tasks)
  67. {
  68. }
  69. void run()
  70. {
  71. handlerTasks->executeInSyncMaster(tasks);
  72. }
  73. private:
  74. ctkEASyncDeliverTasks<HandlerTask>* handlerTasks;
  75. const QList<HandlerTask>& tasks;
  76. };
  77. template<class HandlerTask>
  78. ctkEASyncDeliverTasks<HandlerTask>::ctkEASyncDeliverTasks(
  79. ctkEADefaultThreadPool* pool, ctkEASyncMasterThread* syncMasterThread,
  80. long timeout, const QList<QString>& ignoreTimeout)
  81. : pool(pool), syncMasterThread(syncMasterThread)
  82. {
  83. update(timeout, ignoreTimeout);
  84. }
  85. template<class HandlerTask>
  86. void ctkEASyncDeliverTasks<HandlerTask>::update(long timeout, const QList<QString>& ignoreTimeout)
  87. {
  88. {
  89. QMutexLocker l(&mutex);
  90. this->timeout = timeout;
  91. }
  92. if (ignoreTimeout.isEmpty())
  93. {
  94. QMutexLocker l(&mutex);
  95. qDeleteAll(ignoreTimeoutMatcher);
  96. ignoreTimeoutMatcher.clear();
  97. }
  98. else
  99. {
  100. QList<Matcher*> newMatcherList;
  101. foreach(QString value, ignoreTimeout)
  102. {
  103. value = value.trimmed();
  104. if (!value.isEmpty())
  105. {
  106. newMatcherList.push_back(new ClassMatcher(value));
  107. }
  108. }
  109. {
  110. QMutexLocker l(&mutex);
  111. qDeleteAll(ignoreTimeoutMatcher);
  112. ignoreTimeoutMatcher = newMatcherList;
  113. }
  114. }
  115. }
  116. template<class HandlerTask>
  117. void ctkEASyncDeliverTasks<HandlerTask>::execute(const QList<HandlerTask>& tasks)
  118. {
  119. _RunInSyncMaster<HandlerTask> runnable(this, tasks);
  120. runnable.setAutoDelete(false);
  121. syncMasterThread->syncRun(&runnable);
  122. }
  123. template<class HandlerTask>
  124. void ctkEASyncDeliverTasks<HandlerTask>::executeInSyncMaster(const QList<HandlerTask>& tasks)
  125. {
  126. QThread* sleepingThread = QThread::currentThread();
  127. ctkEASyncThread* syncThread = qobject_cast<ctkEASyncThread*>(sleepingThread);
  128. ctkEARendezvous cascadingBarrier;
  129. // check if this is a cascaded event sending
  130. if (syncThread)
  131. {
  132. // wake up outer thread
  133. if (syncThread->isTopMostHandler())
  134. {
  135. syncThread->getTimerBarrier()->waitForRendezvous();
  136. }
  137. syncThread->innerEventHandlingStart();
  138. }
  139. foreach(HandlerTask task, tasks)
  140. {
  141. if (!useTimeout(task))
  142. {
  143. // no timeout, we can directly execute
  144. task.execute();
  145. }
  146. else
  147. {
  148. _TimeoutRunnable<HandlerTask>* timeoutRunnable
  149. = new _TimeoutRunnable<HandlerTask>(&cascadingBarrier, &task);
  150. ++timeoutRunnable->ref;
  151. ctkEARendezvous* startBarrier = &timeoutRunnable->startBarrier;
  152. ctkEARendezvous* timerBarrier = &timeoutRunnable->timerBarrier;
  153. pool->executeTask(timeoutRunnable);
  154. // we wait for the inner thread to start
  155. startBarrier->waitForRendezvous();
  156. // timeout handling
  157. bool finished = true;
  158. long sleepTime = timeout;
  159. do {
  160. finished = true;
  161. // we sleep for the sleep time
  162. // if someone wakes us up it's the inner task who either
  163. // has finished or a cascading event
  164. //TODO use Qt4.7 API
  165. //long startTime = System.currentTimeMillis();
  166. QDateTime startTime = QDateTime::currentDateTime();
  167. try
  168. {
  169. timerBarrier->waitAttemptForRendezvous(sleepTime);
  170. // if this occurs no timeout occured or we have a cascaded event
  171. if (!task.finished())
  172. {
  173. // adjust remaining sleep time
  174. //TODO use Qt4.7 API
  175. //sleepTime = timeout - (System.currentTimeMillis() - startTime);
  176. sleepTime = timeout - startTime.time().msecsTo(QDateTime::currentDateTime().time());
  177. cascadingBarrier.waitForRendezvous();
  178. finished = task.finished();
  179. }
  180. }
  181. catch (const ctkEATimeoutException& )
  182. {
  183. // if we timed out, we have to blacklist the handler
  184. task.blackListHandler();
  185. }
  186. }
  187. while ( !finished );
  188. if (!--timeoutRunnable->ref) delete timeoutRunnable;
  189. }
  190. }
  191. // wake up outer thread again if cascaded
  192. if (syncThread)
  193. {
  194. syncThread->innerEventHandlingStopped();
  195. if (syncThread->isTopMostHandler())
  196. {
  197. if (!syncThread->getTimerBarrier()->isTimedOut())
  198. {
  199. syncThread->getCascadingBarrier()->waitForRendezvous();
  200. }
  201. }
  202. }
  203. }
  204. template<class HandlerTask>
  205. bool ctkEASyncDeliverTasks<HandlerTask>::useTimeout(const HandlerTask& task)
  206. {
  207. // we only check the classname if a timeout is configured
  208. long t = 0;
  209. {
  210. QMutexLocker l(&mutex);
  211. t = timeout;
  212. }
  213. if (t > 0)
  214. {
  215. QList<Matcher*> currMatcherList;
  216. {
  217. QMutexLocker l(&mutex);
  218. currMatcherList = ignoreTimeoutMatcher;
  219. }
  220. if (!currMatcherList.isEmpty())
  221. {
  222. QString className = task.getHandlerClassName();
  223. foreach(Matcher* matcher, currMatcherList)
  224. {
  225. if (matcher)
  226. {
  227. if (matcher->match(className))
  228. {
  229. return false;
  230. }
  231. }
  232. }
  233. }
  234. return true;
  235. }
  236. return false;
  237. }