From b70142c2915d0b7bcbba1fcb8d24d8d05c9c1fca Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Fri, 11 Jan 2008 22:03:31 +0100 Subject: [PATCH] more job functions Signed-off-by: Pierre Habouzit --- lib-sys/evtloop.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++- lib-sys/evtloop.h | 15 ++++++++-- 2 files changed, 87 insertions(+), 4 deletions(-) diff --git a/lib-sys/evtloop.c b/lib-sys/evtloop.c index 1b5d723..2dbfc9e 100644 --- a/lib-sys/evtloop.c +++ b/lib-sys/evtloop.c @@ -32,6 +32,43 @@ static int epollfd = -1; +static int el_job_setemode(job_t *w, el_mode emode) +{ + static int const evtmode_to_epoll[] = { + [EL_NEW] = EPOLLRDHUP, + [EL_READING] = EPOLLIN, + [EL_WRITING] = EPOLLOUT, + [EL_RDWR] = EPOLLIN | EPOLLOUT, + [EL_IDLE] = EPOLLRDHUP, + }; + + assert (w->mode == emode || emode == EL_WRITING || emode == EL_READING); + + if (emode != w->emode) { + struct epoll_event event = { + .data.ptr = w, + .events = evtmode_to_epoll[emode], + }; + int action = w->emode == EL_NEW ? EPOLL_CTL_ADD : EPOLL_CTL_MOD; + if (epoll_ctl(epollfd, action, w->fd, &event) < 0) { + return el_job_release(w, true); + } + } + w->emode = emode; + return 0; +} + +int el_job_setmode(job_t *w, el_mode mode) +{ + if (w->mode == w->emode) { + w->mode = mode; + return el_job_setemode(w, mode); + } else { + w->mode = mode; + return 0; + } +} + int el_job_release(job_t *w, el_status reason) { w->state = EL_LLP_FINI; @@ -41,10 +78,47 @@ int el_job_release(job_t *w, el_status reason) if (w->fd >= 0) { close(w->fd); } - p_delete(&w); + job_delete(&w); return -1; } +static int el_job_connecting(job_t *w) +{ + int err = 0; + socklen_t len = sizeof(err); + + if (getsockopt(w->fd, SOL_SOCKET, SO_ERROR, (void *)&err, &len) || err) + return el_job_release(w, EL_ERROR); + + w->state = EL_LLP_READY; + return w->m->on_event(w, EL_EVT_RUNNING); +} + +int el_job_connect(job_t *w, struct sockaddr *addr, socklen_t len, + int type, int proto) +{ + int res, sock = socket(addr->sa_family, type, proto); + + if (sock < 0) + goto error; + + res = fcntl(sock, F_GETFL); + if (res < 0) + goto error; + if (fcntl(sock, F_SETFL, res | O_NONBLOCK) < 0) + goto error; + if (connect(sock, addr, len) < 0) + goto error; + + w->fd = sock; + w->llp = &el_job_connecting; + return el_job_setmode(w, EL_WRITING); + + error: + close(sock); + return el_job_release(w, EL_ERROR); +} + int el_dispatch(int timeout) { struct epoll_event events[FD_SETSIZE]; diff --git a/lib-sys/evtloop.h b/lib-sys/evtloop.h index f08f1e7..6c5e0d8 100644 --- a/lib-sys/evtloop.h +++ b/lib-sys/evtloop.h @@ -30,10 +30,11 @@ typedef enum el_state { } el_state; typedef enum el_mode { - EL_IDLE = 0, + EL_NEW = 0, EL_READING = 1, EL_WRITING = 2, EL_RDWR = 3, + EL_IDLE = 4, } el_mode; typedef enum el_status { @@ -55,13 +56,17 @@ typedef struct job_t { int fd; el_state state : 2; - el_mode mode : 2; - el_mode emode : 2; + el_mode mode : 3; + el_mode emode : 3; int (*llp)(struct job_t *); struct machine_t *m; void *ptr; } job_t; +DO_INIT(job_t, job); +DO_WIPE(job_t, job); +DO_NEW(job_t, job); +DO_DELETE(job_t, job); typedef struct machine_t { const char *name; @@ -70,7 +75,11 @@ typedef struct machine_t { void (*finalize)(job_t *w, el_status); } machine_t; +__must_check__ int el_job_setmode(job_t *w, el_mode); __must_check__ int el_job_release(job_t *j, el_status); +__must_check__ int el_job_connect(job_t *w, struct sockaddr *, socklen_t len, + int type, int proto); + int el_dispatch(int timeout); #endif -- 2.20.1