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