Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

lazy update of epoll states

git-svn-id: http://svn.coderepos.org/share/lang/c/picoev/trunk@35013 d0d07461-0603-4401-acd4-de1884942a52
  • Loading branch information...
commit 9c812924cd608cdb62c43653a6b9c542d48e4124 1 parent de4558f
kazuho authored
Showing with 65 additions and 24 deletions.
  1. +1 −1  example/picoev_echo.c
  2. +4 −3 picoev.h
  3. +60 −20 picoev_epoll.c
View
2  example/picoev_echo.c
@@ -116,7 +116,7 @@ int main(void)
picoev_add(loop, listen_sock, PICOEV_READ, 0, accept_callback, NULL);
/* loop */
while (1) {
- picoev_loop_once(loop, 0);
+ picoev_loop_once(loop, 10);
}
/* cleanup */
picoev_destroy_loop(loop);
View
7 picoev.h
@@ -82,7 +82,7 @@ extern "C" {
picoev_loop_id_t loop_id;
char events;
unsigned char timeout_idx; /* PICOEV_TIMEOUT_IDX_UNUSED if not used */
- int _backend; /* can be used by the backend (inited to zero) */
+ int _backend; /* can be used by the backend (inited to -1) */
} picoev_fd;
struct picoev_loop_st {
@@ -214,8 +214,9 @@ extern "C" {
target->loop_id = loop->loop_id;
target->events = 0;
target->timeout_idx = PICOEV_TIMEOUT_IDX_UNUSED;
- target->_backend = 0;
- if (events != 0 && picoev_update_events_internal(loop, fd, events) != 0) {
+ target->_backend = -1;
+ if (events != 0
+ && picoev_update_events_internal(loop, fd, events) != 0) {
target->loop_id = 0;
return -1;
}
View
80 picoev_epoll.c
@@ -34,40 +34,66 @@
typedef struct picoev_loop_epoll_st {
picoev_loop loop;
int epfd;
+ int changed_fds; /* -1 if none */
struct epoll_event events[1024];
} picoev_loop_epoll;
+#define BACKEND_GET_NEXT_FD(backend) ((backend) >> 24)
+#define BACKEND_GET_OLD_EVENTS(backend) ((char)backend)
+#define BACKEND_BUILD(nextfd, oldevents) (((nextfd) << 8) | (oldevents))
+
+#define CALL_EPOLL(epfd, m, fd, e) { \
+ int _epoll_ret = epoll_ctl(epfd, m, fd, e); \
+ assert(m == EPOLL_CTL_DEL || _epoll_ret == 0); \
+ }
+
picoev_globals picoev;
+__inline void picoev_call_epoll(picoev_loop_epoll* loop, int fd,
+ picoev_fd* target)
+{
+ if (loop->loop.loop_id != target->loop_id) {
+ /* now used by another thread, disable */
+ CALL_EPOLL(loop->epfd, EPOLL_CTL_DEL, fd, 0);
+ } else {
+ int old_events = BACKEND_GET_OLD_EVENTS(target->_backend);
+ if (old_events != target->events) {
+ /* apply changes */
+ if (target->events == 0) {
+ CALL_EPOLL(loop->epfd, EPOLL_CTL_DEL, fd, 0);
+ } else {
+ struct epoll_event ev;
+ ev.events = ((target->events & PICOEV_READ) != 0 ? EPOLLIN : 0)
+ | ((target->events & PICOEV_WRITE) != 0 ? EPOLLOUT : 0);
+ ev.data.fd = fd;
+ if (old_events != 0) {
+ CALL_EPOLL(loop->epfd, EPOLL_CTL_MOD, fd, &ev);
+ } else {
+ CALL_EPOLL(loop->epfd, EPOLL_CTL_ADD, fd, &ev);
+ }
+ }
+ }
+ }
+}
+
int picoev_update_events_internal(picoev_loop* _loop, int fd, int events)
{
picoev_loop_epoll* loop = (picoev_loop_epoll*)_loop;
- int old_events = picoev.fds[fd].events;
+ picoev_fd* target = picoev.fds + fd;
assert(PICOEV_FD_BELONGS_TO_LOOP(&loop->loop, fd));
-#define CTL(m, e) \
- if (epoll_ctl(loop->epfd, m, fd, e) != 0) { \
- return -1; \
+ if (target->events == events) {
+ return 0;
}
- if (events == 0) {
- CTL(EPOLL_CTL_DEL, 0);
- } else {
- struct epoll_event ev;
- ev.events = ((events & PICOEV_READ) != 0 ? EPOLLIN : 0)
- | ((events & PICOEV_WRITE) != 0 ? EPOLLOUT : 0);
- ev.data.fd = fd;
- if (old_events != 0) {
- CTL(EPOLL_CTL_MOD, &ev);
- } else {
- CTL(EPOLL_CTL_ADD, &ev);
- }
+ /* update chain */
+ if (target->_backend == -1) {
+ target->_backend = BACKEND_BUILD(loop->changed_fds, target->events);
+ loop->changed_fds = fd;
}
+ target->events = events;
-#undef CTL
-
- picoev.fds[fd].events = events;
return 0;
}
@@ -85,12 +111,13 @@ picoev_loop* picoev_create_loop(int max_timeout)
return NULL;
}
- /* init epoll */
+ /* init myself */
if ((loop->epfd = epoll_create(picoev.max_fd)) == -1) {
picoev_deinit_loop_internal(&loop->loop);
free(loop);
return NULL;
}
+ loop->changed_fds = -1;
return &loop->loop;
}
@@ -112,6 +139,17 @@ int picoev_poll_once_internal(picoev_loop* _loop, int max_wait)
picoev_loop_epoll* loop = (picoev_loop_epoll*)_loop;
int i, nevents;
+ if (loop->changed_fds != -1) {
+ int fd = loop->changed_fds;
+ do {
+ picoev_fd* target = picoev.fds + fd;
+ picoev_call_epoll(loop, fd, target);
+ fd = BACKEND_GET_NEXT_FD(target->_backend);
+ target->_backend = -1;
+ } while (fd != -1);
+ loop->changed_fds = -1;
+ }
+
nevents = epoll_wait(loop->epfd, loop->events,
sizeof(loop->events) / sizeof(loop->events[0]),
max_wait * 1000);
@@ -127,6 +165,8 @@ int picoev_poll_once_internal(picoev_loop* _loop, int max_wait)
| ((event->events & EPOLLOUT) != 0 ? PICOEV_WRITE : 0);
(*target->callback)(&loop->loop, event->data.fd, revents,
target->cb_arg);
+ } else {
+ CALL_EPOLL(loop->epfd, EPOLL_CTL_DEL, event->data.fd, 0);
}
}
return 0;
Please sign in to comment.
Something went wrong with that request. Please try again.