lighttpd 1.4.x
https://www.lighttpd.net/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
3.9 KiB
163 lines
3.9 KiB
8 months ago
|
#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));
|
||
|
}
|