ECScheduler.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <kopano/platform.h>
  18. #include <utility>
  19. #include <kopano/ECScheduler.h>
  20. #include <kopano/lockhelper.hpp>
  21. #include <cerrno>
  22. #include <sys/time.h> /* gettimeofday */
  23. #define SCHEDULER_POLL_FREQUENCY 5
  24. namespace KC {
  25. ECScheduler::ECScheduler(ECLogger *lpLogger) :
  26. m_lpLogger(lpLogger)
  27. {
  28. m_lpLogger->AddRef();
  29. //Create Scheduler thread
  30. pthread_create(&m_hMainThread, NULL, ScheduleThread, (void*)this);
  31. set_thread_name(m_hMainThread, "ECScheduler:main");
  32. }
  33. ECScheduler::~ECScheduler(void)
  34. {
  35. ulock_normal l_exit(m_hExitMutex);
  36. m_bExit = TRUE;
  37. m_hExitSignal.notify_one();
  38. l_exit.unlock();
  39. pthread_join(m_hMainThread, NULL);
  40. //Clean up something
  41. m_lpLogger->Release();
  42. }
  43. HRESULT ECScheduler::AddSchedule(eSchedulerType eType, unsigned int ulBeginCycle, void* (*lpFunction)(void*), void* lpData)
  44. {
  45. scoped_rlock l_sched(m_hSchedulerMutex);
  46. if (lpFunction == NULL)
  47. return E_INVALIDARG;
  48. ECSCHEDULE sECSchedule;
  49. sECSchedule.eType = eType;
  50. sECSchedule.ulBeginCycle = ulBeginCycle;
  51. sECSchedule.lpFunction = lpFunction;
  52. sECSchedule.lpData = lpData;
  53. sECSchedule.tLastRunTime = 0;
  54. m_listScheduler.push_back(std::move(sECSchedule));
  55. return S_OK;
  56. }
  57. bool ECScheduler::hasExpired(time_t ttime, ECSCHEDULE *lpSchedule)
  58. {
  59. struct tm tmLastRunTime;
  60. struct tm tmtime;
  61. localtime_r(&ttime, &tmtime);
  62. if(lpSchedule->tLastRunTime > 0)
  63. localtime_r(&lpSchedule->tLastRunTime, &tmLastRunTime);
  64. else
  65. memset(&tmLastRunTime, 0, sizeof(tmLastRunTime));
  66. switch (lpSchedule->eType) {
  67. case SCHEDULE_SECONDS:
  68. return
  69. (((tmLastRunTime.tm_min != tmtime.tm_min) ||
  70. ((tmLastRunTime.tm_min == tmtime.tm_min) &&
  71. (tmLastRunTime.tm_sec != tmtime.tm_sec))) &&
  72. ((tmtime.tm_sec == (int)lpSchedule->ulBeginCycle) ||
  73. ((lpSchedule->ulBeginCycle > 0) &&
  74. ((tmtime.tm_sec % (int)lpSchedule->ulBeginCycle) < SCHEDULER_POLL_FREQUENCY))));
  75. case SCHEDULE_MINUTES:
  76. return
  77. (((tmLastRunTime.tm_hour != tmtime.tm_hour) ||
  78. ((tmLastRunTime.tm_hour == tmtime.tm_hour) &&
  79. (tmLastRunTime.tm_min != tmtime.tm_min))) &&
  80. ((tmtime.tm_min == (int)lpSchedule->ulBeginCycle) ||
  81. ((lpSchedule->ulBeginCycle > 0) &&
  82. ((tmtime.tm_min % (int)lpSchedule->ulBeginCycle) == 0))));
  83. case SCHEDULE_HOUR:
  84. return
  85. ((tmLastRunTime.tm_hour != tmtime.tm_hour) &&
  86. ((int)lpSchedule->ulBeginCycle >= tmtime.tm_min) &&
  87. ((int)lpSchedule->ulBeginCycle <= (tmtime.tm_min + 2)));
  88. case SCHEDULE_DAY:
  89. return
  90. ((tmLastRunTime.tm_mday != tmtime.tm_mday) &&
  91. ((int)lpSchedule->ulBeginCycle == tmtime.tm_hour));
  92. case SCHEDULE_MONTH:
  93. return
  94. ((tmLastRunTime.tm_mon != tmtime.tm_mon) &&
  95. ((int)lpSchedule->ulBeginCycle == tmtime.tm_mday));
  96. case SCHEDULE_NONE:
  97. return false;
  98. }
  99. return false;
  100. }
  101. void* ECScheduler::ScheduleThread(void* lpTmpScheduler)
  102. {
  103. ECScheduleList::iterator iterScheduleList;
  104. auto lpScheduler = static_cast<ECScheduler *>(lpTmpScheduler);
  105. HRESULT* lperThread = NULL;
  106. pthread_t hThread;
  107. time_t ttime;
  108. if (lpScheduler == NULL)
  109. return NULL;
  110. while(TRUE)
  111. {
  112. // Wait for a terminate signal or return after a few minutes
  113. ulock_normal l_exit(lpScheduler->m_hExitMutex);
  114. if (lpScheduler->m_bExit)
  115. break;
  116. if (lpScheduler->m_hExitSignal.wait_for(l_exit, std::chrono::seconds(SCHEDULER_POLL_FREQUENCY)) ==
  117. std::cv_status::timeout)
  118. break;
  119. l_exit.unlock();
  120. for (auto &sl : lpScheduler->m_listScheduler) {
  121. ulock_rec l_sched(lpScheduler->m_hSchedulerMutex);
  122. //TODO If load on server high, check only items with a high priority
  123. time(&ttime);
  124. if (hasExpired(ttime, &sl)) {
  125. //Create task thread
  126. int err = 0;
  127. if((err = pthread_create(&hThread, NULL, sl.lpFunction, static_cast<void *>(sl.lpData))) != 0) {
  128. lpScheduler->m_lpLogger->Log(EC_LOGLEVEL_FATAL, "Unable to spawn new thread: %s", strerror(err));
  129. goto task_fail;
  130. }
  131. set_thread_name(hThread, "ECScheduler:worker");
  132. sl.tLastRunTime = ttime;
  133. if((err = pthread_join(hThread, (void**)&lperThread)) != 0) {
  134. lpScheduler->m_lpLogger->Log(EC_LOGLEVEL_FATAL, "Unable to join thread: %s", strerror(err));
  135. goto task_fail;
  136. }
  137. delete lperThread;
  138. lperThread = NULL;
  139. }
  140. task_fail:
  141. l_sched.unlock();
  142. // check for a exit signal
  143. l_exit.lock();
  144. if(lpScheduler->m_bExit) {
  145. l_exit.unlock();
  146. break;
  147. }
  148. l_exit.unlock();
  149. }
  150. }
  151. return NULL;
  152. }
  153. } /* namespace */