xref: /lighttpd1.4/src/fdevent_fdnode.c (revision f0786a75)
10f51b372SGlenn Strauss #include "first.h"
20f51b372SGlenn Strauss 
30f51b372SGlenn Strauss #include "fdevent_impl.h"
40f51b372SGlenn Strauss #include "fdevent.h"
50f51b372SGlenn Strauss #include "buffer.h"
60f51b372SGlenn Strauss #include "log.h"
70f51b372SGlenn Strauss 
80f51b372SGlenn Strauss #include <stdlib.h>
90f51b372SGlenn Strauss #include <errno.h>
100f51b372SGlenn Strauss 
110f51b372SGlenn Strauss __attribute_malloc__
120f51b372SGlenn Strauss __attribute_returns_nonnull__
130f51b372SGlenn Strauss static fdnode *
fdnode_init(void)140f51b372SGlenn Strauss fdnode_init (void)
150f51b372SGlenn Strauss {
165e14db43SGlenn Strauss     return ck_calloc(1, sizeof(fdnode));
170f51b372SGlenn Strauss }
180f51b372SGlenn Strauss 
190f51b372SGlenn Strauss static void
fdnode_free(fdnode * fdn)200f51b372SGlenn Strauss fdnode_free (fdnode *fdn)
210f51b372SGlenn Strauss {
220f51b372SGlenn Strauss     free(fdn);
230f51b372SGlenn Strauss }
240f51b372SGlenn Strauss 
250f51b372SGlenn Strauss fdnode *
fdevent_register(fdevents * ev,int fd,fdevent_handler handler,void * ctx)260f51b372SGlenn Strauss fdevent_register (fdevents *ev, int fd, fdevent_handler handler, void *ctx)
270f51b372SGlenn Strauss {
280f51b372SGlenn Strauss     fdnode *fdn  = ev->fdarray[fd] = fdnode_init();
290f51b372SGlenn Strauss     fdn->handler = handler;
300f51b372SGlenn Strauss     fdn->fd      = fd;
310f51b372SGlenn Strauss     fdn->ctx     = ctx;
320f51b372SGlenn Strauss     fdn->events  = 0;
330f51b372SGlenn Strauss     fdn->fde_ndx = -1;
340f51b372SGlenn Strauss     return fdn;
350f51b372SGlenn Strauss }
360f51b372SGlenn Strauss 
370f51b372SGlenn Strauss void
fdevent_unregister(fdevents * ev,fdnode * fdn)38*f0786a75SGlenn Strauss fdevent_unregister (fdevents *ev, fdnode *fdn)
390f51b372SGlenn Strauss {
40*f0786a75SGlenn Strauss     fdnode **fdn_slot = &ev->fdarray[fdn->fd];
41*f0786a75SGlenn Strauss     if ((uintptr_t)*fdn_slot & 0x3) return; /*(should not happen)*/
42*f0786a75SGlenn Strauss     *fdn_slot = NULL;
430f51b372SGlenn Strauss     fdnode_free(fdn);
440f51b372SGlenn Strauss }
450f51b372SGlenn Strauss 
460f51b372SGlenn Strauss void
fdevent_sched_close(fdevents * ev,fdnode * fdn)47*f0786a75SGlenn Strauss fdevent_sched_close (fdevents *ev, fdnode *fdn)
480f51b372SGlenn Strauss {
49*f0786a75SGlenn Strauss     fdnode **fdn_slot = &ev->fdarray[fdn->fd];
50*f0786a75SGlenn Strauss     if ((uintptr_t)*fdn_slot & 0x3) return;
51*f0786a75SGlenn Strauss     *fdn_slot = (fdnode *)((uintptr_t)fdn | 0x3);
520f51b372SGlenn Strauss     fdn->handler = (fdevent_handler)NULL;
530f51b372SGlenn Strauss     fdn->ctx = ev->pendclose;
540f51b372SGlenn Strauss     ev->pendclose = fdn;
550f51b372SGlenn Strauss }
560f51b372SGlenn Strauss 
570f51b372SGlenn Strauss __attribute_cold__
580f51b372SGlenn Strauss __attribute_noinline__
590f51b372SGlenn Strauss static int
fdevent_fdnode_event_unsetter_retry(fdevents * ev,fdnode * fdn)600f51b372SGlenn Strauss fdevent_fdnode_event_unsetter_retry (fdevents *ev, fdnode *fdn)
610f51b372SGlenn Strauss {
620f51b372SGlenn Strauss     do {
630f51b372SGlenn Strauss         switch (errno) {
640f51b372SGlenn Strauss          #ifdef EWOULDBLOCK
650f51b372SGlenn Strauss          #if EAGAIN != EWOULDBLOCK
660f51b372SGlenn Strauss           case EWOULDBLOCK:
670f51b372SGlenn Strauss          #endif
680f51b372SGlenn Strauss          #endif
690f51b372SGlenn Strauss           case EAGAIN:
700f51b372SGlenn Strauss           case EINTR:
710f51b372SGlenn Strauss             /* temporary error; retry */
720f51b372SGlenn Strauss             break;
730f51b372SGlenn Strauss           /*case ENOMEM:*/
740f51b372SGlenn Strauss           default:
750f51b372SGlenn Strauss             /* unrecoverable error; might leak fd */
760f51b372SGlenn Strauss             log_perror(ev->errh, __FILE__, __LINE__,
770f51b372SGlenn Strauss               "fdevent event_del failed on fd %d", fdn->fd);
780f51b372SGlenn Strauss             return 0;
790f51b372SGlenn Strauss         }
800f51b372SGlenn Strauss     } while (0 != ev->event_del(ev, fdn));
810f51b372SGlenn Strauss     return 1;
820f51b372SGlenn Strauss }
830f51b372SGlenn Strauss 
840f51b372SGlenn Strauss static void
fdevent_fdnode_event_unsetter(fdevents * ev,fdnode * fdn)850f51b372SGlenn Strauss fdevent_fdnode_event_unsetter (fdevents *ev, fdnode *fdn)
860f51b372SGlenn Strauss {
870f51b372SGlenn Strauss     if (-1 == fdn->fde_ndx) return;
880f51b372SGlenn Strauss     if (0 != ev->event_del(ev, fdn))
890f51b372SGlenn Strauss         fdevent_fdnode_event_unsetter_retry(ev, fdn);
900f51b372SGlenn Strauss     fdn->fde_ndx = -1;
910f51b372SGlenn Strauss     fdn->events = 0;
920f51b372SGlenn Strauss }
930f51b372SGlenn Strauss 
940f51b372SGlenn Strauss __attribute_cold__
950f51b372SGlenn Strauss __attribute_noinline__
960f51b372SGlenn Strauss static int
fdevent_fdnode_event_setter_retry(fdevents * ev,fdnode * fdn,int events)970f51b372SGlenn Strauss fdevent_fdnode_event_setter_retry (fdevents *ev, fdnode *fdn, int events)
980f51b372SGlenn Strauss {
990f51b372SGlenn Strauss     do {
1000f51b372SGlenn Strauss         switch (errno) {
1010f51b372SGlenn Strauss          #ifdef EWOULDBLOCK
1020f51b372SGlenn Strauss          #if EAGAIN != EWOULDBLOCK
1030f51b372SGlenn Strauss           case EWOULDBLOCK:
1040f51b372SGlenn Strauss          #endif
1050f51b372SGlenn Strauss          #endif
1060f51b372SGlenn Strauss           case EAGAIN:
1070f51b372SGlenn Strauss           case EINTR:
1080f51b372SGlenn Strauss             /* temporary error; retry */
1090f51b372SGlenn Strauss             break;
1100f51b372SGlenn Strauss           /*case ENOMEM:*/
1110f51b372SGlenn Strauss           default:
1120f51b372SGlenn Strauss             /* unrecoverable error */
1130f51b372SGlenn Strauss             log_perror(ev->errh, __FILE__, __LINE__,
1140f51b372SGlenn Strauss               "fdevent event_set failed on fd %d", fdn->fd);
1150f51b372SGlenn Strauss             return 0;
1160f51b372SGlenn Strauss         }
1170f51b372SGlenn Strauss     } while (0 != ev->event_set(ev, fdn, events));
1180f51b372SGlenn Strauss     return 1;
1190f51b372SGlenn Strauss }
1200f51b372SGlenn Strauss 
1210f51b372SGlenn Strauss static void
fdevent_fdnode_event_setter(fdevents * ev,fdnode * fdn,int events)1220f51b372SGlenn Strauss fdevent_fdnode_event_setter (fdevents *ev, fdnode *fdn, int events)
1230f51b372SGlenn Strauss {
1240f51b372SGlenn Strauss     /*(Note: skips registering with kernel if initial events is 0,
1250f51b372SGlenn Strauss      * so caller should pass non-zero events for initial registration.
1260f51b372SGlenn Strauss      * If never registered due to never being called with non-zero events,
1270f51b372SGlenn Strauss      * then FDEVENT_HUP or FDEVENT_ERR will never be returned.) */
1280f51b372SGlenn Strauss     if (fdn->events == events) return;/*(no change; nothing to do)*/
1290f51b372SGlenn Strauss 
1300f51b372SGlenn Strauss     if (0 == ev->event_set(ev, fdn, events)
1310f51b372SGlenn Strauss         || fdevent_fdnode_event_setter_retry(ev, fdn, events))
1320f51b372SGlenn Strauss         fdn->events = events;
1330f51b372SGlenn Strauss }
1340f51b372SGlenn Strauss 
1350f51b372SGlenn Strauss void
fdevent_fdnode_event_del(fdevents * ev,fdnode * fdn)1360f51b372SGlenn Strauss fdevent_fdnode_event_del (fdevents *ev, fdnode *fdn)
1370f51b372SGlenn Strauss {
1380f51b372SGlenn Strauss     if (NULL != fdn) fdevent_fdnode_event_unsetter(ev, fdn);
1390f51b372SGlenn Strauss }
1400f51b372SGlenn Strauss 
1410f51b372SGlenn Strauss void
fdevent_fdnode_event_set(fdevents * ev,fdnode * fdn,int events)1420f51b372SGlenn Strauss fdevent_fdnode_event_set (fdevents *ev, fdnode *fdn, int events)
1430f51b372SGlenn Strauss {
1440f51b372SGlenn Strauss     if (NULL != fdn) fdevent_fdnode_event_setter(ev, fdn, events);
1450f51b372SGlenn Strauss }
1460f51b372SGlenn Strauss 
1470f51b372SGlenn Strauss void
fdevent_fdnode_event_add(fdevents * ev,fdnode * fdn,int event)1480f51b372SGlenn Strauss fdevent_fdnode_event_add (fdevents *ev, fdnode *fdn, int event)
1490f51b372SGlenn Strauss {
1500f51b372SGlenn Strauss     if (NULL != fdn) fdevent_fdnode_event_setter(ev, fdn, (fdn->events|event));
1510f51b372SGlenn Strauss }
1520f51b372SGlenn Strauss 
1530f51b372SGlenn Strauss void
fdevent_fdnode_event_clr(fdevents * ev,fdnode * fdn,int event)1540f51b372SGlenn Strauss fdevent_fdnode_event_clr (fdevents *ev, fdnode *fdn, int event)
1550f51b372SGlenn Strauss {
1560f51b372SGlenn Strauss     if (NULL != fdn) fdevent_fdnode_event_setter(ev, fdn, (fdn->events&~event));
1570f51b372SGlenn Strauss }
158