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 *
fdnode_init(void)14 fdnode_init (void)
15 {
16 return ck_calloc(1, sizeof(fdnode));
17 }
18
19 static void
fdnode_free(fdnode * fdn)20 fdnode_free (fdnode *fdn)
21 {
22 free(fdn);
23 }
24
25 fdnode *
fdevent_register(fdevents * ev,int fd,fdevent_handler handler,void * ctx)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
fdevent_unregister(fdevents * ev,fdnode * fdn)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
fdevent_sched_close(fdevents * ev,fdnode * fdn)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
fdevent_fdnode_event_unsetter_retry(fdevents * ev,fdnode * fdn)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
fdevent_fdnode_event_unsetter(fdevents * ev,fdnode * fdn)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
fdevent_fdnode_event_setter_retry(fdevents * ev,fdnode * fdn,int events)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
fdevent_fdnode_event_setter(fdevents * ev,fdnode * fdn,int events)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
fdevent_fdnode_event_del(fdevents * ev,fdnode * fdn)136 fdevent_fdnode_event_del (fdevents *ev, fdnode *fdn)
137 {
138 if (NULL != fdn) fdevent_fdnode_event_unsetter(ev, fdn);
139 }
140
141 void
fdevent_fdnode_event_set(fdevents * ev,fdnode * fdn,int events)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
fdevent_fdnode_event_add(fdevents * ev,fdnode * fdn,int event)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
fdevent_fdnode_event_clr(fdevents * ev,fdnode * fdn,int event)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