initial runloop implementation
[chaz/yoink] / src / moof / timer.cc
1
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
4 *
5 * vi:ts=4 sw=4 tw=75
6 *
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
9 *
10 **************************************************************************/
11
12 #include "config.h"
13
14 #include <cerrno>
15 #include <ctime>
16 #include <limits>
17
18 #include <SDL/SDL.h>
19
20 #include "debug.hh"
21 #include "timer.hh"
22
23
24 namespace moof {
25
26
27 void timer::init(const function& function,
28 scalar seconds,
29 mode mode,
30 runloop* runloop)
31 {
32 invalidate();
33 ASSERT(runloop && "can't schedule timer without a runloop");
34
35 if ((mode_ = mode) != invalid)
36 {
37 function_ = function;
38
39 if (mode == absolute)
40 {
41 absolute_ = seconds;
42 }
43 else
44 {
45 absolute_ = seconds - ticks();
46 interval_ = seconds;
47 }
48
49 runloop->add_timer(this);
50 runloop_ = runloop;
51 }
52 }
53
54
55 void timer::invalidate()
56 {
57 if (mode_ != invalid)
58 {
59 mode_ = invalid;
60 absolute_ = SCALAR(0.0);
61
62 runloop_->remove_timer(this);
63 runloop_ = 0;
64 }
65 }
66
67
68 void timer::fire(scalar t)
69 {
70 if (function_) function_(*this, t);
71
72 if (is_repeating())
73 {
74 if (is_equal(absolute_, t, 1.0)) absolute_ += interval_;
75 else absolute_ = interval_ + t;
76 }
77 else invalidate();
78 }
79
80
81 #if ENABLE_CLOCK_GETTIME
82
83 // Since the monotonic clock will provide us with the time since the
84 // computer started, the number of seconds since that time could easily
85 // become so large that it cannot be accurately stored in a float (even
86 // with as little two days uptime), therefore we need to start from a more
87 // recent reference (when the program starts). Of course this isn't much
88 // of an issue if scalar is a double-precision number.
89
90 static time_t set_reference()
91 {
92 struct timespec ts;
93
94 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
95 {
96 return 0;
97 }
98
99 return ts.tv_sec;
100 }
101
102 static const time_t reference_ = set_reference();
103
104
105 scalar timer::ticks()
106 {
107 struct timespec ts;
108
109 int result = clock_gettime(CLOCK_MONOTONIC, &ts);
110 ASSERT(result == 0 && "cannot access clock");
111
112 return scalar(ts.tv_sec - reference_) +
113 scalar(ts.tv_nsec) * SCALAR(0.000000001);
114 }
115
116 void timer::sleep(scalar seconds, mode mode)
117 {
118 if (mode == absolute) seconds -= ticks();
119 if (seconds < SCALAR(0.0)) return;
120
121 struct timespec ts;
122 ts.tv_sec = seconds;
123 ts.tv_nsec = (seconds - scalar(ts.tv_sec)) * SCALAR(1000000000.0);
124
125 int ret;
126 do ret = nanosleep(&ts, &ts); while (ret == -1 && errno == EINTR);
127 }
128
129
130 #else // ! ENABLE_CLOCK_GETTIME
131
132
133 // If we don't have posix timers, we'll have to use a different timing
134 // method. SDL only promises centisecond accuracy, but that's better than
135 // a kick in the pants. It could end up being just as good anyway.
136
137 scalar timer::ticks()
138 {
139 return scalar(SDL_GetTicks()) * SCALAR(0.001);
140 }
141
142 void timer::sleep(scalar seconds, mode mode)
143 {
144 if (mode == absolute) seconds -= ticks();
145 if (seconds < SCALAR(0.0)) return;
146 SDL_Delay(seconds * SCALAR(1000.0));
147 }
148
149 #endif // ENABLE_CLOCK_GETTIME
150
151
152 } // namespace moof
153
This page took 0.037642 seconds and 4 git commands to generate.