xref: /lighttpd1.4/src/fdevent_fdnode.c (revision 33fd0db9)
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