Timer.cc

Go to the documentation of this file.
00001 /*
00002  * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By
00003  * downloading, copying, installing or using the software you agree to
00004  * this license. If you do not agree to this license, do not download,
00005  * install, copy or use the software.
00006  * 
00007  * Intel Open Source License 
00008  * 
00009  * Copyright (c) 2004 Intel Corporation. All rights reserved. 
00010  * 
00011  * Redistribution and use in source and binary forms, with or without
00012  * modification, are permitted provided that the following conditions are
00013  * met:
00014  * 
00015  *   Redistributions of source code must retain the above copyright
00016  *   notice, this list of conditions and the following disclaimer.
00017  * 
00018  *   Redistributions in binary form must reproduce the above copyright
00019  *   notice, this list of conditions and the following disclaimer in the
00020  *   documentation and/or other materials provided with the distribution.
00021  * 
00022  *   Neither the name of the Intel Corporation nor the names of its
00023  *   contributors may be used to endorse or promote products derived from
00024  *   this software without specific prior written permission.
00025  *  
00026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00027  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00028  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00029  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR
00030  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00031  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00032  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00033  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00034  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00035  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00036  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037  */
00038 
00039 #include <stdio.h>
00040 #include <stdlib.h>
00041 #include <unistd.h>
00042 #include <errno.h>
00043 #include <sys/time.h>
00044 #include <sys/poll.h>
00045 
00046 #include "Timer.h"
00047 #include "io/IO.h"
00048 #include "../util/InitSequencer.h"
00049 
00050 namespace oasys {
00051 
00052 template <> TimerSystem* Singleton<TimerSystem>::instance_ = 0;
00053 
00054 //----------------------------------------------------------------------
00055 TimerSystem::TimerSystem()
00056     : Logger("TimerSystem", "/timer"),
00057       system_lock_(new SpinLock()),
00058       notifier_(logpath_),
00059       timers_()
00060 {
00061     memset(handlers_, 0, sizeof(handlers_));
00062     memset(signals_, 0, sizeof(signals_));
00063     sigfired_ = false;
00064 }
00065 
00066 //----------------------------------------------------------------------
00067 void
00068 TimerSystem::schedule_at(struct timeval *when, Timer* timer)
00069 {
00070     ScopeLock l(system_lock_, "TimerSystem::schedule_at");
00071     
00072     struct timeval now;
00073     
00074     if (when == 0) {
00075         // special case a NULL timeval as an immediate timer
00076         log_debug("scheduling timer %p immediately", timer);
00077         
00078         timer->when_.tv_sec = 0;
00079         timer->when_.tv_usec = 0;
00080     } else {
00081         ::gettimeofday(&now, 0);
00082         log_debug("scheduling timer %p in %ld ms at %u:%u",
00083                   timer, TIMEVAL_DIFF_MSEC(*when, now),
00084                   (u_int)when->tv_sec, (u_int)when->tv_usec);
00085         
00086         timer->when_ = *when;
00087     }
00088     
00089     if (timer->pending_) {
00090         // XXX/demmer this could scan through the heap, find the right
00091         // timer and re-sort the heap, but it seems better to just
00092         // expose a new "reschedule" api call to make it explicit that
00093         // it's a different operation.
00094         PANIC("rescheduling timers not implemented");
00095     }
00096     
00097     timer->pending_ = 1;
00098     timer->cancelled_ = 0;
00099     timers_.push(timer);
00100 
00101     notifier_.signal();
00102 }
00103 
00104 //----------------------------------------------------------------------
00105 void
00106 TimerSystem::schedule_in(int milliseconds, Timer* timer)
00107 {
00108     struct timeval when;
00109     ::gettimeofday(&when, 0);
00110     when.tv_sec += milliseconds / 1000;
00111     when.tv_usec += (milliseconds % 1000) * 1000;
00112     while (when.tv_usec > 1000000) {
00113         when.tv_sec += 1;
00114         when.tv_usec -= 1000000;
00115     }
00116     
00117     return schedule_at(&when, timer);
00118 }
00119 
00120 //----------------------------------------------------------------------
00121 void
00122 TimerSystem::schedule_immediate(Timer* timer)
00123 {
00124     return schedule_at(0, timer);
00125 }
00126 
00127 //----------------------------------------------------------------------
00128 bool
00129 TimerSystem::cancel(Timer* timer)
00130 {
00131     ScopeLock l(system_lock_, "TimerSystem::cancel");
00132 
00133     // There's no good way to get a timer out of a heap, so we let it
00134     // stay in there and mark it as cancelled so when it bubbles to
00135     // the top, we don't bother with it. This makes rescheduling a
00136     // single timer instance tricky...
00137     if (timer->pending_) {
00138         timer->cancelled_ = true;
00139         return true;
00140     }
00141     
00142     return false;
00143 }
00144 
00145 //----------------------------------------------------------------------
00146 void
00147 TimerSystem::post_signal(int sig)
00148 {
00149     TimerSystem* _this = TimerSystem::instance();
00150 
00151     _this->sigfired_ = true;
00152     _this->signals_[sig] = true;
00153     
00154     _this->notifier_.signal();
00155 }
00156 
00157 //----------------------------------------------------------------------
00158 void
00159 TimerSystem::add_sighandler(int sig, sighandlerfn_t* handler)
00160 {
00161     log_debug("adding signal handler 0x%x for signal %d",
00162               (u_int)handler, sig);
00163     handlers_[sig] = handler;
00164     signal(sig, post_signal);
00165 }
00166 
00167 //----------------------------------------------------------------------
00168 void
00169 TimerSystem::pop_timer(const struct timeval& now)
00170 {
00171     ASSERT(system_lock_->is_locked_by_me());
00172     
00173     Timer* next_timer = timers_.top();
00174     timers_.pop();
00175 
00176     // clear the pending bit since it could get rescheduled 
00177     ASSERT(next_timer->pending_);
00178     next_timer->pending_ = 0;
00179 
00180     int late = TIMEVAL_DIFF_MSEC(now, next_timer->when());
00181     if (late > 2000) {
00182         log_warn("timer thread running slow -- timer is %d msecs late", late);
00183     }
00184         
00185     if (! next_timer->cancelled_) {
00186         log_debug("popping timer %p at %u.%u", next_timer,
00187                   (u_int)now.tv_sec, (u_int)now.tv_usec);
00188         next_timer->timeout(now);
00189     } else {
00190         log_debug("popping cancelled timer %p at %u.%u", next_timer,
00191                   (u_int)now.tv_sec, (u_int)now.tv_usec);
00192         next_timer->cancelled_ = 0;
00193         
00194         if (next_timer->cancel_flags_ == Timer::DELETE_ON_CANCEL) {
00195             log_debug("deleting cancelled timer %p at %u.%u", next_timer,
00196                       (u_int)now.tv_sec, (u_int)now.tv_usec);
00197             delete next_timer;
00198         }
00199     }
00200 }
00201 
00202 //----------------------------------------------------------------------
00203 void
00204 TimerSystem::handle_signals()
00205 {        
00206     // KNOWN ISSUE: if a second signal is received before the first is
00207     // handled it is ignored, i.e. sending signal gives at-least-once
00208     // semantics, not exactly-once semantics
00209     if (sigfired_) {
00210         sigfired_ = 0;
00211         
00212         log_debug("sigfired_ set, calling registered handlers");
00213         for (int i = 0; i < NSIG; ++i) {
00214             if (signals_[i]) {
00215                 handlers_[i](i);
00216                 signals_[i] = 0;
00217             }
00218         }
00219     }
00220 }
00221 
00222 //----------------------------------------------------------------------
00223 int
00224 TimerSystem::run_expired_timers()
00225 {
00226     ScopeLock l(system_lock_, "TimerSystem::run_expired_timers");
00227     
00228     handle_signals();
00229     
00230     struct timeval now;    
00231     while (! timers_.empty()) 
00232     {
00233         if (::gettimeofday(&now, 0) != 0) {
00234             PANIC("gettimeofday");
00235         }
00236 
00237         Timer* next_timer = timers_.top();
00238         if (TIMEVAL_LT(now, next_timer->when_)) {
00239             int diff_ms = TIMEVAL_DIFF_MSEC(next_timer->when_, now);
00240             ASSERT(diff_ms >= 0);
00241             
00242             // there's a chance that we're within a millisecond of the
00243             // time to pop, but still not at the right time. in this
00244             // case case we don't return 0, but fall through to pop
00245             // the timer
00246             if (diff_ms != 0) {
00247                 log_debug("new timeout %d", diff_ms);
00248                 return diff_ms;
00249             } else {
00250                 log_debug("sub-millisecond difference found, falling through");
00251             }
00252         }
00253         pop_timer(now);
00254     }
00255 
00256     return -1;
00257 }
00258 
00259 //----------------------------------------------------------------------
00260 void
00261 TimerThread::run()
00262 {
00263     TimerSystem* sys = TimerSystem::instance();
00264     while (true) 
00265     {
00266         int timeout = sys->run_expired_timers();
00267         sys->notifier()->wait(NULL, timeout);
00268     }
00269 
00270     NOTREACHED;
00271 }
00272 
00273 //----------------------------------------------------------------------
00274 void
00275 TimerThread::init()
00276 {
00277     ASSERT(instance_ == NULL);
00278     instance_ = new TimerThread();
00279     instance_->start();
00280 }
00281 
00282 TimerThread* TimerThread::instance_ = NULL;
00283 
00284 } // namespace oasys

Generated on Fri Dec 22 14:48:01 2006 for DTN Reference Implementation by  doxygen 1.5.1