2 Copyright 2004-2005 Chris Tallon
\r
4 This file is part of VOMP.
\r
6 VOMP is free software; you can redistribute it and/or modify
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 VOMP is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with VOMP; if not, write to the Free Software
\r
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
23 Timers* Timers::instance = NULL;
\r
27 if (instance) return;
\r
37 Timers* Timers::getInstance()
\r
44 if (initted) return 0;
\r
46 logger = Log::getInstance();
\r
48 logger->log("Timers", Log::DEBUG, "Timers init start");
\r
58 logger->log("Timers", Log::DEBUG, "Timers init end");
\r
63 int Timers::shutdown()
\r
65 if (!initted) return 0;
\r
68 logger->log("Timers", Log::DEBUG, "Timers shutdown start");
\r
72 TimerList::iterator i;
\r
73 UINT numTimers = timerList.size();
\r
76 i = timerList.begin();
\r
78 timerList.pop_front();
\r
82 logger->log("Timers", Log::DEBUG, "Timers shutdown end");
\r
87 int Timers::setTimer(TimerReceiver* client, int clientReference, time_t requestedTime)
\r
89 if (!initted) return 0;
\r
91 Timer* t = new Timer();
\r
93 t->clientReference = clientReference;
\r
94 t->requestedTime.tv_sec = requestedTime;
\r
95 t->requestedTime.tv_nsec = 0;
\r
98 timerList.push_back(t);
\r
102 logger->log("Timers", Log::DEBUG, "Have set timer for %p ref %i", client, clientReference);
\r
107 int Timers::setTimer(TimerReceiver* client, int clientReference, struct timespec duration)
\r
109 if (!initted) return 0;
\r
111 Timer* t = new Timer();
\r
112 t->client = client;
\r
113 t->clientReference = clientReference;
\r
115 struct timespec currentTime;
\r
116 clock_gettime(CLOCK_REALTIME, ¤tTime);
\r
118 t->requestedTime.tv_sec = currentTime.tv_sec + duration.tv_sec;
\r
119 t->requestedTime.tv_nsec = currentTime.tv_nsec + duration.tv_nsec;
\r
120 if (t->requestedTime.tv_nsec > 999999999)
\r
122 ++t->requestedTime.tv_sec;
\r
123 t->requestedTime.tv_nsec -= 1000000000;
\r
124 logger->log("Timers", Log::DEBUG, "Second rollover - CHECK FIXME");
\r
128 timerList.push_back(t);
\r
132 logger->log("Timers", Log::DEBUG, "Have set timer for %p ref %i", client, clientReference);
\r
137 int Timers::cancelTimer(TimerReceiver* client, int clientReference)
\r
139 if (!initted) return 0;
\r
142 TimerList::iterator i;
\r
143 Timer* currentTimer = NULL;
\r
144 for(i = timerList.begin(); i != timerList.end(); i++)
\r
147 if ((currentTimer->client == client) && (currentTimer->clientReference == clientReference))
\r
149 timerList.erase(i);
\r
151 // At this point currentTimer is not in the list but might still be nextTimer in the thread
\r
154 if (i == timerList.end())
\r
157 logger->log("Timers", Log::DEBUG, "No timer found in cancelTimer %p ref %i", client, clientReference);
\r
162 // FIXME how to delete a cancelled timer?
\r
163 // Just delete it, thread now checks to see if timer is still valid when it wakes up
\r
168 logger->log("Timers", Log::DEBUG, "Removed timer for %p ref %i", client, clientReference);
\r
173 void Timers::threadMethod()
\r
175 struct timespec nextTime;
\r
176 Timer* nextTimer = NULL;
\r
177 resetThreadFlag = true;
\r
183 if (resetThreadFlag)
\r
185 resetThreadFlag = false;
\r
187 // Work out the next Timer
\r
189 nextTime.tv_sec = 0;
\r
190 nextTime.tv_nsec = 0;
\r
193 TimerList::iterator i;
\r
194 Timer* currentTimer = NULL;
\r
195 for(i = timerList.begin(); i != timerList.end(); i++)
\r
200 nextTime.tv_sec = currentTimer->requestedTime.tv_sec;
\r
201 nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec;
\r
202 nextTimer = currentTimer;
\r
206 if (currentTimer->requestedTime.tv_sec < nextTime.tv_sec)
\r
208 nextTime.tv_sec = currentTimer->requestedTime.tv_sec;
\r
209 nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec;
\r
210 nextTimer = currentTimer;
\r
212 else if (currentTimer->requestedTime.tv_sec == nextTime.tv_sec)
\r
214 if (currentTimer->requestedTime.tv_nsec < nextTime.tv_nsec)
\r
216 nextTime.tv_sec = currentTimer->requestedTime.tv_sec;
\r
217 nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec;
\r
218 nextTimer = currentTimer;
\r
226 threadWaitForSignalTimed(&nextTime); // FIXME does this work if the time is in the past?
\r
227 logger->log("Timers", Log::DEBUG, "FIXME CHECK does waitforsignaltimed work for time < now?");
\r
229 // unlocks in the wait
\r
233 threadWaitForSignal();
\r
234 // unlocks in the wait
\r
237 // ok. we have been signalled or the time has run out
\r
238 // This only gets signalled if it is to reset or die
\r
240 // First check for die..
\r
241 threadCheckExit(); // exiting thread with mutex locked
\r
243 // Check for reset..
\r
244 if (resetThreadFlag) continue;
\r
247 // we have the lock, but we didn't in the wait. in case a timer was deleted during the wait,
\r
248 // check to see if object nextTimer is still in the list
\r
249 // FIXME - actually imlement the above
\r
251 // Ok. Get the main lock.
\r
252 // If we get the main lock, the view can't be deleted before the timer gets there.
\r
253 // (But will need to call Command->postMessageNoLock) to keep the lock
\r
254 // How to run message queue then?
\r
255 // Ah, no need to worry, if it is locked then main thread is waiting on getButtonPress and will
\r
256 // run the queue afterwards anyway
\r
257 // If we don't get the lock, lets say the view is deleted while we wait.
\r
258 // As part of its delete process, it will cancel its timer AND CAUSE DEADLOCK. DAMN.
\r
261 Log::getInstance()->log("Timers", Log::DEBUG, "Timer firing for client %p ref %i", nextTimer->client, nextTimer->clientReference);
\r
263 // send this timer to the timer receiver somehow
\r
264 // possibly give to command message queue
\r
266 Message* m = new Message();
\r
268 m->to = nextTimer->client;
\r
269 m->message = Message::TIMER;
\r
270 m->parameter = nextTimer->clientReference;
\r
271 Command::getInstance()->postMessage(m);
\r
273 timerList.remove(nextTimer);
\r
277 resetThreadFlag = true;
\r
282 void Timers::threadPostStopCleanup()
\r