1 #include "first.h" 2 3 #include "fdevent_impl.h" 4 #include "fdevent.h" 5 #include "buffer.h" 6 #include "log.h" 7 8 #include <stdlib.h> 9 #include <errno.h> 10 11 __attribute_malloc__ 12 __attribute_returns_nonnull__ 13 static fdnode * 14 fdnode_init (void) 15 { 16 fdnode * const restrict fdn = calloc(1, sizeof(fdnode)); 17 force_assert(NULL != fdn); 18 return fdn; 19 } 20 21 static void 22 fdnode_free (fdnode *fdn) 23 { 24 free(fdn); 25 } 26 27 fdnode * 28 fdevent_register (fdevents *ev, int fd, fdevent_handler handler, void *ctx) 29 { 30 fdnode *fdn = ev->fdarray[fd] = fdnode_init(); 31 fdn->handler = handler; 32 fdn->fd = fd; 33 fdn->ctx = ctx; 34 fdn->events = 0; 35 fdn->fde_ndx = -1; 36 #ifdef FDEVENT_USE_LIBEV 37 fdn->handler_ctx = NULL; 38 #endif 39 return fdn; 40 } 41 42 void 43 fdevent_unregister (fdevents *ev, int fd) 44 { 45 fdnode *fdn = ev->fdarray[fd]; 46 if ((uintptr_t)fdn & 0x3) return; /*(should not happen)*/ 47 ev->fdarray[fd] = NULL; 48 fdnode_free(fdn); 49 } 50 51 void 52 fdevent_sched_close (fdevents *ev, int fd, int issock) 53 { 54 fdnode *fdn = ev->fdarray[fd]; 55 if ((uintptr_t)fdn & 0x3) return; 56 ev->fdarray[fd] = (fdnode *)((uintptr_t)fdn | (issock ? 0x1 : 0x2)); 57 fdn->handler = (fdevent_handler)NULL; 58 fdn->ctx = ev->pendclose; 59 ev->pendclose = fdn; 60 } 61 62 __attribute_cold__ 63 __attribute_noinline__ 64 static int 65 fdevent_fdnode_event_unsetter_retry (fdevents *ev, fdnode *fdn) 66 { 67 do { 68 switch (errno) { 69 #ifdef EWOULDBLOCK 70 #if EAGAIN != EWOULDBLOCK 71 case EWOULDBLOCK: 72 #endif 73 #endif 74 case EAGAIN: 75 case EINTR: 76 /* temporary error; retry */ 77 break; 78 /*case ENOMEM:*/ 79 default: 80 /* unrecoverable error; might leak fd */ 81 log_perror(ev->errh, __FILE__, __LINE__, 82 "fdevent event_del failed on fd %d", fdn->fd); 83 return 0; 84 } 85 } while (0 != ev->event_del(ev, fdn)); 86 return 1; 87 } 88 89 static void 90 fdevent_fdnode_event_unsetter (fdevents *ev, fdnode *fdn) 91 { 92 if (-1 == fdn->fde_ndx) return; 93 if (0 != ev->event_del(ev, fdn)) 94 fdevent_fdnode_event_unsetter_retry(ev, fdn); 95 fdn->fde_ndx = -1; 96 fdn->events = 0; 97 } 98 99 __attribute_cold__ 100 __attribute_noinline__ 101 static int 102 fdevent_fdnode_event_setter_retry (fdevents *ev, fdnode *fdn, int events) 103 { 104 do { 105 switch (errno) { 106 #ifdef EWOULDBLOCK 107 #if EAGAIN != EWOULDBLOCK 108 case EWOULDBLOCK: 109 #endif 110 #endif 111 case EAGAIN: 112 case EINTR: 113 /* temporary error; retry */ 114 break; 115 /*case ENOMEM:*/ 116 default: 117 /* unrecoverable error */ 118 log_perror(ev->errh, __FILE__, __LINE__, 119 "fdevent event_set failed on fd %d", fdn->fd); 120 return 0; 121 } 122 } while (0 != ev->event_set(ev, fdn, events)); 123 return 1; 124 } 125 126 static void 127 fdevent_fdnode_event_setter (fdevents *ev, fdnode *fdn, int events) 128 { 129 /*(Note: skips registering with kernel if initial events is 0, 130 * so caller should pass non-zero events for initial registration. 131 * If never registered due to never being called with non-zero events, 132 * then FDEVENT_HUP or FDEVENT_ERR will never be returned.) */ 133 if (fdn->events == events) return;/*(no change; nothing to do)*/ 134 135 if (0 == ev->event_set(ev, fdn, events) 136 || fdevent_fdnode_event_setter_retry(ev, fdn, events)) 137 fdn->events = events; 138 } 139 140 void 141 fdevent_fdnode_event_del (fdevents *ev, fdnode *fdn) 142 { 143 if (NULL != fdn) fdevent_fdnode_event_unsetter(ev, fdn); 144 } 145 146 void 147 fdevent_fdnode_event_set (fdevents *ev, fdnode *fdn, int events) 148 { 149 if (NULL != fdn) fdevent_fdnode_event_setter(ev, fdn, events); 150 } 151 152 void 153 fdevent_fdnode_event_add (fdevents *ev, fdnode *fdn, int event) 154 { 155 if (NULL != fdn) fdevent_fdnode_event_setter(ev, fdn, (fdn->events|event)); 156 } 157 158 void 159 fdevent_fdnode_event_clr (fdevents *ev, fdnode *fdn, int event) 160 { 161 if (NULL != fdn) fdevent_fdnode_event_setter(ev, fdn, (fdn->events&~event)); 162 } 163