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