| 1 | /********** |
| 2 | This library is free software; you can redistribute it and/or modify it under |
| 3 | the terms of the GNU Lesser General Public License as published by the |
| 4 | Free Software Foundation; either version 3 of the License, or (at your |
| 5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) |
| 6 | |
| 7 | This library is distributed in the hope that it will be useful, but WITHOUT |
| 8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
| 10 | more details. |
| 11 | |
| 12 | You should have received a copy of the GNU Lesser General Public License |
| 13 | along with this library; if not, write to the Free Software Foundation, Inc., |
| 14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 15 | **********/ |
| 16 | // Copyright (c) 1996-2020, Live Networks, Inc. All rights reserved |
| 17 | // Help by Carlo Bonamico to get working for Windows |
| 18 | // Delay queue |
| 19 | // Implementation |
| 20 | |
| 21 | #include "DelayQueue.hh" |
| 22 | #include "GroupsockHelper.hh" |
| 23 | |
| 24 | static const int MILLION = 1000000; |
| 25 | |
| 26 | ///// Timeval ///// |
| 27 | |
| 28 | int Timeval::operator>=(const Timeval& arg2) const { |
| 29 | return seconds() > arg2.seconds() |
| 30 | || (seconds() == arg2.seconds() |
| 31 | && useconds() >= arg2.useconds()); |
| 32 | } |
| 33 | |
| 34 | void Timeval::operator+=(const DelayInterval& arg2) { |
| 35 | secs() += arg2.seconds(); usecs() += arg2.useconds(); |
| 36 | if (useconds() >= MILLION) { |
| 37 | usecs() -= MILLION; |
| 38 | ++secs(); |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | void Timeval::operator-=(const DelayInterval& arg2) { |
| 43 | secs() -= arg2.seconds(); usecs() -= arg2.useconds(); |
| 44 | if ((int)useconds() < 0) { |
| 45 | usecs() += MILLION; |
| 46 | --secs(); |
| 47 | } |
| 48 | if ((int)seconds() < 0) |
| 49 | secs() = usecs() = 0; |
| 50 | |
| 51 | } |
| 52 | |
| 53 | DelayInterval operator-(const Timeval& arg1, const Timeval& arg2) { |
| 54 | time_base_seconds secs = arg1.seconds() - arg2.seconds(); |
| 55 | time_base_seconds usecs = arg1.useconds() - arg2.useconds(); |
| 56 | |
| 57 | if ((int)usecs < 0) { |
| 58 | usecs += MILLION; |
| 59 | --secs; |
| 60 | } |
| 61 | if ((int)secs < 0) |
| 62 | return DELAY_ZERO; |
| 63 | else |
| 64 | return DelayInterval(secs, usecs); |
| 65 | } |
| 66 | |
| 67 | |
| 68 | ///// DelayInterval ///// |
| 69 | |
| 70 | DelayInterval operator*(short arg1, const DelayInterval& arg2) { |
| 71 | time_base_seconds result_seconds = arg1*arg2.seconds(); |
| 72 | time_base_seconds result_useconds = arg1*arg2.useconds(); |
| 73 | |
| 74 | time_base_seconds carry = result_useconds/MILLION; |
| 75 | result_useconds -= carry*MILLION; |
| 76 | result_seconds += carry; |
| 77 | |
| 78 | return DelayInterval(result_seconds, result_useconds); |
| 79 | } |
| 80 | |
| 81 | #ifndef INT_MAX |
| 82 | #define INT_MAX 0x7FFFFFFF |
| 83 | #endif |
| 84 | const DelayInterval DELAY_ZERO(0, 0); |
| 85 | const DelayInterval DELAY_SECOND(1, 0); |
| 86 | const DelayInterval DELAY_MINUTE = 60*DELAY_SECOND; |
| 87 | const DelayInterval DELAY_HOUR = 60*DELAY_MINUTE; |
| 88 | const DelayInterval DELAY_DAY = 24*DELAY_HOUR; |
| 89 | const DelayInterval ETERNITY(INT_MAX, MILLION-1); |
| 90 | // used internally to make the implementation work |
| 91 | |
| 92 | |
| 93 | ///// DelayQueueEntry ///// |
| 94 | |
| 95 | intptr_t DelayQueueEntry::tokenCounter = 0; |
| 96 | |
| 97 | DelayQueueEntry::DelayQueueEntry(DelayInterval delay) |
| 98 | : fDeltaTimeRemaining(delay) { |
| 99 | fNext = fPrev = this; |
| 100 | fToken = ++tokenCounter; |
| 101 | } |
| 102 | |
| 103 | DelayQueueEntry::~DelayQueueEntry() { |
| 104 | } |
| 105 | |
| 106 | void DelayQueueEntry::handleTimeout() { |
| 107 | delete this; |
| 108 | } |
| 109 | |
| 110 | |
| 111 | ///// DelayQueue ///// |
| 112 | |
| 113 | DelayQueue::DelayQueue() |
| 114 | : DelayQueueEntry(ETERNITY) { |
| 115 | fLastSyncTime = TimeNow(); |
| 116 | } |
| 117 | |
| 118 | DelayQueue::~DelayQueue() { |
| 119 | while (fNext != this) { |
| 120 | DelayQueueEntry* entryToRemove = fNext; |
| 121 | removeEntry(entryToRemove); |
| 122 | delete entryToRemove; |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | void DelayQueue::addEntry(DelayQueueEntry* newEntry) { |
| 127 | synchronize(); |
| 128 | |
| 129 | DelayQueueEntry* cur = head(); |
| 130 | while (newEntry->fDeltaTimeRemaining >= cur->fDeltaTimeRemaining) { |
| 131 | newEntry->fDeltaTimeRemaining -= cur->fDeltaTimeRemaining; |
| 132 | cur = cur->fNext; |
| 133 | } |
| 134 | |
| 135 | cur->fDeltaTimeRemaining -= newEntry->fDeltaTimeRemaining; |
| 136 | |
| 137 | // Add "newEntry" to the queue, just before "cur": |
| 138 | newEntry->fNext = cur; |
| 139 | newEntry->fPrev = cur->fPrev; |
| 140 | cur->fPrev = newEntry->fPrev->fNext = newEntry; |
| 141 | } |
| 142 | |
| 143 | void DelayQueue::updateEntry(DelayQueueEntry* entry, DelayInterval newDelay) { |
| 144 | if (entry == NULL) return; |
| 145 | |
| 146 | removeEntry(entry); |
| 147 | entry->fDeltaTimeRemaining = newDelay; |
| 148 | addEntry(entry); |
| 149 | } |
| 150 | |
| 151 | void DelayQueue::updateEntry(intptr_t tokenToFind, DelayInterval newDelay) { |
| 152 | DelayQueueEntry* entry = findEntryByToken(tokenToFind); |
| 153 | updateEntry(entry, newDelay); |
| 154 | } |
| 155 | |
| 156 | void DelayQueue::removeEntry(DelayQueueEntry* entry) { |
| 157 | if (entry == NULL || entry->fNext == NULL) return; |
| 158 | |
| 159 | entry->fNext->fDeltaTimeRemaining += entry->fDeltaTimeRemaining; |
| 160 | entry->fPrev->fNext = entry->fNext; |
| 161 | entry->fNext->fPrev = entry->fPrev; |
| 162 | entry->fNext = entry->fPrev = NULL; |
| 163 | // in case we should try to remove it again |
| 164 | } |
| 165 | |
| 166 | DelayQueueEntry* DelayQueue::removeEntry(intptr_t tokenToFind) { |
| 167 | DelayQueueEntry* entry = findEntryByToken(tokenToFind); |
| 168 | removeEntry(entry); |
| 169 | return entry; |
| 170 | } |
| 171 | |
| 172 | DelayInterval const& DelayQueue::timeToNextAlarm() { |
| 173 | if (head()->fDeltaTimeRemaining == DELAY_ZERO) return DELAY_ZERO; // a common case |
| 174 | |
| 175 | synchronize(); |
| 176 | return head()->fDeltaTimeRemaining; |
| 177 | } |
| 178 | |
| 179 | void DelayQueue::handleAlarm() { |
| 180 | if (head()->fDeltaTimeRemaining != DELAY_ZERO) synchronize(); |
| 181 | |
| 182 | if (head()->fDeltaTimeRemaining == DELAY_ZERO) { |
| 183 | // This event is due to be handled: |
| 184 | DelayQueueEntry* toRemove = head(); |
| 185 | removeEntry(toRemove); // do this first, in case handler accesses queue |
| 186 | |
| 187 | toRemove->handleTimeout(); |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | DelayQueueEntry* DelayQueue::findEntryByToken(intptr_t tokenToFind) { |
| 192 | DelayQueueEntry* cur = head(); |
| 193 | while (cur != this) { |
| 194 | if (cur->token() == tokenToFind) return cur; |
| 195 | cur = cur->fNext; |
| 196 | } |
| 197 | |
| 198 | return NULL; |
| 199 | } |
| 200 | |
| 201 | void DelayQueue::synchronize() { |
| 202 | // First, figure out how much time has elapsed since the last sync: |
| 203 | _EventTime timeNow = TimeNow(); |
| 204 | if (timeNow < fLastSyncTime) { |
| 205 | // The system clock has apparently gone back in time; reset our sync time and return: |
| 206 | fLastSyncTime = timeNow; |
| 207 | return; |
| 208 | } |
| 209 | DelayInterval timeSinceLastSync = timeNow - fLastSyncTime; |
| 210 | fLastSyncTime = timeNow; |
| 211 | |
| 212 | // Then, adjust the delay queue for any entries whose time is up: |
| 213 | DelayQueueEntry* curEntry = head(); |
| 214 | while (timeSinceLastSync >= curEntry->fDeltaTimeRemaining) { |
| 215 | timeSinceLastSync -= curEntry->fDeltaTimeRemaining; |
| 216 | curEntry->fDeltaTimeRemaining = DELAY_ZERO; |
| 217 | curEntry = curEntry->fNext; |
| 218 | } |
| 219 | curEntry->fDeltaTimeRemaining -= timeSinceLastSync; |
| 220 | } |
| 221 | |
| 222 | |
| 223 | ///// _EventTime ///// |
| 224 | |
| 225 | _EventTime TimeNow() { |
| 226 | struct timeval tvNow; |
| 227 | |
| 228 | gettimeofday(&tvNow, NULL); |
| 229 | |
| 230 | return _EventTime(tvNow.tv_sec, tvNow.tv_usec); |
| 231 | } |
| 232 | |
| 233 | const _EventTime THE_END_OF_TIME(INT_MAX); |
| 234 | |