Revision 75bddfec

View differences:

src/timer.cpp
1
#include "timer.h"
2

  
3
#include <signal.h>
4

  
5
#include <iostream>
6
#include <queue>
7
#include <functional>
8

  
9
struct TimerLess {
10
  bool operator()(Timer *& left, Timer *& right) const
11
  {
12
    // a Timer has less priority if it's expiry time is bigger
13
    struct timeval a = left->getExpiry();
14
    struct timeval b = right->getExpiry();
15
    return timercmp(&a, &b, >); 
16
  }
17
};
18

  
19
typedef std::priority_queue<Timer *, std::vector<Timer *>, struct TimerLess> TimerQueue; 
20

  
21
static TimerQueue timerQueue;
22
static struct timeval earliestTime;
23

  
24
static void maskTimer()
25
{
26
  sigset_t set;
27
  sigemptyset(&set);
28
  sigaddset(&set, SIGALRM);
29
  sigprocmask(SIG_BLOCK, &set, NULL);
30
}
31

  
32
static void unmaskTimer()
33
{
34
  sigset_t set;
35
  sigemptyset(&set);
36
  sigaddset(&set, SIGALRM);
37
  sigprocmask(SIG_UNBLOCK, &set, NULL);
38
}
39

  
40
void calcInterval(const struct timeval &future, struct timeval &interval)
41
{
42
  struct timeval now;
43
  gettimeofday(&now, 0);
44

  
45
  std::cout << "Calculating time difference between " << future.tv_sec << ", " 
46
	    << future.tv_usec << " and now " << now.tv_sec << ", " << now.tv_usec << std::endl;
47

  
48
  interval.tv_sec = future.tv_sec - now.tv_sec;
49
  interval.tv_usec = future.tv_usec - now.tv_usec;
50

  
51
  if (interval.tv_usec < 0) {
52
    interval.tv_usec += 1000000;
53
    interval.tv_sec--;
54
  }
55
}
56

  
57
static void fireTimers()
58
{
59
  struct timeval now;
60
  gettimeofday(&now, 0);
61

  
62
  while (!timerQueue.empty()) {
63
    Timer *top = timerQueue.top();
64
    struct timeval expiry = top->getExpiry();
65
    if (timercmp(&now, &expiry, >=)) {
66
      timerQueue.pop();
67
      top->fire();
68
    }
69
    else
70
      break;
71
  }
72
}
73

  
74
static void setTimer()
75
{
76
  // Must be called with an timer in the timerQueue
77
  Timer *top = timerQueue.top();
78
  struct timeval expiry = top->getExpiry();
79
  struct timeval interval;
80

  
81
  calcInterval(expiry, interval);
82

  
83
  if (interval.tv_sec < 0) {
84
    interval.tv_sec = 0;
85
    fireTimers();
86
    return;
87
  }
88
  
89
  earliestTime = expiry;
90
  
91
  // Single shot timer
92
  struct itimerval it;
93
  it.it_interval.tv_sec = 0;
94
  it.it_interval.tv_usec = 0;
95
  it.it_value = interval;
96
    
97
  std::cout << "Setting up itimer for interval " 
98
	    << it.it_value.tv_sec << ", " << it.it_value.tv_usec << std::endl;
99
  setitimer(ITIMER_REAL, &it, 0);
100
}
101

  
102
static void handleAlarmSig(int sig)
103
{
104
  std::cout << "Got alarm signal" << std::endl;
105
  // Alarm signal is masked already
106
  fireTimers();
107
  if (!timerQueue.empty())
108
    setTimer();
109
}
110

  
111
static struct SetupSignalHandler {
112
  SetupSignalHandler()
113
  {
114
    std::cout << "Setting up signal handler" << std::endl;
115
    struct sigaction act;
116
    act.sa_handler = handleAlarmSig;
117
    sigemptyset(&act.sa_mask);
118
    sigaddset(&act.sa_mask, SIGALRM);
119
    act.sa_flags = 0;
120
    sigaction(SIGALRM, &act, 0);
121
  }
122
} setupSignalHandler;
123

  
124

  
125
void Timer::start()
126
{
127
  stop();
128

  
129
  // Calculate expiry time
130
  gettimeofday(&expiry, 0);
131
  expiry.tv_usec += delayMs * 1000;
132
  expiry.tv_sec += expiry.tv_usec / 1000000;
133
  expiry.tv_usec %= 1000000;
134
  
135
  // Add the timer to the queue
136
  maskTimer();
137
  timerQueue.push(this);
138
  setTimer();
139
  unmaskTimer();
140
}
141

  
142
void Timer::fire()
143
{
144
  callback(arg);
145
}
146

  
147
void Timer::stop()
148
{
149
  if (started) {
150
    started = false;
151
    maskTimer();
152
    TimerQueue copy = timerQueue;
153

  
154
    while (!timerQueue.empty())
155
      timerQueue.pop();
156

  
157
    while (!copy.empty()) {
158
      Timer *top = copy.top();
159
      copy.pop();
160
      if (top != this)
161
	timerQueue.push(top);
162
    }
163
    unmaskTimer();
164
  }
165
}
src/timer.h
1
#if !defined __MY_TIMER_H
2
#define __MY_TIMER_H
3

  
4
#include <sys/time.h>
5
#include <time.h>
6

  
7
class Timer {
8
 public:
9
  typedef void CallbackType( void * );
10
  
11
  Timer( unsigned delayMs, CallbackType *callback, void *arg )
12
    : started(false), delayMs(delayMs), callback(callback), arg(arg)
13
    {
14
    }
15

  
16
  void start();
17
  void stop();
18

  
19
  struct timeval getExpiry() const
20
    {
21
      return expiry;
22
    }
23
  
24
  void fire();
25

  
26
 private:
27

  
28
  bool started;
29
  unsigned delayMs;
30
  CallbackType *callback;
31
  void *arg;
32
  struct timeval expiry;
33
};
34

  
35

  
36
#endif // __MY_TIMER_H

Also available in: Unified diff