Statistics
| Branch: | Tag: | Revision:

dvbd / src / timer.cpp @ a24dbbce

History | View | Annotate | Download (2.99 KB)

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
  interval.tv_sec = future.tv_sec - now.tv_sec;
46
  interval.tv_usec = future.tv_usec - now.tv_usec;
47

    
48
  if (interval.tv_usec < 0) {
49
    interval.tv_usec += 1000000;
50
    interval.tv_sec--;
51
  }
52
}
53

    
54
static void fireTimers()
55
{
56
  struct timeval now;
57
  gettimeofday(&now, 0);
58

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

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

    
78
  calcInterval(expiry, interval);
79

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

    
98
static void handleAlarmSig(int sig)
99
{
100
  std::cout << "Got alarm signal\n";
101
  // Alarm signal is masked already
102
  fireTimers();
103
  if (!timerQueue.empty())
104
    setTimer();
105
}
106

    
107
static struct SetupSignalHandler {
108
  SetupSignalHandler()
109
  {
110
    std::cout << "Setting up signal handler\n";
111
    struct sigaction act;
112
    act.sa_handler = handleAlarmSig;
113
    sigemptyset(&act.sa_mask);
114
    sigaddset(&act.sa_mask, SIGALRM);
115
    act.sa_flags = 0;
116
    sigaction(SIGALRM, &act, 0);
117
  }
118
} setupSignalHandler;
119

    
120

    
121
void Timer::start()
122
{
123
  // Calculate expiry time
124
  gettimeofday(&expiry, 0);
125
  expiry.tv_usec += delayMs * 1000;
126
  expiry.tv_sec += expiry.tv_usec % 1000000;
127
  expiry.tv_usec %= 1000000;
128
  
129
  // Add the timer to the queue
130
  maskTimer();
131
  timerQueue.push(this);
132
  setTimer();
133
  unmaskTimer();
134
}
135

    
136
void Timer::fire()
137
{
138
  callback(arg);
139
}
140

    
141
void Timer::stop()
142
{
143
  maskTimer();
144
  TimerQueue copy = timerQueue;
145

    
146
  while (!timerQueue.empty())
147
    timerQueue.pop();
148

    
149
  while (!copy.empty()) {
150
    Timer *top = copy.top();
151
    copy.pop();
152
    if (top != this)
153
      timerQueue.push(top);
154
  }
155
  unmaskTimer();
156
}