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