]> git.vomp.tv Git - vompclient.git/blob - timers.cc
New timers system. New program structure for handling buttons/timers
[vompclient.git] / timers.cc
1 /*\r
2     Copyright 2004-2005 Chris Tallon\r
3 \r
4     This file is part of VOMP.\r
5 \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
10 \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
15 \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
19 */\r
20 \r
21 #include "timers.h"\r
22 \r
23 Timers* Timers::instance = NULL;\r
24 \r
25 Timers::Timers()\r
26 {\r
27   if (instance) return;\r
28   instance = this;\r
29   initted = false;\r
30 }\r
31 \r
32 Timers::~Timers()\r
33 {\r
34   instance = NULL;\r
35 }\r
36 \r
37 Timers* Timers::getInstance()\r
38 {\r
39   return instance;\r
40 }\r
41 \r
42 int Timers::init()\r
43 {\r
44   if (initted) return 0;\r
45   initted = true;\r
46   logger = Log::getInstance();\r
47 \r
48   logger->log("Timers", Log::DEBUG, "Timers init start");\r
49 \r
50   threadLock();\r
51   if (!threadStart())\r
52   {\r
53     shutdown();\r
54     return 0;\r
55   }\r
56   threadUnlock();\r
57 \r
58   logger->log("Timers", Log::DEBUG, "Timers init end");\r
59 \r
60   return 1;\r
61 }\r
62 \r
63 int Timers::shutdown()\r
64 {\r
65   if (!initted) return 0;\r
66   initted = false;\r
67 \r
68   logger->log("Timers", Log::DEBUG, "Timers shutdown start");\r
69 \r
70   threadStop();\r
71 \r
72   TimerList::iterator i;\r
73   UINT numTimers = timerList.size();\r
74   while(numTimers)\r
75   {\r
76     i = timerList.begin();\r
77     delete *i;\r
78     timerList.pop_front();\r
79     --numTimers;\r
80   }\r
81 \r
82   logger->log("Timers", Log::DEBUG, "Timers shutdown end");\r
83 \r
84   return 1;\r
85 }\r
86 \r
87 int Timers::setTimer(TimerReceiver* client, int clientReference, time_t requestedTime)\r
88 {\r
89   if (!initted) return 0;\r
90 \r
91   Timer* t = new Timer();\r
92   t->client = client;\r
93   t->clientReference = clientReference;\r
94   t->requestedTime.tv_sec = requestedTime;\r
95   t->requestedTime.tv_nsec = 0;\r
96 \r
97   threadLock();\r
98   timerList.push_back(t);\r
99   threadUnlock();\r
100   threadSignal();\r
101 \r
102   logger->log("Timers", Log::DEBUG, "Have set timer for %p ref %i", client, clientReference);\r
103 \r
104   return 1;\r
105 }\r
106 \r
107 int Timers::setTimer(TimerReceiver* client, int clientReference, struct timespec duration)\r
108 {\r
109   if (!initted) return 0;\r
110 \r
111   Timer* t = new Timer();\r
112   t->client = client;\r
113   t->clientReference = clientReference;\r
114 \r
115   struct timespec currentTime;\r
116   clock_gettime(CLOCK_REALTIME, &currentTime);\r
117 \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
121   {\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
125   }\r
126 \r
127   threadLock();\r
128   timerList.push_back(t);\r
129   threadUnlock();\r
130   threadSignal();\r
131 \r
132   logger->log("Timers", Log::DEBUG, "Have set timer for %p ref %i", client, clientReference);\r
133 \r
134   return 1;\r
135 }\r
136 \r
137 int Timers::cancelTimer(TimerReceiver* client, int clientReference)\r
138 {\r
139   if (!initted) return 0;\r
140 \r
141   threadLock();\r
142   TimerList::iterator i;\r
143   Timer* currentTimer = NULL;\r
144   for(i = timerList.begin(); i != timerList.end(); i++)\r
145   {\r
146     currentTimer = *i;\r
147     if ((currentTimer->client == client) && (currentTimer->clientReference == clientReference))\r
148     {\r
149       timerList.erase(i);\r
150       break;\r
151       // At this point currentTimer is not in the list but might still be nextTimer in the thread\r
152     }\r
153   }\r
154   if (i == timerList.end())\r
155   {\r
156     // no timer found\r
157     logger->log("Timers", Log::DEBUG, "No timer found in cancelTimer %p ref %i", client, clientReference);\r
158     threadUnlock();\r
159     return 0;\r
160   }\r
161 \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
164 \r
165   threadUnlock();\r
166   threadSignal();\r
167 \r
168   logger->log("Timers", Log::DEBUG, "Removed timer for %p ref %i", client, clientReference);\r
169 \r
170   return 1;\r
171 }\r
172 \r
173 void Timers::threadMethod()\r
174 {\r
175   struct timespec nextTime;\r
176   Timer* nextTimer = NULL;\r
177   resetThreadFlag = true;\r
178 \r
179   // locked here\r
180 \r
181   while(1)\r
182   {\r
183     if (resetThreadFlag)\r
184     {\r
185       resetThreadFlag = false;\r
186 \r
187       // Work out the next Timer\r
188 \r
189       nextTime.tv_sec = 0;\r
190       nextTime.tv_nsec = 0;\r
191       nextTimer = NULL;\r
192 \r
193       TimerList::iterator i;\r
194       Timer* currentTimer = NULL;\r
195       for(i = timerList.begin(); i != timerList.end(); i++)\r
196       {\r
197         currentTimer = *i;\r
198         if (!nextTimer)\r
199         {\r
200           nextTime.tv_sec = currentTimer->requestedTime.tv_sec;\r
201           nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec;\r
202           nextTimer = currentTimer;\r
203         }\r
204         else\r
205         {\r
206           if (currentTimer->requestedTime.tv_sec < nextTime.tv_sec)\r
207           {\r
208             nextTime.tv_sec = currentTimer->requestedTime.tv_sec;\r
209             nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec;\r
210             nextTimer = currentTimer;\r
211           }\r
212           else if (currentTimer->requestedTime.tv_sec == nextTime.tv_sec)\r
213           {\r
214             if (currentTimer->requestedTime.tv_nsec < nextTime.tv_nsec)\r
215             {\r
216               nextTime.tv_sec = currentTimer->requestedTime.tv_sec;\r
217               nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec;\r
218               nextTimer = currentTimer;\r
219             }\r
220           }\r
221         }\r
222       }\r
223 \r
224       if (nextTimer)\r
225       {\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
228 \r
229         // unlocks in the wait\r
230       }\r
231       else\r
232       {\r
233         threadWaitForSignal();\r
234         // unlocks in the wait\r
235       }\r
236 \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
239 \r
240       // First check for die..\r
241       threadCheckExit(); // exiting thread with mutex locked\r
242 \r
243       // Check for reset..\r
244       if (resetThreadFlag) continue;\r
245 \r
246       // timer ran out\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
250 \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
259 \r
260 \r
261       Log::getInstance()->log("Timers", Log::DEBUG, "Timer firing for client %p ref %i", nextTimer->client, nextTimer->clientReference);\r
262 \r
263       // send this timer to the timer receiver somehow\r
264       // possibly give to command message queue\r
265 \r
266       Message* m = new Message();\r
267       m->from = this;\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
272 \r
273       timerList.remove(nextTimer);\r
274       delete nextTimer;\r
275       nextTimer = NULL;\r
276 \r
277       resetThreadFlag = true;\r
278     }\r
279   }\r
280 }\r
281 \r
282 void Timers::threadPostStopCleanup()\r
283 {\r
284 }\r