Root/src/clock.cpp

Source at commit 73ceffa51d3450d2d20ce933e7fc6da187e09fc8 created 7 years 5 months ago.
By Maarten ter Huurne, Fix bug in section directory creation method
1#include "clock.h"
2
3#include "debug.h"
4#include "inputmanager.h"
5#include "utilities.h"
6
7#include <SDL.h>
8#include <atomic>
9#include <sys/time.h>
10
11
12class Clock::Timer {
13public:
14    Timer();
15    ~Timer();
16    void start();
17    void getTime(unsigned int &hours, unsigned int &minutes);
18    unsigned int callback();
19
20private:
21    unsigned int update();
22
23    SDL_TimerID timerID;
24    struct Timestamp { unsigned char hours, minutes; };
25    std::atomic<Timestamp> timestamp;
26};
27
28static std::weak_ptr<Clock::Timer> globalTimer;
29
30/**
31 * Gets the global timer instance, or create it if it doesn't exist already.
32 * This function is not thread safe: only one thread at a time may call it.
33 */
34static std::shared_ptr<Clock::Timer> globalTimerInstance()
35{
36    std::shared_ptr<Clock::Timer> timer = globalTimer.lock();
37    if (timer) {
38        return timer;
39    } else {
40        // Note: Separate start method is necessary because globalTimer must
41        // be written before callbacks can occur.
42        timer.reset(new Clock::Timer());
43        globalTimer = timer;
44        timer->start();
45        return timer;
46    }
47}
48
49extern "C" Uint32 callbackFunc(Uint32 /*timeout*/, void */*d*/)
50{
51    std::shared_ptr<Clock::Timer> timer = globalTimer.lock();
52    return timer ? timer->callback() : 0;
53}
54
55Clock::Timer::Timer()
56    : timerID(NULL)
57{
58    tzset();
59}
60
61Clock::Timer::~Timer()
62{
63    if (timerID) {
64        SDL_RemoveTimer(timerID);
65    }
66}
67
68void Clock::Timer::start()
69{
70    if (timerID) {
71        ERROR("SDL timer was already started\n");
72        return;
73    }
74    unsigned int ms = update();
75    timerID = SDL_AddTimer(ms, callbackFunc, this);
76    if (!timerID) {
77        ERROR("Could not initialize SDL timer: %s\n", SDL_GetError());
78    }
79}
80
81void Clock::Timer::getTime(unsigned int &hours, unsigned int &minutes)
82{
83    struct Timestamp ts = timestamp.load();
84    hours = ts.hours;
85    minutes = ts.minutes;
86}
87
88unsigned int Clock::Timer::update()
89{
90    struct timeval tv;
91    struct tm result;
92    gettimeofday(&tv, NULL);
93    localtime_r(&tv.tv_sec, &result);
94    timestamp.store({
95        static_cast<unsigned char>(result.tm_hour),
96        static_cast<unsigned char>(result.tm_min)
97        });
98    DEBUG("Time updated: %02i:%02i:%02i\n",
99            result.tm_hour, result.tm_min, result.tm_sec);
100
101    // Compute number of milliseconds to next minute boundary.
102    // We don't need high precision, but it is important that any deviation is
103    // past the minute mark, so the fetched hour and minute number belong to
104    // the freshly started minute.
105    // TODO: Does the SDL timer in fact guarantee we're never called early?
106    // "ms = t->interval - SDL_TIMESLICE;" worries me.
107    // Clamping it at 1 sec both avoids overloading the system in case our
108    // computation goes haywire and avoids passing 0 to SDL, which would stop
109    // the recurring timer.
110    return std::max(1, (60 - result.tm_sec)) * 1000;
111}
112
113unsigned int Clock::Timer::callback()
114{
115    unsigned int ms = update();
116    inject_user_event();
117
118    // TODO: SDL timer forgets adjusted interval if a timer was inserted or
119    // removed during the callback. So we should either fix that bug
120    // in SDL or ensure we don't insert/remove timers at runtime.
121    // The blanking timer is inserted/removed quite a lot at time moment,
122    // but it could be reprogrammed to adjust the interval instead.
123    return ms;
124}
125
126std::string Clock::getTime(bool is24)
127{
128    unsigned int hours, minutes;
129    timer->getTime(hours, minutes);
130
131    bool pm = hours >= 12;
132    if (!is24 && pm)
133        hours -= 12;
134
135    char buf[9];
136    sprintf(buf, "%02i:%02i%s", hours, minutes, is24 ? "" : (pm ? "pm" : "am"));
137    return std::string(buf);
138}
139
140Clock::Clock()
141    : timer(globalTimerInstance())
142{
143}
144

Archive Download this file



interactive