-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathplatform_timer_macos.cpp
More file actions
executable file
·110 lines (87 loc) · 3.26 KB
/
platform_timer_macos.cpp
File metadata and controls
executable file
·110 lines (87 loc) · 3.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <eosio/chain/platform_timer.hpp>
#include <eosio/chain/platform_timer_accuracy.hpp>
#include <fc/time.hpp>
#include <fc/fwd_impl.hpp>
#include <fc/exception/exception.hpp>
#include <fc/log/logger_config.hpp> //set_os_thread_name()
#include <mutex>
#include <thread>
#include <sys/event.h>
namespace eosio { namespace chain {
//a kqueue & thread is shared for all platform_timer_macos instances
static std::mutex timer_ref_mutex;
static unsigned next_timerid;
static unsigned refcount;
static int kqueue_fd;
static std::thread kevent_thread;
struct platform_timer::impl {
uint64_t timerid;
constexpr static uint64_t quit_event_id = 1;
};
platform_timer::platform_timer() {
static_assert(sizeof(impl) <= fwd_size);
std::lock_guard guard(timer_ref_mutex);
if(refcount++ == 0) {
kqueue_fd = kqueue();
FC_ASSERT(kqueue_fd != -1, "failed to create kqueue");
//set up a EVFILT_USER which will be signaled to shut down the thread
struct kevent64_s quit_event;
EV_SET64(&quit_event, impl::quit_event_id, EVFILT_USER, EV_ADD|EV_ENABLE, NOTE_FFNOP, 0, 0, 0, 0);
FC_ASSERT(kevent64(kqueue_fd, &quit_event, 1, NULL, 0, KEVENT_FLAG_IMMEDIATE, NULL) == 0, "failed to create quit event");
kevent_thread = std::thread([]() {
fc::set_os_thread_name("checktime");
while(true) {
struct kevent64_s anEvent;
int c = kevent64(kqueue_fd, NULL, 0, &anEvent, 1, 0, NULL);
if(c == 1 && anEvent.filter == EVFILT_TIMER) {
platform_timer* self = (platform_timer*)anEvent.udata;
self->expired = 1;
self->call_expiration_callback();
}
else if(c == 1 && anEvent.filter == EVFILT_USER)
return;
else if(c == -1 && errno == EINTR)
continue;
else if(c == -1)
return; //?? not much we can do now
}
});
}
my->timerid = next_timerid++;
compute_and_print_timer_accuracy(*this);
}
platform_timer::~platform_timer() {
stop();
if(std::lock_guard guard(timer_ref_mutex); --refcount == 0) {
struct kevent64_s signal_quit_event;
EV_SET64(&signal_quit_event, impl::quit_event_id, EVFILT_USER, 0, NOTE_TRIGGER, 0, 0, 0, 0);
if(kevent64(kqueue_fd, &signal_quit_event, 1, NULL, 0, KEVENT_FLAG_IMMEDIATE, NULL) != -1)
kevent_thread.join();
close(kqueue_fd);
}
}
void platform_timer::start(fc::time_point tp) {
if(tp == fc::time_point::maximum()) {
expired = 0;
return;
}
fc::microseconds x = tp.time_since_epoch() - fc::time_point::now().time_since_epoch();
if(x.count() <= 0)
expired = 1;
else {
struct kevent64_s aTimerEvent;
EV_SET64(&aTimerEvent, my->timerid, EVFILT_TIMER, EV_ADD|EV_ENABLE|EV_ONESHOT, NOTE_USECONDS|NOTE_CRITICAL, x.count(), (uint64_t)this, 0, 0);
expired = 0;
if(kevent64(kqueue_fd, &aTimerEvent, 1, NULL, 0, KEVENT_FLAG_IMMEDIATE, NULL) != 0)
expired = 1;
}
}
void platform_timer::stop() {
if(expired)
return;
struct kevent64_s stop_timer_event;
EV_SET64(&stop_timer_event, my->timerid, EVFILT_TIMER, EV_DELETE, 0, 0, 0, 0, 0);
kevent64(kqueue_fd, &stop_timer_event, 1, NULL, 0, KEVENT_FLAG_IMMEDIATE, NULL);
expired = 1;
}
}}