diff options
author | Glenn Strauss <gstrauss@gluelogic.com> | 2021-11-01 20:07:06 -0400 |
---|---|---|
committer | Glenn Strauss <gstrauss@gluelogic.com> | 2021-11-02 02:58:03 -0400 |
commit | 0f51b3728a8f184594073478456eb352c72dee52 (patch) | |
tree | 84e90ad07d51092130b65f1834a0c0f47a13a98c /src/fdevent_fdnode.c | |
parent | 7113dcb49b51b66a1f24203e57e93b61a1c47fbf (diff) | |
download | lighttpd-git-0f51b3728a8f184594073478456eb352c72dee52.tar.gz |
[core] fdevent_fdnode.c separate from fdevent.c
Diffstat (limited to 'src/fdevent_fdnode.c')
-rw-r--r-- | src/fdevent_fdnode.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/src/fdevent_fdnode.c b/src/fdevent_fdnode.c new file mode 100644 index 00000000..b79aad1a --- /dev/null +++ b/src/fdevent_fdnode.c @@ -0,0 +1,162 @@ +#include "first.h" + +#include "fdevent_impl.h" +#include "fdevent.h" +#include "buffer.h" +#include "log.h" + +#include <stdlib.h> +#include <errno.h> + +__attribute_malloc__ +__attribute_returns_nonnull__ +static fdnode * +fdnode_init (void) +{ + fdnode * const restrict fdn = calloc(1, sizeof(fdnode)); + force_assert(NULL != fdn); + return fdn; +} + +static void +fdnode_free (fdnode *fdn) +{ + free(fdn); +} + +fdnode * +fdevent_register (fdevents *ev, int fd, fdevent_handler handler, void *ctx) +{ + fdnode *fdn = ev->fdarray[fd] = fdnode_init(); + fdn->handler = handler; + fdn->fd = fd; + fdn->ctx = ctx; + fdn->events = 0; + fdn->fde_ndx = -1; + #ifdef FDEVENT_USE_LIBEV + fdn->handler_ctx = NULL; + #endif + return fdn; +} + +void +fdevent_unregister (fdevents *ev, int fd) +{ + fdnode *fdn = ev->fdarray[fd]; + if ((uintptr_t)fdn & 0x3) return; /*(should not happen)*/ + ev->fdarray[fd] = NULL; + fdnode_free(fdn); +} + +void +fdevent_sched_close (fdevents *ev, int fd, int issock) +{ + fdnode *fdn = ev->fdarray[fd]; + if ((uintptr_t)fdn & 0x3) return; + ev->fdarray[fd] = (fdnode *)((uintptr_t)fdn | (issock ? 0x1 : 0x2)); + fdn->handler = (fdevent_handler)NULL; + fdn->ctx = ev->pendclose; + ev->pendclose = fdn; +} + +__attribute_cold__ +__attribute_noinline__ +static int +fdevent_fdnode_event_unsetter_retry (fdevents *ev, fdnode *fdn) +{ + do { + switch (errno) { + #ifdef EWOULDBLOCK + #if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: + #endif + #endif + case EAGAIN: + case EINTR: + /* temporary error; retry */ + break; + /*case ENOMEM:*/ + default: + /* unrecoverable error; might leak fd */ + log_perror(ev->errh, __FILE__, __LINE__, + "fdevent event_del failed on fd %d", fdn->fd); + return 0; + } + } while (0 != ev->event_del(ev, fdn)); + return 1; +} + +static void +fdevent_fdnode_event_unsetter (fdevents *ev, fdnode *fdn) +{ + if (-1 == fdn->fde_ndx) return; + if (0 != ev->event_del(ev, fdn)) + fdevent_fdnode_event_unsetter_retry(ev, fdn); + fdn->fde_ndx = -1; + fdn->events = 0; +} + +__attribute_cold__ +__attribute_noinline__ +static int +fdevent_fdnode_event_setter_retry (fdevents *ev, fdnode *fdn, int events) +{ + do { + switch (errno) { + #ifdef EWOULDBLOCK + #if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: + #endif + #endif + case EAGAIN: + case EINTR: + /* temporary error; retry */ + break; + /*case ENOMEM:*/ + default: + /* unrecoverable error */ + log_perror(ev->errh, __FILE__, __LINE__, + "fdevent event_set failed on fd %d", fdn->fd); + return 0; + } + } while (0 != ev->event_set(ev, fdn, events)); + return 1; +} + +static void +fdevent_fdnode_event_setter (fdevents *ev, fdnode *fdn, int events) +{ + /*(Note: skips registering with kernel if initial events is 0, + * so caller should pass non-zero events for initial registration. + * If never registered due to never being called with non-zero events, + * then FDEVENT_HUP or FDEVENT_ERR will never be returned.) */ + if (fdn->events == events) return;/*(no change; nothing to do)*/ + + if (0 == ev->event_set(ev, fdn, events) + || fdevent_fdnode_event_setter_retry(ev, fdn, events)) + fdn->events = events; +} + +void +fdevent_fdnode_event_del (fdevents *ev, fdnode *fdn) +{ + if (NULL != fdn) fdevent_fdnode_event_unsetter(ev, fdn); +} + +void +fdevent_fdnode_event_set (fdevents *ev, fdnode *fdn, int events) +{ + if (NULL != fdn) fdevent_fdnode_event_setter(ev, fdn, events); +} + +void +fdevent_fdnode_event_add (fdevents *ev, fdnode *fdn, int event) +{ + if (NULL != fdn) fdevent_fdnode_event_setter(ev, fdn, (fdn->events|event)); +} + +void +fdevent_fdnode_event_clr (fdevents *ev, fdnode *fdn, int event) +{ + if (NULL != fdn) fdevent_fdnode_event_setter(ev, fdn, (fdn->events&~event)); +} |