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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
#include "minibuffer.h"
#include "reactor.h"
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/inotify.h>
#include <unistd.h>
struct reactor {
int epoll_fd;
struct events *events;
int inotify_fd;
uint32_t inotify_poll_id;
};
struct events {
struct epoll_event events[10];
uint32_t nevents;
};
struct reactor *reactor_create(void) {
int epollfd = epoll_create1(0);
if (epollfd == -1) {
return NULL;
}
int inotifyfd = inotify_init1(IN_NONBLOCK);
if (inotifyfd == -1) {
return NULL;
}
struct reactor *r = (struct reactor *)calloc(1, sizeof(struct reactor));
r->epoll_fd = epollfd;
r->events = calloc(1, sizeof(struct events));
r->inotify_fd = inotifyfd;
r->inotify_poll_id = reactor_register_interest(r, inotifyfd, ReadInterest);
return r;
}
void reactor_destroy(struct reactor *reactor) {
free(reactor->events);
free(reactor);
}
uint32_t reactor_register_interest(struct reactor *reactor, int fd,
enum interest interest) {
struct epoll_event ev;
ev.events = 0;
ev.events |= (interest & ReadInterest) != 0 ? EPOLLIN : 0;
ev.events |= (interest & WriteInterest) != 0 ? EPOLLOUT : 0;
ev.data.fd = fd;
if (epoll_ctl(reactor->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
return -1;
}
return fd;
}
void reactor_unregister_interest(struct reactor *reactor, uint32_t ev_id) {
epoll_ctl(reactor->epoll_fd, EPOLL_CTL_DEL, ev_id, NULL);
}
bool reactor_poll_event(struct reactor *reactor, uint32_t ev_id) {
struct events *events = (struct events *)reactor->events;
for (uint32_t ei = 0; ei < events->nevents; ++ei) {
struct epoll_event *ev = &events->events[ei];
if ((uint32_t)ev->data.fd == ev_id) {
return true;
}
}
return false;
}
uint32_t reactor_watch_file(struct reactor *reactor, const char *path,
uint32_t mask) {
// TODO: change if we get more event types
mask = IN_CLOSE_WRITE;
return (uint32_t)inotify_add_watch(reactor->inotify_fd, path, mask);
}
void reactor_unwatch_file(struct reactor *reactor, uint32_t id) {
inotify_rm_watch(reactor->inotify_fd, id);
}
bool reactor_next_file_event(struct reactor *reactor, struct file_event *out) {
if (reactor_poll_event(reactor, reactor->inotify_poll_id)) {
ssize_t sz = sizeof(struct inotify_event) + NAME_MAX + 1;
uint8_t buf[sz];
ssize_t bytes_read = read(reactor->inotify_fd, buf, sz);
if (bytes_read < 0) {
return false;
}
struct inotify_event *ev = (struct inotify_event *)buf;
// TODO: change when adding more of these
out->mask = FileWritten;
if ((ev->mask & IN_IGNORED) != 0) {
out->mask |= LastEvent;
}
out->id = (uint32_t)ev->wd;
return true;
}
return false;
}
void reactor_update(struct reactor *reactor) {
struct events *events = reactor->events;
int nfds = epoll_wait(reactor->epoll_fd, events->events, 10, -1);
if (nfds == -1) {
events->nevents = 0;
message("failed update epoll reactor: %s", strerror(errno));
}
events->nevents = nfds;
}
|