Merge branch 'master' into timeheap
[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;
4b70e201 39 struct iterator *it;
a6cda4dd 40 int fd;
205ee933 41 int ev, rev, id;
a6cda4dd
FT
42 time_t to;
43 struct muth *th;
44};
45
4b70e201
FT
46struct iterator {
47 struct blocker *bl;
48};
49
205ee933 50static void addblock(struct blocker *bl)
a6cda4dd 51{
a6cda4dd
FT
52 bl->n = blockers;
53 if(blockers)
54 blockers->p = bl;
55 blockers = bl;
205ee933
FT
56}
57
58static void remblock(struct blocker *bl)
59{
a6cda4dd
FT
60 if(bl->n)
61 bl->n->p = bl->p;
62 if(bl->p)
63 bl->p->n = bl->n;
64 if(bl == blockers)
65 blockers = bl->n;
4b70e201
FT
66 if(bl->it) {
67 if((bl->it->bl = bl->n) != NULL)
68 bl->it->bl->it = bl->it;
69 bl->it = NULL;
70 }
205ee933
FT
71}
72
73struct selected mblock(time_t to, int n, struct selected *spec)
74{
75 int i, id;
76 struct blocker bls[n];
77
78 to = (to > 0)?(time(NULL) + to):0;
79 for(i = 0; i < n; i++) {
80 bls[i] = (struct blocker){
81 .fd = spec[i].fd,
82 .ev = spec[i].ev,
83 .id = i,
84 .to = to,
85 .th = current,
86 };
87 addblock(&bls[i]);
88 }
89 id = yield();
90 for(i = 0; i < n; i++)
91 remblock(&bls[i]);
92 if(id < 0)
93 return((struct selected){.fd = -1, .ev = -1});
94 return((struct selected){.fd = bls[id].fd, .ev = bls[id].rev});
95}
96
97int block(int fd, int ev, time_t to)
98{
99 struct blocker bl;
100 int rv;
101
102 if(fd >= FD_SETSIZE) {
103 flog(LOG_ERR, "tried to use more file descriptors than select() can handle: fd %i", fd);
104 errno = EMFILE;
105 return(-1);
106 }
107 bl = (struct blocker) {
108 .fd = fd,
109 .ev = ev,
110 .id = -1,
111 .to = (to > 0)?(time(NULL) + to):0,
112 .th = current,
113 };
114 addblock(&bl);
115 rv = yield();
116 remblock(&bl);
a6cda4dd
FT
117 return(rv);
118}
119
9d32586e 120int ioloop(void)
a6cda4dd
FT
121{
122 int ret;
123 fd_set rfds, wfds, efds;
4b70e201
FT
124 struct blocker *bl;
125 struct iterator it;
a6cda4dd
FT
126 struct timeval toval;
127 time_t now, timeout;
128 int maxfd;
129 int ev;
130
9d32586e 131 exitstatus = 0;
a6cda4dd
FT
132 while(blockers != NULL) {
133 FD_ZERO(&rfds);
134 FD_ZERO(&wfds);
135 FD_ZERO(&efds);
136 maxfd = 0;
137 now = time(NULL);
138 timeout = 0;
139 for(bl = blockers; bl; bl = bl->n) {
140 if(bl->ev & EV_READ)
141 FD_SET(bl->fd, &rfds);
142 if(bl->ev & EV_WRITE)
143 FD_SET(bl->fd, &wfds);
144 FD_SET(bl->fd, &efds);
145 if(bl->fd > maxfd)
146 maxfd = bl->fd;
147 if((bl->to != 0) && ((timeout == 0) || (timeout > bl->to)))
148 timeout = bl->to;
149 }
9d32586e
FT
150 if(exitstatus)
151 return(exitstatus);
a6cda4dd
FT
152 toval.tv_sec = timeout - now;
153 toval.tv_usec = 0;
154 ret = select(maxfd + 1, &rfds, &wfds, &efds, timeout?(&toval):NULL);
155 if(ret < 0) {
156 if(errno != EINTR) {
157 flog(LOG_CRIT, "ioloop: select errored out: %s", strerror(errno));
158 /* To avoid CPU hogging in case it's bad, which it
159 * probably is. */
160 sleep(1);
161 }
9d32586e
FT
162 } else {
163 now = time(NULL);
4b70e201
FT
164 for(bl = it.bl = blockers; bl; bl = it.bl) {
165 if((it.bl = bl->n) != NULL)
166 it.bl->it = &it;
9d32586e
FT
167 ev = 0;
168 if(FD_ISSET(bl->fd, &rfds))
169 ev |= EV_READ;
170 if(FD_ISSET(bl->fd, &wfds))
171 ev |= EV_WRITE;
172 if(FD_ISSET(bl->fd, &efds))
173 ev = -1;
205ee933
FT
174 if((ev < 0) || (ev & bl->ev)) {
175 if(bl->id < 0) {
176 resume(bl->th, ev);
177 } else {
178 bl->rev = ev;
179 resume(bl->th, bl->id);
180 }
181 } else if((bl->to != 0) && (bl->to <= now)) {
182 if(bl->id < 0) {
183 resume(bl->th, 0);
184 } else {
185 bl->rev = 0;
186 resume(bl->th, bl->id);
187 }
188 }
4b70e201
FT
189 if(it.bl)
190 it.bl->it = NULL;
9d32586e 191 }
a6cda4dd
FT
192 }
193 }
9d32586e
FT
194 return(0);
195}
196
197void exitioloop(int status)
198{
199 exitstatus = status;
a6cda4dd 200}