summaryrefslogtreecommitdiff
path: root/src/dged/reactor-epoll.c
blob: beee7ec1a56d0dcdb6a32b5864d6c746f9c65edc (plain)
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;
}