ctkEASyncDeliverTasks.tpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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(HandlerTask* task)
  28. : task(task)
  29. {
  30. }
  31. void run()
  32. {
  33. try
  34. {
  35. // notify the outer thread to start the timer
  36. startBarrier.waitForRendezvous();
  37. // execute the task
  38. task->execute();
  39. // stop the timer
  40. timerBarrier.waitForRendezvous();
  41. }
  42. catch (const ctkIllegalStateException& )
  43. {
  44. // this can happen on shutdown, so we ignore it
  45. }
  46. }
  47. private:
  48. HandlerTask* task;
  49. };
  50. template<class HandlerTask>
  51. class _RunInSyncMaster : public QRunnable
  52. {
  53. public:
  54. _RunInSyncMaster(ctkEASyncDeliverTasks<HandlerTask>* handlerTasks,
  55. const QList<HandlerTask>& tasks)
  56. : handlerTasks(handlerTasks), tasks(tasks)
  57. {
  58. }
  59. void run()
  60. {
  61. handlerTasks->executeInSyncMaster(tasks);
  62. }
  63. private:
  64. ctkEASyncDeliverTasks<HandlerTask>* handlerTasks;
  65. const QList<HandlerTask>& tasks;
  66. };
  67. template<class HandlerTask>
  68. ctkEASyncDeliverTasks<HandlerTask>::ctkEASyncDeliverTasks(
  69. ctkEADefaultThreadPool* pool, ctkEASyncMasterThread* syncMasterThread,
  70. long timeout, const QList<QString>& ignoreTimeout)
  71. : pool(pool), syncMasterThread(syncMasterThread)
  72. {
  73. update(timeout, ignoreTimeout);
  74. }
  75. template<class HandlerTask>
  76. void ctkEASyncDeliverTasks<HandlerTask>::update(long timeout, const QList<QString>& ignoreTimeout)
  77. {
  78. {
  79. QMutexLocker l(&mutex);
  80. this->timeout = timeout;
  81. }
  82. if (ignoreTimeout.isEmpty())
  83. {
  84. QMutexLocker l(&mutex);
  85. qDeleteAll(ignoreTimeoutMatcher);
  86. ignoreTimeoutMatcher.clear();
  87. }
  88. else
  89. {
  90. QList<Matcher*> newMatcherList;
  91. foreach(QString value, ignoreTimeout)
  92. {
  93. value = value.trimmed();
  94. if (!value.isEmpty())
  95. {
  96. newMatcherList.push_back(new ClassMatcher(value));
  97. }
  98. }
  99. {
  100. QMutexLocker l(&mutex);
  101. qDeleteAll(ignoreTimeoutMatcher);
  102. ignoreTimeoutMatcher = newMatcherList;
  103. }
  104. }
  105. }
  106. template<class HandlerTask>
  107. void ctkEASyncDeliverTasks<HandlerTask>::execute(const QList<HandlerTask>& tasks)
  108. {
  109. _RunInSyncMaster<HandlerTask> runnable(this, tasks);
  110. runnable.setAutoDelete(false);
  111. syncMasterThread->syncRun(&runnable);
  112. }
  113. template<class HandlerTask>
  114. void ctkEASyncDeliverTasks<HandlerTask>::executeInSyncMaster(const QList<HandlerTask>& tasks)
  115. {
  116. QThread* const sleepingThread = QThread::currentThread();
  117. ctkEASyncThread* const syncThread = qobject_cast<ctkEASyncThread*>(sleepingThread);
  118. foreach(HandlerTask task, tasks)
  119. {
  120. if (!useTimeout(task))
  121. {
  122. // no timeout, we can directly execute
  123. task.execute();
  124. }
  125. else if (syncThread != 0)
  126. {
  127. // if this is a cascaded event, we directly use this thread
  128. // otherwise we could end up in a starvation
  129. //TODO use Qt4.7 API
  130. //long startTime = System.currentTimeMillis();
  131. QDateTime startTime = QDateTime::currentDateTime();
  132. task.execute();
  133. if (startTime.time().msecsTo(QDateTime::currentDateTime().time()) > timeout)
  134. {
  135. task.blackListHandler();
  136. }
  137. }
  138. else
  139. {
  140. _TimeoutRunnable<HandlerTask>* timeoutRunnable
  141. = new _TimeoutRunnable<HandlerTask>(&task);
  142. ctkEAScopedRunnableReference runnableRef(timeoutRunnable);
  143. ctkEARendezvous* startBarrier = &timeoutRunnable->startBarrier;
  144. ctkEARendezvous* timerBarrier = &timeoutRunnable->timerBarrier;
  145. pool->executeTask(timeoutRunnable);
  146. // we wait for the inner thread to start
  147. startBarrier->waitForRendezvous();
  148. // timeout handling
  149. // we sleep for the sleep time
  150. // if someone wakes us up it's the finished inner task
  151. try
  152. {
  153. timerBarrier->waitAttemptForRendezvous(timeout);
  154. }
  155. catch (const ctkEATimeoutException& )
  156. {
  157. // if we timed out, we have to blacklist the handler
  158. task.blackListHandler();
  159. }
  160. }
  161. }
  162. }
  163. template<class HandlerTask>
  164. bool ctkEASyncDeliverTasks<HandlerTask>::useTimeout(const HandlerTask& task)
  165. {
  166. // we only check the classname if a timeout is configured
  167. long t = 0;
  168. {
  169. QMutexLocker l(&mutex);
  170. t = timeout;
  171. }
  172. if (t > 0)
  173. {
  174. QList<Matcher*> currMatcherList;
  175. {
  176. QMutexLocker l(&mutex);
  177. currMatcherList = ignoreTimeoutMatcher;
  178. }
  179. if (!currMatcherList.isEmpty())
  180. {
  181. QString className = task.getHandlerClassName();
  182. foreach(Matcher* matcher, currMatcherList)
  183. {
  184. if (matcher)
  185. {
  186. if (matcher->match(className))
  187. {
  188. return false;
  189. }
  190. }
  191. }
  192. }
  193. return true;
  194. }
  195. return false;
  196. }