source: source/ariba/communication/modules/transport/protlib/timer_module.cpp@ 5638

Last change on this file since 5638 was 5638, checked in by Christoph Mayer, 15 years ago

adress detection aufgeräumt, network info für bleutooth, data stream (hopeful crash fix), logging auf maemo nur warn, ...

File size: 18.9 KB
Line 
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
42namespace protlib {
43
44/** @addtogroup timermodule Timer Module
45 * @{
46 */
47
48 using namespace log;
49
50/***** class TimerMsg *****/
51
52TimerMsg::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. */
67TimerMsg::~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 */
73bool 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. */
80bool 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. */
85bool 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
89bool 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. */
101bool 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. */
106bool 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 */
113bool 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. */
130bool 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. */
146bool 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 */
159bool TimerMsg::set_elapsed() {
160 send_error = false;
161 action = ac_elapsed;
162 ok = true;
163 return ok;
164} // end set_elapsed
165
166bool TimerMsg::get_send_error() const {
167 return send_error;
168} // end get_send_error
169
170/** Set send_error flag and return old value. */
171bool 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
177TimerMsg::param_t TimerMsg::get_param1() const { return param1; }
178
179TimerMsg::param_t TimerMsg::get_param2() const { return param2; }
180
181void TimerMsg::get_params(param_t& p1, param_t& p2) const {
182 p1 = param1;
183 p2 = param2;
184} // end get_params
185
186bool TimerMsg::is_absolute() const { return (!relative); }
187
188bool 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 */
197TimerModuleParam::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. */
207TimerModule::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. */
216TimerModule::~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 */
226void 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 */
241void 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 */
310void 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. */
325bool 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. */
363bool 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. */
403bool 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. */
434bool 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 */
450void 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 */
488void 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
520bool 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 */
533message::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 */
543timer_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 */
552TimerMsg* 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 */
562void 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
575void 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
Note: See TracBrowser for help on using the repository browser.