2 Copyright 2004-2005 Chris Tallon
4 This file is part of VOMP.
6 VOMP is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 VOMP is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with VOMP; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 Timers* Timers::instance = NULL;
37 Timers* Timers::getInstance()
44 if (initted) return 0;
46 logger = Log::getInstance();
48 threadLock(); // lock here, the thread loop will unlock and wait
49 //logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 1");
59 int Timers::shutdown()
61 if (!initted) return 0;
64 logger->log("Timers", Log::DEBUG, "Timers shutdown start");
68 TimerList::iterator i;
69 UINT numTimers = timerList.size();
72 i = timerList.begin();
74 timerList.pop_front();
78 logger->log("Timers", Log::DEBUG, "Timers shutdown end");
83 int Timers::setTimerT(TimerReceiver* client, int clientReference, long int requestedTime, long int requestedTimeNSEC)
85 if (!initted) return 0;
87 logger->log("Timers", Log::DEBUG, "Starting set timer 1");
89 //logger->log("Timers", Log::DEBUG, "Waiting for LOCK -TIMERS- MUTEX 2");
92 // Check that this timer is not already in the list
93 TimerList::iterator i;
94 Timer* currentTimer = NULL;
95 for(i = timerList.begin(); i != timerList.end(); i++)
98 if ((currentTimer->client == client) && (currentTimer->clientReference == clientReference))
100 // Overwrite an existing timer
101 currentTimer->requestedTime.tv_sec = requestedTime;
102 currentTimer->requestedTime.tv_nsec = requestedTimeNSEC;
103 resetThreadFlag = true;
104 threadSignalNoLock();
106 //logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX 2 (b)");
112 Timer* t = new Timer();
114 t->clientReference = clientReference;
115 t->requestedTime.tv_sec = requestedTime;
116 t->requestedTime.tv_nsec = requestedTimeNSEC;
118 //logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 2");
119 timerList.push_back(t);
120 resetThreadFlag = true;
121 threadSignalNoLock();
122 //logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX 2");
125 logger->log("Timers", Log::DEBUG, "Timer set for %p ref %i", client, clientReference);
130 int Timers::setTimerD(TimerReceiver* client, int clientReference, long int requestedSecs, long int requestedNSecs)
132 struct timespec currentTime;
135 clock_gettime(CLOCK_REALTIME, ¤tTime);
140 GetSystemTime(&systime);
141 SystemTimeToFileTime(&systime,(FILETIME*)&filetime);
142 currentTime.tv_sec=(filetime-WINDOWS_TIME_BASE_OFFSET)/(10*1000*1000);
143 //#error "Hier gibt was zu tun!"
144 currentTime.tv_nsec=((filetime-WINDOWS_TIME_BASE_OFFSET)%(10*1000*1000))*100;
147 long int requestedTime;
148 long int requestedTimeNSEC;
150 requestedTime = currentTime.tv_sec + requestedSecs;
151 requestedTimeNSEC = currentTime.tv_nsec + requestedNSecs;
152 if (requestedTimeNSEC > 999999999)
155 requestedTimeNSEC -= 1000000000;
156 logger->log("Timers", Log::DEBUG, "Second rollover - CHECK FIXME");
159 return setTimerT(client, clientReference, requestedTime, requestedTimeNSEC);
162 int Timers::cancelTimer(TimerReceiver* client, int clientReference)
164 if (!initted) return 0;
166 logger->log("Timers", Log::DEBUG, "Starting cancel timer %p %i, list size = %i", client, clientReference, timerList.size());
168 //logger->log("Timers", Log::DEBUG, "Waiting for LOCK -TIMERS- MUTEX 4");
170 //logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 4");
171 TimerList::iterator i;
172 Timer* currentTimer = NULL;
173 for(i = timerList.begin(); i != timerList.end(); i++)
176 //logger->log("Timers", Log::DEBUG, "I: %p %i : %p %i", client, clientReference, currentTimer->client, currentTimer->clientReference);
177 if ((currentTimer->client == client) && (currentTimer->clientReference == clientReference))
180 logger->log("Timers", Log::DEBUG, "Removed timer for %p ref %i", client, clientReference);
182 // At this point currentTimer is not in the list but might still be nextTimer in the thread
185 if (i == timerList.end())
188 logger->log("Timers", Log::DEBUG, "No timer found in cancelTimer %p ref %i", client, clientReference);
189 //logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX 4");
194 resetThreadFlag = true;
195 threadSignalNoLock();
196 //logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX 4");
203 void Timers::threadMethod()
205 struct timespec nextTime;
206 Timer* nextTimer = NULL;
207 resetThreadFlag = true;
215 resetThreadFlag = false;
217 // Work out the next Timer
220 nextTime.tv_nsec = 0;
223 TimerList::iterator i;
224 Timer* currentTimer = NULL;
225 for(i = timerList.begin(); i != timerList.end(); i++)
230 nextTime.tv_sec = currentTimer->requestedTime.tv_sec;
231 nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec;
232 nextTimer = currentTimer;
236 if (currentTimer->requestedTime.tv_sec < nextTime.tv_sec)
238 nextTime.tv_sec = currentTimer->requestedTime.tv_sec;
239 nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec;
240 nextTimer = currentTimer;
242 else if (currentTimer->requestedTime.tv_sec == nextTime.tv_sec)
244 if (currentTimer->requestedTime.tv_nsec < nextTime.tv_nsec)
246 nextTime.tv_sec = currentTimer->requestedTime.tv_sec;
247 nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec;
248 nextTimer = currentTimer;
257 //## logger->log("Timers", Log::DEBUG, "List size: %i. nextTimerClient: %p/%i. nextTime.tv_sec: %li. nextTime.tv_nsec: %li", timerList.size(), nextTimer->client, nextTimer->clientReference, nextTime.tv_sec, nextTime.tv_nsec);
260 //logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX (1)");
261 threadWaitForSignalTimed(&nextTime);
262 //logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 5");
264 // unlocks in the wait
268 //logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX (2)");
269 threadWaitForSignal();
270 //logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 6");
271 // unlocks in the wait
274 // ok. we have been signalled or the time has run out
275 // This only gets signalled if it is to reset or die
277 // First check for die..
278 threadCheckExit(); // exiting thread with mutex locked
281 // This can be caused by an addition or deletion to the list
282 if (resetThreadFlag || (nextTimer == NULL)) continue;
286 Log::getInstance()->log("Timers", Log::DEBUG, "Timer firing for client %p ref %i", nextTimer->client, nextTimer->clientReference);
288 // send this timer to the timer receiver, via the command message queue
289 // so that the gui mutex is locked when it happens
291 Message* m = new Message(); // Timer call, must be injected into master mutex (this is generated outside the mutex)
293 m->to = nextTimer->client;
294 m->message = Message::TIMER;
295 m->parameter = nextTimer->clientReference;
297 if (!Command::getInstance()->postMessageIfNotBusy(m))
299 // GUI mutex was locked
300 // abort this timer delivery - it might be trying to be deleted!
303 // now unlock the timers mutex for a fraction of a second
304 // in case the gui thread is waiting on the timers mutex
306 //logger->log("Timers", Log::DEBUG, "un-LOCKED -TIMERS- MUTEX (3)");
307 //printf("\n\n\n WOOOOO \n\n\n The anti deadlock code is working!!! \n\n\n");
308 MILLISLEEP(20); // 10ms - too long? too short?
309 //logger->log("Timers", Log::DEBUG, "Waiting for LOCK -TIMERS- MUTEX 7");
311 //logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 7");
312 resetThreadFlag = true;
316 // timer was delivered
317 timerList.remove(nextTimer);
320 resetThreadFlag = true;
327 Avoiding deadlock using the timer class...
331 timer condwait finishes
332 timers is about to fire a timer
333 timers locks timers-mutex
335 user presses a button
336 command locks gui-mutex
338 timers tries to get gui-mutex
341 view wants to delete itself
342 view tries to deletetimer
343 goes into delete timer
344 waits on timers mutex
351 timers tries to get gui mutex
352 if mutex is locked already abort
354 wait a fraction of time
355 (allow other thread to lock timers mutex)
357 set reset flag to recalculate
358 - if timer has been cancelled next timer will be calced
359 - if timer has not been cancelled it will be called next