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 
operator >=(const Timeval & arg2) const28 int Timeval::operator>=(const Timeval& arg2) const {
29   return seconds() > arg2.seconds()
30     || (seconds() == arg2.seconds()
31 	&& useconds() >= arg2.useconds());
32 }
33 
operator +=(const DelayInterval & arg2)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 
operator -=(const DelayInterval & arg2)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 
operator -(const Timeval & arg1,const Timeval & arg2)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 
operator *(short arg1,const DelayInterval & arg2)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 
DelayQueueEntry(DelayInterval delay)97 DelayQueueEntry::DelayQueueEntry(DelayInterval delay)
98   : fDeltaTimeRemaining(delay) {
99   fNext = fPrev = this;
100   fToken = ++tokenCounter;
101 }
102 
~DelayQueueEntry()103 DelayQueueEntry::~DelayQueueEntry() {
104 }
105 
handleTimeout()106 void DelayQueueEntry::handleTimeout() {
107   delete this;
108 }
109 
110 
111 ///// DelayQueue /////
112 
DelayQueue()113 DelayQueue::DelayQueue()
114   : DelayQueueEntry(ETERNITY) {
115   fLastSyncTime = TimeNow();
116 }
117 
~DelayQueue()118 DelayQueue::~DelayQueue() {
119   while (fNext != this) {
120     DelayQueueEntry* entryToRemove = fNext;
121     removeEntry(entryToRemove);
122     delete entryToRemove;
123   }
124 }
125 
addEntry(DelayQueueEntry * newEntry)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 
updateEntry(DelayQueueEntry * entry,DelayInterval newDelay)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 
updateEntry(intptr_t tokenToFind,DelayInterval newDelay)151 void DelayQueue::updateEntry(intptr_t tokenToFind, DelayInterval newDelay) {
152   DelayQueueEntry* entry = findEntryByToken(tokenToFind);
153   updateEntry(entry, newDelay);
154 }
155 
removeEntry(DelayQueueEntry * entry)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 
removeEntry(intptr_t tokenToFind)166 DelayQueueEntry* DelayQueue::removeEntry(intptr_t tokenToFind) {
167   DelayQueueEntry* entry = findEntryByToken(tokenToFind);
168   removeEntry(entry);
169   return entry;
170 }
171 
timeToNextAlarm()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 
handleAlarm()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 
findEntryByToken(intptr_t tokenToFind)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 
synchronize()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 
TimeNow()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