wvdailyevent.cc

00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2004 Net Integration Technologies, Inc.
00004  *
00005  * A simple class that can trigger an event on a timed basis.
00006  *   a) if given an hour, triggers once per day, on that hour.
00007  *   b) if given a number of times per day, triggers that many times per
00008  *      day, evenly, starting at the hour given in (a).  (Needed to get a
00009  *      Microbackup going every 15 minutes.)  
00010  *
00011  * Presently has a one-hour granularity in the first case, but that can be
00012  * extended one day when someone cares.
00013  *
00014  */
00015 #include "wvdailyevent.h"
00016 #include "wvstream.h"
00017 #include "wvtimeutils.h"
00018 
00019 #include <time.h>
00020 
00021 #ifndef _WIN32
00022 #include <sys/time.h>
00023 #include <unistd.h>
00024 #endif
00025 
00026 #define NUM_MINS_IN_DAY (24*60)
00027 #define NUM_SECS_IN_DAY (60*NUM_MINS_IN_DAY)
00028 
00029 WvDailyEvent::WvDailyEvent(int _first_hour, int _num_per_day, bool _skip_first)
00030     : prev(time(NULL))
00031 {
00032     need_reset = false;
00033     prev = wvstime().tv_sec;
00034     configure(_first_hour, _num_per_day, _skip_first);
00035 }
00036 
00037 
00038 // Compute the next time this stream should select()
00039 bool WvDailyEvent::pre_select(SelectInfo &si)
00040 {
00041     if (num_per_day)
00042     {
00043         time_t now = wvstime().tv_sec;
00044         time_t next = next_event();
00045 
00046         assert(prev);
00047         assert(next);
00048         assert(prev > 100000);
00049         assert(next > 100000);
00050 
00051         //printf("%d %d %d\n", now, next, msecdiff(now, next));
00052         if (now < next)
00053             si.msec_timeout = msecdiff(now, next);
00054         else if (!need_reset)
00055         {
00056             need_reset = true;
00057             prev = next;
00058         }
00059     }
00060     bool ret = WvStream::pre_select(si) || need_reset;
00061     //printf("%p ret=%d msd=%d\n", this, ret, si.msec_timeout);
00062     return ret;
00063 }
00064 
00065 
00066 // Test to see if the timer has gone off
00067 bool WvDailyEvent::post_select(SelectInfo& si)
00068 {
00069     bool timer_rang = false;
00070     WvTime next(next_event(), 0);
00071     if (next < wvtime())
00072     {
00073         timer_rang = true;
00074         prev = next;
00075     }
00076 
00077     return WvStream::post_select(si) || timer_rang;
00078 }
00079 
00080 
00081 void WvDailyEvent::set_num_per_day(int _num_per_day) 
00082 {
00083     num_per_day = _num_per_day;
00084     if (num_per_day < 0)
00085         num_per_day = 1;
00086 
00087     if (num_per_day > NUM_SECS_IN_DAY)
00088         num_per_day = NUM_SECS_IN_DAY;
00089         
00090     time_t max = num_per_day ? NUM_SECS_IN_DAY/num_per_day : 6*60*60;
00091     if (max > 6*60*60)
00092         max = 6*60*60; // unless that's a very long time, 6 hrs
00093 
00094     // don't start until at least one period has gone by
00095     prev = wvstime().tv_sec;
00096     not_until = prev + max;
00097 }
00098 
00099 
00100 void WvDailyEvent::configure(int _first_hour, int _num_per_day, bool _skip_first)
00101 {
00102     first_hour = _first_hour;
00103     skip_first = _skip_first;
00104 
00105     // Don't let WvDailyEvents occur more than once a minute. -- use an alarm
00106     // instead
00107     if (_num_per_day > NUM_MINS_IN_DAY)
00108         _num_per_day = NUM_MINS_IN_DAY;
00109 
00110     set_num_per_day(_num_per_day);
00111 }
00112 
00113 // the daily event occurs each day at first_hour on the hour, or at
00114 // some multiple of the interval *after* that hour.
00115 time_t WvDailyEvent::next_event() const
00116 {
00117     if (!num_per_day) // disabled
00118         return 0;
00119 
00120     assert(prev);
00121     
00122     time_t interval = NUM_SECS_IN_DAY/num_per_day;
00123     time_t start = prev + interval;
00124    
00125     // find the time to start counting from (up to 24 hours in the past)
00126     struct tm *tm = localtime(&start);
00127     if (tm->tm_hour < first_hour)
00128     {
00129         start = prev - NUM_SECS_IN_DAY + 1; // this time yesterday
00130         tm = localtime(&start);
00131     }
00132     tm->tm_hour = first_hour; // always start at the given hour
00133     tm->tm_min = tm->tm_sec = 0; // right on the hour
00134     start = mktime(tm); // convert back into a time_t
00135 
00136     // find the next event after prev that's a multiple of 'interval'
00137     // since 'start'
00138     time_t next = prev + interval;
00139     if ((next - start)%interval != 0)
00140         next = start + (next - start)/interval * interval;
00141     
00142     assert(next);
00143     assert(next > 100000);
00144 
00145     while (skip_first && next < not_until)
00146         next += interval;
00147 
00148     return next;
00149 }

Generated on Fri Oct 5 18:20:27 2007 for WvStreams by  doxygen 1.5.3