[5641] | 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
|
---|