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