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