1 | /// ----------------------------------------*- mode: C++; -*-- |
---|
2 | /// @file timer_module.cpp |
---|
3 | /// timer module that maintains timers and triggers messages |
---|
4 | /// ---------------------------------------------------------- |
---|
5 | /// $Id: timer_module.cpp 2756 2007-08-06 12:51:39Z bless $ |
---|
6 | /// $HeadURL: https://svn.ipv6.tm.uka.de/nsis/protlib/trunk/src/timer_module.cpp $ |
---|
7 | // =========================================================== |
---|
8 | // |
---|
9 | // Copyright (C) 2005-2007, all rights reserved by |
---|
10 | // - Institute of Telematics, Universitaet Karlsruhe (TH) |
---|
11 | // |
---|
12 | // More information and contact: |
---|
13 | // https://projekte.tm.uka.de/trac/NSIS |
---|
14 | // |
---|
15 | // This program is free software; you can redistribute it and/or modify |
---|
16 | // it under the terms of the GNU General Public License as published by |
---|
17 | // the Free Software Foundation; version 2 of the License |
---|
18 | // |
---|
19 | // This program is distributed in the hope that it will be useful, |
---|
20 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
21 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
22 | // GNU General Public License for more details. |
---|
23 | // |
---|
24 | // You should have received a copy of the GNU General Public License along |
---|
25 | // with this program; if not, write to the Free Software Foundation, Inc., |
---|
26 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
---|
27 | // |
---|
28 | // =========================================================== |
---|
29 | /** @ingroup timermodule |
---|
30 | * The timer module provides a way for other modules to set timers via a |
---|
31 | * message and receive a message back on their queue when the timer goes |
---|
32 | * off. |
---|
33 | */ |
---|
34 | |
---|
35 | #include <sstream> |
---|
36 | |
---|
37 | #include "timer_module.h" |
---|
38 | #include "queuemanager.h" |
---|
39 | #include "logfile.h" |
---|
40 | #include "cleanuphandler.h" |
---|
41 | |
---|
42 | namespace protlib { |
---|
43 | |
---|
44 | /** @addtogroup timermodule Timer Module |
---|
45 | * @{ |
---|
46 | */ |
---|
47 | |
---|
48 | using namespace log; |
---|
49 | |
---|
50 | /***** class TimerMsg *****/ |
---|
51 | |
---|
52 | TimerMsg::TimerMsg(qaddr_t s, bool s_err) |
---|
53 | : message(type_timer,s), |
---|
54 | time_sec(0), |
---|
55 | time_msec(0), |
---|
56 | action(ac_ignore), |
---|
57 | param1(NULL), |
---|
58 | param2(NULL), |
---|
59 | ok(true), |
---|
60 | send_error(s_err), |
---|
61 | relative(true) |
---|
62 | { |
---|
63 | // Log(DEBUG_LOG,LOG_NORMAL,"TimerMsg","TimerMsg constructor. msgid:" << get_id()); |
---|
64 | } // end TimerMsg |
---|
65 | |
---|
66 | /** Destructor, does nothing. */ |
---|
67 | TimerMsg::~TimerMsg() {} |
---|
68 | |
---|
69 | |
---|
70 | /** Set result flag and get old value. |
---|
71 | * You should not set this, this is done by the timer module. |
---|
72 | */ |
---|
73 | bool TimerMsg::set_ok(bool r) { |
---|
74 | register bool old = ok; |
---|
75 | ok = r; |
---|
76 | return old; |
---|
77 | } // end set_ok |
---|
78 | |
---|
79 | /** Prepare message to start an absolute timer. */ |
---|
80 | bool TimerMsg::start_absolute(int32 sec, int32 msec, param_t p1, param_t p2) { |
---|
81 | return start(false,sec,msec,p1,p2); |
---|
82 | } // end start_absolute |
---|
83 | |
---|
84 | /** Prepare message to start a relative timer. */ |
---|
85 | bool TimerMsg::start_relative(int32 sec, int32 msec, param_t p1, param_t p2) { |
---|
86 | return start(true,sec,msec,p1,p2); |
---|
87 | } // end start_relative |
---|
88 | |
---|
89 | bool TimerMsg::start(bool rel, int32 sec, int32 msec, param_t p1, param_t p2) { |
---|
90 | time_sec = (sec<=0)?0:sec; |
---|
91 | time_msec = (msec<=0)?0:msec; |
---|
92 | param1 = p1; |
---|
93 | param2 = p2; |
---|
94 | action = ac_start; |
---|
95 | relative = rel; |
---|
96 | ok = true; |
---|
97 | return true; |
---|
98 | } // end start |
---|
99 | |
---|
100 | /** Restart an absolute timer. */ |
---|
101 | bool TimerMsg::restart_absolute(id_t id, int32 sec, int32 msec) { |
---|
102 | return restart(false,id,sec,msec); |
---|
103 | } // end restart_absolute |
---|
104 | |
---|
105 | /** Restart a relative timer. */ |
---|
106 | bool TimerMsg::restart_relative(id_t id, int32 sec, int32 msec) { |
---|
107 | return restart(true,id,sec,msec); |
---|
108 | } // end restart_relative |
---|
109 | |
---|
110 | /** restart timer |
---|
111 | * please note that this method actually overwrites the id of the message(!) |
---|
112 | */ |
---|
113 | bool TimerMsg::restart(bool rel, id_t id, int32 sec, int32 msec) { |
---|
114 | relative = rel; |
---|
115 | if (id && set_id(id)) { |
---|
116 | time_sec = (sec<=0)?0:sec; |
---|
117 | time_msec = (msec<=0)?0:msec; |
---|
118 | action = ac_restart; |
---|
119 | ok = true; |
---|
120 | } else { |
---|
121 | time_sec = 0; |
---|
122 | time_msec = 0; |
---|
123 | action = ac_ignore; |
---|
124 | ok = false; |
---|
125 | } // end if id |
---|
126 | return ok; |
---|
127 | } // end restart |
---|
128 | |
---|
129 | /** Stop a timer. */ |
---|
130 | bool TimerMsg::stop(id_t id) { |
---|
131 | relative = false; |
---|
132 | time_sec = 0; |
---|
133 | time_msec = 0; |
---|
134 | param1 = param2 = NULL; |
---|
135 | if (id && set_id(id)) { |
---|
136 | action = ac_stop; |
---|
137 | ok = true; |
---|
138 | } else { |
---|
139 | action = ac_ignore; |
---|
140 | ok = false; |
---|
141 | } // end if id |
---|
142 | return ok; |
---|
143 | } // end stop |
---|
144 | |
---|
145 | /** Stop all running timers. */ |
---|
146 | bool TimerMsg::stop_all() { |
---|
147 | relative = false, |
---|
148 | time_sec = 0; |
---|
149 | time_msec = 0; |
---|
150 | param1 = param2 = NULL; |
---|
151 | action = ac_stop_all; |
---|
152 | ok = true; |
---|
153 | return true; |
---|
154 | } // end stop_all |
---|
155 | |
---|
156 | /** Prepare message for sending it back as a reply message from the |
---|
157 | * TimerModule when its timer expires. |
---|
158 | */ |
---|
159 | bool TimerMsg::set_elapsed() { |
---|
160 | send_error = false; |
---|
161 | action = ac_elapsed; |
---|
162 | ok = true; |
---|
163 | return ok; |
---|
164 | } // end set_elapsed |
---|
165 | |
---|
166 | bool TimerMsg::get_send_error() const { |
---|
167 | return send_error; |
---|
168 | } // end get_send_error |
---|
169 | |
---|
170 | /** Set send_error flag and return old value. */ |
---|
171 | bool TimerMsg::set_send_error(bool f) { |
---|
172 | register bool o = send_error; |
---|
173 | send_error = f; |
---|
174 | return o; |
---|
175 | } // end set_send_error |
---|
176 | |
---|
177 | TimerMsg::param_t TimerMsg::get_param1() const { return param1; } |
---|
178 | |
---|
179 | TimerMsg::param_t TimerMsg::get_param2() const { return param2; } |
---|
180 | |
---|
181 | void TimerMsg::get_params(param_t& p1, param_t& p2) const { |
---|
182 | p1 = param1; |
---|
183 | p2 = param2; |
---|
184 | } // end get_params |
---|
185 | |
---|
186 | bool TimerMsg::is_absolute() const { return (!relative); } |
---|
187 | |
---|
188 | bool TimerMsg::is_relative() const { return relative; } |
---|
189 | |
---|
190 | /***** struct TimerModuleParam *****/ |
---|
191 | |
---|
192 | /** @param sleep_time default sleep time |
---|
193 | * @param sua send messages until aborted or just until stopped |
---|
194 | * @param see send error messages as expedited data |
---|
195 | * @param sre send reply messages as expedited data |
---|
196 | */ |
---|
197 | TimerModuleParam::TimerModuleParam(uint32 sleep_time, bool sua, bool see, bool sre) |
---|
198 | : ThreadParam(sleep_time, "TimerModule", 2), send_until_abort(sua), |
---|
199 | source(message::qaddr_timer), |
---|
200 | send_error_expedited(see), send_reply_expedited(sre) { |
---|
201 | // nothing more to do |
---|
202 | } // end constructor TimerModuleParam |
---|
203 | |
---|
204 | /***** class TimerModule *****/ |
---|
205 | |
---|
206 | /** Set parameters. */ |
---|
207 | TimerModule::TimerModule(const TimerModuleParam& p) |
---|
208 | : Thread(p), timerparam(p) { |
---|
209 | tmap.clear(); |
---|
210 | // register queue |
---|
211 | QueueManager::instance()->register_queue(get_fqueue(),p.source); |
---|
212 | DLog(timerparam.name, "Creating TimerModule object"); |
---|
213 | } // end constructor TimerModule |
---|
214 | |
---|
215 | /** Stop all running timers. */ |
---|
216 | TimerModule::~TimerModule() { |
---|
217 | stop_all_timers(); |
---|
218 | DLog(timerparam.name, "Destroying TimerModule object"); |
---|
219 | QueueManager::instance()->unregister_queue(timerparam.source); |
---|
220 | |
---|
221 | } // end destructor TimerModule |
---|
222 | |
---|
223 | /** Devide Threads in thos which process the queue and those which process |
---|
224 | * expired timers. |
---|
225 | */ |
---|
226 | void TimerModule::main_loop(uint32 nr) { |
---|
227 | Log(INFO_LOG,LOG_NORMAL, timerparam.name, "Starting " << timerparam.name << " thread #" << nr << ", " << ((nr%2) ? "processing input queue" : "processing timer callbacks")); |
---|
228 | |
---|
229 | if (nr%2) process_queue(); |
---|
230 | else process_elapsed_timers(); |
---|
231 | |
---|
232 | Log(INFO_LOG,LOG_NORMAL, timerparam.name,"Thread #" << nr << " stopped"); |
---|
233 | } // end main_loop |
---|
234 | |
---|
235 | /** Wait for incomming mesages and evaluate message action. |
---|
236 | * Messages are accepted until the module is asked to stop. |
---|
237 | * |
---|
238 | * The module mutex inherited from the Thread base class is locked here, so all |
---|
239 | * called member functions are called inside a critical section if necessary. |
---|
240 | */ |
---|
241 | void TimerModule::process_queue() { |
---|
242 | uint32 wait = timerparam.sleep_time*1000; |
---|
243 | message* msg = NULL; |
---|
244 | TimerMsg* tmsg = NULL; |
---|
245 | FastQueue* fq = QueueManager::instance()->get_queue(message::qaddr_timer); |
---|
246 | bool opresult = false; |
---|
247 | if (!fq) { |
---|
248 | Log(ERROR_LOG,LOG_ALERT, timerparam.name," cannot find input queue"); |
---|
249 | return; |
---|
250 | } // end if not fq |
---|
251 | // wait for messages |
---|
252 | while (get_state()==STATE_RUN) { |
---|
253 | msg = fq->dequeue_timedwait(wait); |
---|
254 | if (msg) { |
---|
255 | if (msg->get_type()==message::type_timer) { |
---|
256 | tmsg = dynamic_cast<TimerMsg*>(msg); |
---|
257 | if (tmsg) { |
---|
258 | // begin critical section |
---|
259 | lock(); // install_cleanup_thread_lock(TimerModule,this); |
---|
260 | if (tmsg->is_ok()) { |
---|
261 | // evaluate action |
---|
262 | switch (tmsg->get_action()) { |
---|
263 | case TimerMsg::ac_ignore: |
---|
264 | // do nothing |
---|
265 | Log(DEBUG_LOG,LOG_UNIMP, timerparam.name,"received message with action set to ignore"); |
---|
266 | opresult = true; |
---|
267 | break; |
---|
268 | case TimerMsg::ac_start: |
---|
269 | opresult = start_timer(tmsg); |
---|
270 | break; |
---|
271 | case TimerMsg::ac_restart: |
---|
272 | opresult = restart_timer(tmsg); |
---|
273 | break; |
---|
274 | case TimerMsg::ac_stop: |
---|
275 | opresult = stop_timer(tmsg); |
---|
276 | break; |
---|
277 | case TimerMsg::ac_stop_all: |
---|
278 | opresult = stop_all_timers(); |
---|
279 | break; |
---|
280 | default: |
---|
281 | ERRLog(timerparam.name, "Wrong action " << tmsg->get_action() << " in message from " << tmsg->get_qaddr_name() << " to " << message::get_qaddr_name(timerparam.source) ); |
---|
282 | |
---|
283 | opresult = false; |
---|
284 | } // end switch get_action |
---|
285 | } else { |
---|
286 | Log(DEBUG_LOG,LOG_UNIMP, timerparam.name,"received message in invalid state, mid " << tmsg->get_id() ); |
---|
287 | opresult = false; |
---|
288 | } // if tmsg->is_ok() |
---|
289 | // error handling, message disposing |
---|
290 | send_error_or_dispose(tmsg,opresult); |
---|
291 | // end critical section |
---|
292 | unlock(); // uninstall_cleanup(1); |
---|
293 | } else { |
---|
294 | Log(ERROR_LOG,LOG_ALERT, timerparam.name, "Cannot cast message from " << msg->get_qaddr_name() << " of type " << msg->get_type_name() << " to TimerMsg"); |
---|
295 | delete msg; |
---|
296 | } // end if tmsg |
---|
297 | } else { |
---|
298 | ERRLog(timerparam.name,"received message that is not of type_timer from " << msg->get_qaddr_name() << ", type was " << msg->get_type_name()); |
---|
299 | delete msg; |
---|
300 | } // end if type |
---|
301 | } // end if msg |
---|
302 | } // end while running |
---|
303 | } // end process_queue |
---|
304 | |
---|
305 | /** Check if timers expired and send reply messages. |
---|
306 | * Reply messages are sent until the module is asked to abort if |
---|
307 | * the flag send_until_abort is set true. Otherwise no messages are sent |
---|
308 | * after a stop request. |
---|
309 | */ |
---|
310 | void TimerModule::process_elapsed_timers() { |
---|
311 | state_t end_state; |
---|
312 | uint32 num = 0; |
---|
313 | uint32 sleeptime = timerparam.sleep_time*1000; |
---|
314 | if (timerparam.send_until_abort) end_state = STATE_ABORT; |
---|
315 | else end_state = STATE_STOP; |
---|
316 | while(get_state()!=end_state) { |
---|
317 | num = tm.check_timers_wait(sleeptime); |
---|
318 | if (num) { |
---|
319 | Log(DEBUG_LOG,LOG_UNIMP, timerparam.name,"got " << num << " elapsed timer(s)"); |
---|
320 | } // end if num |
---|
321 | } // end while state |
---|
322 | } // end process_elapsed_timers |
---|
323 | |
---|
324 | /** Starts a timer and stores its ID and the reply message in the hash maps. */ |
---|
325 | bool TimerModule::start_timer(TimerMsg* m) { |
---|
326 | timer_id_t tid = 0; |
---|
327 | bool res = true; |
---|
328 | message::id_t mid = m->get_id(); |
---|
329 | bool relative = m->is_relative(); |
---|
330 | int32 sec = 0; |
---|
331 | int32 msec = 0; |
---|
332 | if (mid) { |
---|
333 | // lookup timer ID in map |
---|
334 | if ((tid=tmap.lookup_tid(mid))) { |
---|
335 | ERRLog(timerparam.name, m->get_qaddr_name() << " tried to start a timer with mid " << mid << ", but there is already a timer " << tid); |
---|
336 | res = false; |
---|
337 | } else { |
---|
338 | // start timer |
---|
339 | m->get_time(sec,msec); |
---|
340 | if (relative) tid = tm.start_relative(this,sec,msec,NULL); |
---|
341 | else tid = tm.start_absolute(this,sec,msec,NULL); |
---|
342 | if (tid) { |
---|
343 | // insert in map |
---|
344 | tmap.insert(tid,m); |
---|
345 | // timer successfully started |
---|
346 | Log(EVENT_LOG,LOG_UNIMP, timerparam.name, "Timer " << tid << " (" << sec << "s " << msec << "ms) started for " |
---|
347 | << m->get_qaddr_name() << " with mid " << mid); |
---|
348 | res = true; |
---|
349 | } else { |
---|
350 | // timer not started |
---|
351 | ERRLog(timerparam.name, "TimerManager in " << timerparam.name << " is unable to start a timer for " << m->get_qaddr_name()); |
---|
352 | res = false; |
---|
353 | } // end if tid |
---|
354 | } // end if lookup repmsg |
---|
355 | } else { |
---|
356 | ERRLog(timerparam.name, m->get_qaddr_name() << " tried to start a timer with message ID 0"); |
---|
357 | res = false; |
---|
358 | } // end if repmsg |
---|
359 | return res; |
---|
360 | } // end start_timer |
---|
361 | |
---|
362 | /** Restarts a timer and stores its ID and the reply message in the hash maps. */ |
---|
363 | bool TimerModule::restart_timer(TimerMsg* m) { |
---|
364 | timer_id_t tid = 0; |
---|
365 | bool res = true; |
---|
366 | message::id_t mid = m->get_id(); |
---|
367 | bool relative = m->is_relative(); |
---|
368 | TimerMsg* repmsg = NULL; |
---|
369 | int32 sec = 0; |
---|
370 | int32 msec = 0; |
---|
371 | if (mid) { |
---|
372 | // lookup timer_id and reply message for mid in map |
---|
373 | tid = tmap.lookup_tid(mid); |
---|
374 | repmsg = tmap.lookup_msg(tid); |
---|
375 | if (tid && repmsg) { |
---|
376 | // restart timer |
---|
377 | m->get_time(sec,msec); |
---|
378 | if (relative) res = tm.restart_relative(tid,sec,msec); |
---|
379 | else res = tm.restart_absolute(tid,sec,msec); |
---|
380 | if (res) { |
---|
381 | // modify reply message |
---|
382 | repmsg->restart(relative,mid,sec,msec); |
---|
383 | // timer successfully restarted |
---|
384 | DLog(timerparam.name, "Timer " << tid << ", mid " << mid << " restarted for " << m->get_qaddr_name()); |
---|
385 | } else { |
---|
386 | // timer not restarted |
---|
387 | ERRLog(timerparam.name, "TimerManager in " << timerparam.name << " is unable to restart a timer for " << m->get_qaddr_name() << ", mid " << mid); |
---|
388 | } // end if res |
---|
389 | } else { |
---|
390 | if (tid) ERRLog(timerparam.name, m->get_qaddr_name() << " tried to restart a timer with mid " << mid << ": or no reply message for timer found"); |
---|
391 | if (repmsg) ERRLog(timerparam.name, m->get_qaddr_name() << " tried to restart timer with mid " << mid << ": timer not found"); |
---|
392 | if ((!repmsg) & (!tid)) ERRLog(timerparam.name, m->get_qaddr_name() << " tried to restart timer with mid " << mid << ": neither timer nor reply message found"); |
---|
393 | res = false; |
---|
394 | } // end if tid |
---|
395 | } else { |
---|
396 | ERRLog(timerparam.name, m->get_qaddr_name() << " tried to restart a timer with an invalid message ID"); |
---|
397 | res = false; |
---|
398 | } // end if repmsg |
---|
399 | return res; |
---|
400 | } // end restart_timer |
---|
401 | |
---|
402 | /** Stop a timer and remove its ID and reply message from the hash maps. */ |
---|
403 | bool TimerModule::stop_timer(TimerMsg* m) { |
---|
404 | timer_id_t tid = 0; |
---|
405 | bool res = true; |
---|
406 | message::id_t mid = m->get_id(); |
---|
407 | if (mid) { |
---|
408 | // lookup timer_id for mid in map |
---|
409 | tid = tmap.lookup_tid(mid); |
---|
410 | if (tid) { |
---|
411 | // stop timer |
---|
412 | res = tm.stop(tid); |
---|
413 | if (res) { |
---|
414 | // delete from map |
---|
415 | tmap.erase(tid,mid,true); |
---|
416 | // timer stopped |
---|
417 | DLog(timerparam.name, "Stopped timer " << tid << ", mid " << mid << " for " << m->get_qaddr_name()); |
---|
418 | } else { |
---|
419 | // timer not stopped |
---|
420 | ERRLog(timerparam.name, "TimerManager in " << timerparam.name << " is unable to stop timer " << tid << ", mid " << mid << " for " << m->get_qaddr_name()); |
---|
421 | } // end if tid |
---|
422 | } else { |
---|
423 | ERRLog(timerparam.name, m->get_qaddr_name() << " tried to stop a non-existing timer with mid " << mid); |
---|
424 | res = false; |
---|
425 | } // end if tid |
---|
426 | } else { |
---|
427 | ERRLog(timerparam.name, m->get_qaddr_name() << " tried to stop a timer with an invalid message ID"); |
---|
428 | res = false; |
---|
429 | } // end if repmsg |
---|
430 | return res; |
---|
431 | } // end stop_timer |
---|
432 | |
---|
433 | /** Stop all timers and clear the hash maps. */ |
---|
434 | bool TimerModule::stop_all_timers() { |
---|
435 | uint32 num = 0; |
---|
436 | // clear map |
---|
437 | tmap.clear(true); |
---|
438 | // clear TimerManager |
---|
439 | num = tm.stop_all(); |
---|
440 | Log(DEBUG_LOG,LOG_UNIMP, timerparam.name,"stopped all timers, num " << num); |
---|
441 | return true; |
---|
442 | } // end stop_all_timers |
---|
443 | |
---|
444 | /** Send back error message. |
---|
445 | * If no error is necessary, the message is disposed. |
---|
446 | * @param m message that is changed to an error message if |
---|
447 | * its flags are set appropriately. |
---|
448 | * @param ok success or error? |
---|
449 | */ |
---|
450 | void TimerModule::send_error_or_dispose(TimerMsg* m, bool ok) { |
---|
451 | message::qaddr_t dest; |
---|
452 | if (!m) return; |
---|
453 | |
---|
454 | #ifndef _NO_LOGGING |
---|
455 | message::id_t mid = m->get_id(); // only used for logging |
---|
456 | #endif |
---|
457 | |
---|
458 | // Do we send errors? |
---|
459 | if ((!ok) && m->get_send_error()) ok = false; |
---|
460 | else ok = true; |
---|
461 | if (ok) { |
---|
462 | // dispose if not a start message |
---|
463 | if (m->get_action()!=TimerMsg::ac_start) { |
---|
464 | dest = m->get_source(); |
---|
465 | delete m; |
---|
466 | //Log(DEBUG_LOG,LOG_UNIMP, timerparam.name,"disposed message " << mid << " from " << message::get_qaddr_name(dest)); |
---|
467 | } // end if dispose message |
---|
468 | } else { |
---|
469 | // send error |
---|
470 | dest = m->get_source(); |
---|
471 | m->set_ok(false); |
---|
472 | if (m->send(timerparam.source,dest,timerparam.send_error_expedited)) { |
---|
473 | Log(DEBUG_LOG,LOG_UNIMP, timerparam.name,"sent error message w/ mid " << mid << " to " << message::get_qaddr_name(dest)); |
---|
474 | } else { |
---|
475 | ERRLog(timerparam.name,"cannot send error message w/ mid " << mid << " to " << message::get_qaddr_name(dest) << ", disposing it now"); |
---|
476 | delete m; |
---|
477 | } // end if sent error |
---|
478 | } // end if ok |
---|
479 | } // end send_error_or_dispose |
---|
480 | |
---|
481 | /** This is the callback for the TimerManager used by the TimerModule object. |
---|
482 | * @param timer timer ID |
---|
483 | * @param callback_param additional callback parameter. |
---|
484 | * |
---|
485 | * The module mutex inherited from the Thread base class is locked here, so all |
---|
486 | * called member functions are called inside a critical section if necessary. |
---|
487 | */ |
---|
488 | void TimerModule::timer_expired(timer_id_t timer, timer_callback_param_t callback_param) { |
---|
489 | TimerMsg* msg = NULL; |
---|
490 | message::qaddr_t dest; |
---|
491 | message::id_t mid = 0; |
---|
492 | // begin critical section |
---|
493 | lock(); // install_cleanup_thread_lock(TimerModule,this); |
---|
494 | // get reply message |
---|
495 | msg = tmap.lookup_msg(timer); |
---|
496 | if (msg) { |
---|
497 | // store message ID for erasing this record from the map |
---|
498 | mid = msg->get_id(); |
---|
499 | // send message |
---|
500 | dest = msg->get_source(); |
---|
501 | if (msg->set_elapsed() && msg->send_back(timerparam.source,timerparam.send_reply_expedited)) { |
---|
502 | Log(DEBUG_LOG,LOG_UNIMP, timerparam.name,"sent reply mid " << mid << " for elapsed timer " << timer << " to " << message::get_qaddr_name(dest)); |
---|
503 | } else { |
---|
504 | ERRLog(timerparam.name,"cannot send reply mid " << mid << " for elapsed timer " << timer <<" to " << message::get_qaddr_name(dest)); |
---|
505 | // dispose message |
---|
506 | delete msg; |
---|
507 | } // end if send_back |
---|
508 | } else { |
---|
509 | // may be timer has been stopped |
---|
510 | DLog(timerparam.name, "TimerModule::timer_expired cannot find reply message for a timer " << timer << ". Maybe the timer has been stopped"); |
---|
511 | } // end if msg |
---|
512 | // erase (timer,mid) without disposing the reply message |
---|
513 | tmap.erase(timer,mid,false); |
---|
514 | // end critical section |
---|
515 | unlock(); // uninstall_cleanup(1); |
---|
516 | } // end timer_expired |
---|
517 | |
---|
518 | /***** class TimerModule::TimerMap *****/ |
---|
519 | |
---|
520 | bool TimerModule::TimerMap::insert(timer_id_t tid, TimerMsg* m) { |
---|
521 | if (tid && m) { |
---|
522 | message::id_t mid = m->get_id(); |
---|
523 | tid2mid[tid] = mid; |
---|
524 | mid2tid[mid] = tid; |
---|
525 | tid2msg[tid] = m; |
---|
526 | return true; |
---|
527 | } else return false; |
---|
528 | } // end insert |
---|
529 | |
---|
530 | /** Returns the message ID of the timer bound to timer ID or 0 if not |
---|
531 | * found, since every timer must have an ID <> 0. |
---|
532 | */ |
---|
533 | message::id_t TimerModule::TimerMap::lookup_mid(timer_id_t tid) const { |
---|
534 | const_tid2mid_it_t hit; |
---|
535 | hit = tid2mid.find(tid); |
---|
536 | if (hit!=tid2mid.end()) return hit->second; |
---|
537 | else return 0; |
---|
538 | } // end lookup |
---|
539 | |
---|
540 | /** Returns the timer-ID of the timer bound to the message ID or 0 if not |
---|
541 | * found, since 0 is never used as a timer ID. |
---|
542 | */ |
---|
543 | timer_id_t TimerModule::TimerMap::lookup_tid(message::id_t mid) const { |
---|
544 | const_mid2tid_it_t hit; |
---|
545 | if ((hit=mid2tid.find(mid))!=mid2tid.end()) return hit->second; |
---|
546 | else return 0; |
---|
547 | } // end lookup |
---|
548 | |
---|
549 | /** Returns the timer message of the timer bound to timer ID or NULL if not |
---|
550 | * found. |
---|
551 | */ |
---|
552 | TimerMsg* TimerModule::TimerMap::lookup_msg(timer_id_t tid) const { |
---|
553 | const_tid2msg_it_t hit; |
---|
554 | hit = tid2msg.find(tid); |
---|
555 | if (hit!=tid2msg.end()) return hit->second; |
---|
556 | else return NULL; |
---|
557 | } // end lookup_msg |
---|
558 | |
---|
559 | /** Please be sure that timer ID and message ID are bound to the same timer. |
---|
560 | * No checking is done! |
---|
561 | */ |
---|
562 | void TimerModule::TimerMap::erase(timer_id_t tid, message::id_t mid, bool dispose) { |
---|
563 | TimerMsg* m = NULL; |
---|
564 | if (tid) { |
---|
565 | if (dispose) { |
---|
566 | m = lookup_msg(tid); |
---|
567 | if (m) delete m; |
---|
568 | } // end if dispose |
---|
569 | tid2mid.erase(tid); |
---|
570 | tid2msg.erase(tid); |
---|
571 | } // end if tid |
---|
572 | if (mid) mid2tid.erase(mid); |
---|
573 | } // end erase |
---|
574 | |
---|
575 | void TimerModule::TimerMap::clear(bool dispose) { |
---|
576 | const_tid2msg_it_t hit; |
---|
577 | if (dispose) { |
---|
578 | for (hit=tid2msg.begin();hit!=tid2msg.end();hit++) { |
---|
579 | if (hit->second) delete hit->second; |
---|
580 | } // end for hit |
---|
581 | } // end if dispose |
---|
582 | tid2mid.clear(); |
---|
583 | tid2msg.clear(); |
---|
584 | mid2tid.clear(); |
---|
585 | } // end clear |
---|
586 | |
---|
587 | //@} |
---|
588 | |
---|
589 | } // end namespace protlib |
---|