forked from rbeeli/websocketclient-cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkqueue.cpp
104 lines (93 loc) · 2.97 KB
/
kqueue.cpp
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
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <system_error>
#include "kqueue.hpp"
namespace NNet {
TKqueue::TKqueue()
: Fd_(kqueue())
{
if (Fd_ < 0) {
throw std::system_error(errno, std::generic_category(), "kqueue");
}
}
TKqueue::~TKqueue()
{
if (Fd_ >= 0) { close(Fd_); }
}
void TKqueue::Poll()
{
auto ts = GetTimeout();
ChangeList_.clear();
if (InEvents_.size() <= MaxFd_) {
InEvents_.resize(MaxFd_+1);
}
for (auto& ch : Changes_) {
int fd = ch.Fd;
struct kevent kev = {};
bool changed = false;
auto& ev = InEvents_[fd];
if (ch.Handle) {
if (ch.Type & TEvent::READ && ev.Read != ch.Handle) {
EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, nullptr);
ChangeList_.emplace_back(kev);
ev.Read = ch.Handle;
}
if (ch.Type & TEvent::WRITE && ev.Write != ch.Handle) {
EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, nullptr);
ChangeList_.emplace_back(kev);
ev.Write = ch.Handle;
}
} else {
if (ch.Type & TEvent::READ && ev.Read) {
EV_SET(&kev, fd, EVFILT_READ, EV_DELETE | EV_CLEAR, 0, 0, nullptr);
ChangeList_.emplace_back(kev);
ev.Read = {};
}
if (ch.Type & TEvent::WRITE && ev.Write) {
EV_SET(&kev, fd, EVFILT_WRITE, EV_DELETE | EV_CLEAR, 0, 0, nullptr);
ChangeList_.emplace_back(kev);
ev.Write = {};
}
}
}
Reset();
OutEvents_.resize(std::max<size_t>(1, 2*InEvents_.size()));
int nfds;
if ((nfds = kevent(
Fd_,
&ChangeList_[0], ChangeList_.size(),
&OutEvents_[0], OutEvents_.size(),
&ts)) < 0)
{
throw std::system_error(errno, std::generic_category(), "kevent");
}
for (int i = 0; i < nfds; i++) {
int fd = OutEvents_[i].ident;
int filter = OutEvents_[i].filter;
int flags = OutEvents_[i].flags;
if (flags & EV_DELETE) {
// closed socket?
continue;
}
// TODO: check flags & EV_ERROR && errno = OutEvents_[i].data
THandlePair ev = InEvents_[fd];
if (filter == EVFILT_READ && ev.Read) {
ReadyEvents_.emplace_back(TEvent{fd, TEvent::READ, ev.Read});
ev.Read = {};
}
if (filter == EVFILT_WRITE && ev.Write) {
ReadyEvents_.emplace_back(TEvent{fd, TEvent::WRITE, ev.Write});
ev.Write = {};
}
if (flags & EV_EOF) {
if (ev.Read) {
ReadyEvents_.emplace_back(TEvent{fd, TEvent::READ, ev.Read});
}
if (ev.Write) {
ReadyEvents_.emplace_back(TEvent{fd, TEvent::WRITE, ev.Write});
}
}
}
ProcessTimers();
}
} // namespace NNet
#endif // #if defined(__APPLE__) || defined(__FreeBSD__)