lib: Fixed mblock bug for epoll.
[ashd.git] / lib / mtio-select.c
CommitLineData
a6cda4dd
FT
1/*
2 ashd - A Sane HTTP Daemon
3 Copyright (C) 2008 Fredrik Tolf <fredrik@dolda2000.com>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include <stdlib.h>
20#include <string.h>
3f3a9a68
FT
21#include <time.h>
22#include <unistd.h>
a6cda4dd
FT
23#include <errno.h>
24#include <sys/select.h>
25
26#ifdef HAVE_CONFIG_H
27#include <config.h>
28#endif
29#include <log.h>
30#include <utils.h>
31#include <mt.h>
32#include <mtio.h>
33
34static struct blocker *blockers;
9d32586e 35static int exitstatus;
a6cda4dd
FT
36
37struct blocker {
38 struct blocker *n, *p;
39 int fd;
205ee933 40 int ev, rev, id;
a6cda4dd
FT
41 time_t to;
42 struct muth *th;
43};
44
205ee933 45static void addblock(struct blocker *bl)
a6cda4dd 46{
a6cda4dd
FT
47 bl->n = blockers;
48 if(blockers)
49 blockers->p = bl;
50 blockers = bl;
205ee933
FT
51}
52
53static void remblock(struct blocker *bl)
54{
a6cda4dd
FT
55 if(bl->n)
56 bl->n->p = bl->p;
57 if(bl->p)
58 bl->p->n = bl->n;
59 if(bl == blockers)
60 blockers = bl->n;
205ee933
FT
61}
62
63struct selected mblock(time_t to, int n, struct selected *spec)
64{
65 int i, id;
66 struct blocker bls[n];
67
68 to = (to > 0)?(time(NULL) + to):0;
69 for(i = 0; i < n; i++) {
70 bls[i] = (struct blocker){
71 .fd = spec[i].fd,
72 .ev = spec[i].ev,
73 .id = i,
74 .to = to,
75 .th = current,
76 };
77 addblock(&bls[i]);
78 }
79 id = yield();
80 for(i = 0; i < n; i++)
81 remblock(&bls[i]);
82 if(id < 0)
83 return((struct selected){.fd = -1, .ev = -1});
84 return((struct selected){.fd = bls[id].fd, .ev = bls[id].rev});
85}
86
87int block(int fd, int ev, time_t to)
88{
89 struct blocker bl;
90 int rv;
91
92 if(fd >= FD_SETSIZE) {
93 flog(LOG_ERR, "tried to use more file descriptors than select() can handle: fd %i", fd);
94 errno = EMFILE;
95 return(-1);
96 }
97 bl = (struct blocker) {
98 .fd = fd,
99 .ev = ev,
100 .id = -1,
101 .to = (to > 0)?(time(NULL) + to):0,
102 .th = current,
103 };
104 addblock(&bl);
105 rv = yield();
106 remblock(&bl);
a6cda4dd
FT
107 return(rv);
108}
109
9d32586e 110int ioloop(void)
a6cda4dd
FT
111{
112 int ret;
113 fd_set rfds, wfds, efds;
114 struct blocker *bl, *nbl;
115 struct timeval toval;
116 time_t now, timeout;
117 int maxfd;
118 int ev;
119
9d32586e 120 exitstatus = 0;
a6cda4dd
FT
121 while(blockers != NULL) {
122 FD_ZERO(&rfds);
123 FD_ZERO(&wfds);
124 FD_ZERO(&efds);
125 maxfd = 0;
126 now = time(NULL);
127 timeout = 0;
128 for(bl = blockers; bl; bl = bl->n) {
129 if(bl->ev & EV_READ)
130 FD_SET(bl->fd, &rfds);
131 if(bl->ev & EV_WRITE)
132 FD_SET(bl->fd, &wfds);
133 FD_SET(bl->fd, &efds);
134 if(bl->fd > maxfd)
135 maxfd = bl->fd;
136 if((bl->to != 0) && ((timeout == 0) || (timeout > bl->to)))
137 timeout = bl->to;
138 }
9d32586e
FT
139 if(exitstatus)
140 return(exitstatus);
a6cda4dd
FT
141 toval.tv_sec = timeout - now;
142 toval.tv_usec = 0;
143 ret = select(maxfd + 1, &rfds, &wfds, &efds, timeout?(&toval):NULL);
144 if(ret < 0) {
145 if(errno != EINTR) {
146 flog(LOG_CRIT, "ioloop: select errored out: %s", strerror(errno));
147 /* To avoid CPU hogging in case it's bad, which it
148 * probably is. */
149 sleep(1);
150 }
9d32586e
FT
151 } else {
152 now = time(NULL);
153 for(bl = blockers; bl; bl = nbl) {
154 nbl = bl->n;
155 ev = 0;
156 if(FD_ISSET(bl->fd, &rfds))
157 ev |= EV_READ;
158 if(FD_ISSET(bl->fd, &wfds))
159 ev |= EV_WRITE;
160 if(FD_ISSET(bl->fd, &efds))
161 ev = -1;
205ee933
FT
162 if((ev < 0) || (ev & bl->ev)) {
163 if(bl->id < 0) {
164 resume(bl->th, ev);
165 } else {
166 bl->rev = ev;
167 resume(bl->th, bl->id);
168 }
169 } else if((bl->to != 0) && (bl->to <= now)) {
170 if(bl->id < 0) {
171 resume(bl->th, 0);
172 } else {
173 bl->rev = 0;
174 resume(bl->th, bl->id);
175 }
176 }
9d32586e 177 }
a6cda4dd
FT
178 }
179 }
9d32586e
FT
180 return(0);
181}
182
183void exitioloop(int status)
184{
185 exitstatus = status;
a6cda4dd 186}