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
|
---|