WvStreams
wvdailyevent.cc
1 /*
2  * Worldvisions Weaver Software:
3  * Copyright (C) 1997-2004 Net Integration Technologies, Inc.
4  *
5  * A simple class that can trigger an event on a timed basis.
6  * a) if given an hour, triggers once per day, on that hour.
7  * b) if given a number of times per day, triggers that many times per
8  * day, evenly, starting at the hour given in (a). (Needed to get a
9  * Microbackup going every 15 minutes.)
10  *
11  * Presently has a one-hour granularity in the first case, but that can be
12  * extended one day when someone cares.
13  *
14  */
15 #include "wvdailyevent.h"
16 #include "wvstream.h"
17 #include "wvtimeutils.h"
18 
19 #include <time.h>
20 
21 #ifndef _WIN32
22 #include <sys/time.h>
23 #include <unistd.h>
24 #endif
25 
26 #define NUM_MINS_IN_DAY (24*60)
27 #define NUM_SECS_IN_DAY (60*NUM_MINS_IN_DAY)
28 
29 WvDailyEvent::WvDailyEvent(int _first_hour, int _num_per_day, bool _skip_first)
30  : prev(time(NULL))
31 {
32  need_reset = false;
33  prev = wvstime().tv_sec;
34  configure(_first_hour, _num_per_day, _skip_first);
35 }
36 
37 
38 // Compute the next time this stream should select()
40 {
42 
43  if (num_per_day)
44  {
45  time_t now = wvstime().tv_sec;
46  time_t next = next_event();
47 
48  assert(prev);
49  assert(next);
50  assert(prev > 100000);
51  assert(next > 100000);
52 
53  //printf("%d %d %d\n", now, next, msecdiff(now, next));
54  if (now < next)
55  si.msec_timeout = msecdiff(now, next);
56  else if (!need_reset)
57  {
58  need_reset = true;
59  prev = next;
60  }
61  }
62  if (need_reset)
63  si.msec_timeout = 0;
64  //printf("%p msd=%d\n", this, ret, si.msec_timeout);
65 }
66 
67 
68 // Test to see if the timer has gone off
70 {
71  bool timer_rang = false;
72  WvTime next(next_event(), 0);
73  if (next < wvtime())
74  {
75  timer_rang = true;
76  prev = next;
77  }
78 
79  return WvStream::post_select(si) || need_reset || timer_rang;
80 }
81 
82 
83 void WvDailyEvent::set_num_per_day(int _num_per_day)
84 {
85  num_per_day = _num_per_day;
86  if (num_per_day < 0)
87  num_per_day = 1;
88 
89  if (num_per_day > NUM_SECS_IN_DAY)
90  num_per_day = NUM_SECS_IN_DAY;
91 
92  time_t max = num_per_day ? NUM_SECS_IN_DAY/num_per_day : 6*60*60;
93  if (max > 6*60*60)
94  max = 6*60*60; // unless that's a very long time, 6 hrs
95 
96  // don't start until at least one period has gone by
97  prev = wvstime().tv_sec;
98  not_until = prev + max;
99 }
100 
101 
102 void WvDailyEvent::configure(int _first_hour, int _num_per_day, bool _skip_first)
103 {
104  first_hour = _first_hour;
105  skip_first = _skip_first;
106 
107  // Don't let WvDailyEvents occur more than once a minute. -- use an alarm
108  // instead
109  if (_num_per_day > NUM_MINS_IN_DAY)
110  _num_per_day = NUM_MINS_IN_DAY;
111 
112  set_num_per_day(_num_per_day);
113 }
114 
115 // the daily event occurs each day at first_hour on the hour, or at
116 // some multiple of the interval *after* that hour.
118 {
119  if (!num_per_day) // disabled
120  return 0;
121 
122  assert(prev);
123 
124  time_t interval = NUM_SECS_IN_DAY/num_per_day;
125  time_t start = prev + interval;
126 
127  // find the time to start counting from (up to 24 hours in the past)
128  struct tm *tm = localtime(&start);
129  if (tm->tm_hour < first_hour)
130  {
131  start = prev - NUM_SECS_IN_DAY + 1; // this time yesterday
132  tm = localtime(&start);
133  }
134  tm->tm_hour = first_hour; // always start at the given hour
135  tm->tm_min = tm->tm_sec = 0; // right on the hour
136  start = mktime(tm); // convert back into a time_t
137 
138  // find the next event after prev that's a multiple of 'interval'
139  // since 'start'
140  time_t next = prev + interval;
141  if ((next - start)%interval != 0)
142  next = start + (next - start)/interval * interval;
143 
144  assert(next);
145  assert(next > 100000);
146 
147  while (skip_first && next < not_until)
148  next += interval;
149 
150  return next;
151 }
WvDailyEvent::set_num_per_day
void set_num_per_day(int _num_per_day)
Set number of times per day the event should occur - ONLY FOR TESTING!
Definition: wvdailyevent.cc:83
WvDailyEvent::configure
void configure(int _first_hour, int _num_per_day=0, bool _skip_first=true)
Modifies the first hour in which the event should occur and the number of times the event should occu...
Definition: wvdailyevent.cc:102
WvTime
Based on (and interchangeable with) struct timeval.
Definition: wvtimeutils.h:17
WvDailyEvent::post_select
virtual bool post_select(SelectInfo &si)
post_select() is called after ::select(), and returns true if this object is now ready.
Definition: wvdailyevent.cc:69
WvDailyEvent::WvDailyEvent
WvDailyEvent(int _first_hour, int _num_per_day=0, bool _skip_first=true)
Constructs WvDailyEvent.
Definition: wvdailyevent.cc:29
IWvStream::SelectInfo
the data structure used by pre_select()/post_select() and internally by select().
Definition: iwvstream.h:50
WvStream::post_select
virtual bool post_select(SelectInfo &si)
post_select() is called after ::select(), and returns true if this object is now ready.
Definition: wvstream.cc:875
WvDailyEvent::pre_select
virtual void pre_select(SelectInfo &si)
Munges SelectInfo such that the stream will select when the time is right for the event to occur.
Definition: wvdailyevent.cc:39
WvDailyEvent::next_event
time_t next_event() const
return the time when the next event will occur
Definition: wvdailyevent.cc:117
WvStream::pre_select
virtual void pre_select(SelectInfo &si)
pre_select() sets up for eventually calling ::select().
Definition: wvstream.cc:844