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