WvStreams
|
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 void WvDailyEvent::pre_select(SelectInfo &si) 00040 { 00041 WvStream::pre_select(si); 00042 00043 if (num_per_day) 00044 { 00045 time_t now = wvstime().tv_sec; 00046 time_t next = next_event(); 00047 00048 assert(prev); 00049 assert(next); 00050 assert(prev > 100000); 00051 assert(next > 100000); 00052 00053 //printf("%d %d %d\n", now, next, msecdiff(now, next)); 00054 if (now < next) 00055 si.msec_timeout = msecdiff(now, next); 00056 else if (!need_reset) 00057 { 00058 need_reset = true; 00059 prev = next; 00060 } 00061 } 00062 if (need_reset) 00063 si.msec_timeout = 0; 00064 //printf("%p msd=%d\n", this, ret, si.msec_timeout); 00065 } 00066 00067 00068 // Test to see if the timer has gone off 00069 bool WvDailyEvent::post_select(SelectInfo& si) 00070 { 00071 bool timer_rang = false; 00072 WvTime next(next_event(), 0); 00073 if (next < wvtime()) 00074 { 00075 timer_rang = true; 00076 prev = next; 00077 } 00078 00079 return WvStream::post_select(si) || need_reset || timer_rang; 00080 } 00081 00082 00083 void WvDailyEvent::set_num_per_day(int _num_per_day) 00084 { 00085 num_per_day = _num_per_day; 00086 if (num_per_day < 0) 00087 num_per_day = 1; 00088 00089 if (num_per_day > NUM_SECS_IN_DAY) 00090 num_per_day = NUM_SECS_IN_DAY; 00091 00092 time_t max = num_per_day ? NUM_SECS_IN_DAY/num_per_day : 6*60*60; 00093 if (max > 6*60*60) 00094 max = 6*60*60; // unless that's a very long time, 6 hrs 00095 00096 // don't start until at least one period has gone by 00097 prev = wvstime().tv_sec; 00098 not_until = prev + max; 00099 } 00100 00101 00102 void WvDailyEvent::configure(int _first_hour, int _num_per_day, bool _skip_first) 00103 { 00104 first_hour = _first_hour; 00105 skip_first = _skip_first; 00106 00107 // Don't let WvDailyEvents occur more than once a minute. -- use an alarm 00108 // instead 00109 if (_num_per_day > NUM_MINS_IN_DAY) 00110 _num_per_day = NUM_MINS_IN_DAY; 00111 00112 set_num_per_day(_num_per_day); 00113 } 00114 00115 // the daily event occurs each day at first_hour on the hour, or at 00116 // some multiple of the interval *after* that hour. 00117 time_t WvDailyEvent::next_event() const 00118 { 00119 if (!num_per_day) // disabled 00120 return 0; 00121 00122 assert(prev); 00123 00124 time_t interval = NUM_SECS_IN_DAY/num_per_day; 00125 time_t start = prev + interval; 00126 00127 // find the time to start counting from (up to 24 hours in the past) 00128 struct tm *tm = localtime(&start); 00129 if (tm->tm_hour < first_hour) 00130 { 00131 start = prev - NUM_SECS_IN_DAY + 1; // this time yesterday 00132 tm = localtime(&start); 00133 } 00134 tm->tm_hour = first_hour; // always start at the given hour 00135 tm->tm_min = tm->tm_sec = 0; // right on the hour 00136 start = mktime(tm); // convert back into a time_t 00137 00138 // find the next event after prev that's a multiple of 'interval' 00139 // since 'start' 00140 time_t next = prev + interval; 00141 if ((next - start)%interval != 0) 00142 next = start + (next - start)/interval * interval; 00143 00144 assert(next); 00145 assert(next > 100000); 00146 00147 while (skip_first && next < not_until) 00148 next += interval; 00149 00150 return next; 00151 }