Convert time-related variables to consistently use "unsigned long".
[srvx.git] / src / ioset-select.c
1 /* ioset select() backend for srvx
2  * Copyright 2002-2006 srvx Development Team
3  *
4  * This file is part of srvx.
5  *
6  * srvx is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with srvx; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
19  */
20
21 #include "ioset-impl.h"
22 #include "common.h"
23 #include "log.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27
28 #ifdef HAVE_SYS_SELECT_H
29 # include <sys/select.h>
30 #endif
31
32 #ifdef HAVE_SYS_SOCKET_H
33 # include <sys/socket.h>
34 #endif
35
36 extern int clock_skew;
37 static struct io_fd **fds;
38 static unsigned int fds_size;
39 static fd_set read_fds, write_fds;
40
41 static int
42 ioset_select_init(void)
43 {
44     return 1;
45 }
46
47 static void
48 ioset_select_add(struct io_fd *fd)
49 {
50     if ((unsigned)fd->fd >= fds_size) {
51         unsigned int old_size = fds_size;
52         fds_size = fd->fd + 8;
53         fds = realloc(fds, fds_size*sizeof(*fds));
54         memset(fds+old_size, 0, (fds_size-old_size)*sizeof(*fds));
55     }
56     fds[fd->fd] = fd;
57 }
58
59 static void
60 ioset_select_remove(struct io_fd *fd, int closed)
61 {
62     FD_CLR(fd->fd, &read_fds);
63     FD_CLR(fd->fd, &write_fds);
64     (void)closed;
65 }
66
67 static void
68 ioset_select_update(struct io_fd *fd)
69 {
70     (void)fd;
71 }
72
73 static void
74 ioset_select_cleanup(void)
75 {
76     free(fds);
77 }
78
79 #if 0
80 #define debug_fdsets(MSG, NFDS, READ_FDS, WRITE_FDS, EXCEPT_FDS, SELECT_TIMEOUT) (void)0
81 #else
82 static void
83 debug_fdsets(const char *msg, int nfds, fd_set *read_fds, fd_set *write_fds, fd_set *except_fds, struct timeval *select_timeout) {
84     static const char *flag_text[8] = { "---", "r", "w", "rw", "e", "er", "ew", "erw" };
85     char buf[MAXLEN];
86     int pos, ii, flags;
87     struct timeval now;
88
89     for (pos=ii=0; ii<nfds; ++ii) {
90         flags  = (read_fds && FD_ISSET(ii, read_fds)) ? 1 : 0;
91         flags |= (write_fds && FD_ISSET(ii, write_fds)) ? 2 : 0;
92         flags |= (except_fds && FD_ISSET(ii, except_fds)) ? 4 : 0;
93         if (!flags)
94             continue;
95         pos += sprintf(buf+pos, " %d%s", ii, flag_text[flags]);
96     }
97     gettimeofday(&now, NULL);
98     if (select_timeout) {
99         log_module(MAIN_LOG, LOG_DEBUG, "%s, at %lu.%06lu:%s (timeout %lu.%06lu)", msg, (unsigned long)now.tv_sec, (unsigned long)now.tv_usec, buf, (unsigned long)select_timeout->tv_sec, (unsigned long)select_timeout->tv_usec);
100     } else {
101         log_module(MAIN_LOG, LOG_DEBUG, "%s, at %lu.%06lu:%s (no timeout)", msg, (unsigned long)now.tv_sec, (unsigned long)now.tv_usec, buf);
102     }
103 }
104 #endif
105
106 static int
107 ioset_select_loop(struct timeval *timeout)
108 {
109     struct io_fd *fd;
110     unsigned int nn;
111     int select_result;
112     int max_fd;
113
114     /* Set up read_fds and write_fds fdsets. */
115     FD_ZERO(&read_fds);
116     FD_ZERO(&write_fds);
117     max_fd = -1;
118     for (nn=0; nn<fds_size; nn++) {
119         if (!(fd = fds[nn]))
120             continue;
121         max_fd = nn;
122         FD_SET(nn, &read_fds);
123         if (fd_wants_writes(fd))
124             FD_SET(nn, &write_fds);
125     }
126
127     /* Check for activity, update time. */
128     debug_fdsets("Entering select", max_fd+1, &read_fds, &write_fds, NULL, timeout);
129     select_result = select(max_fd + 1, &read_fds, &write_fds, NULL, timeout);
130     debug_fdsets("After select", max_fd+1, &read_fds, &write_fds, NULL, timeout);
131     now = time(NULL) + clock_skew;
132     if (select_result < 0) {
133         if (errno != EINTR) {
134             log_module(MAIN_LOG, LOG_ERROR, "select() error %d: %s", errno, strerror(errno));
135             close_socket();
136         }
137         return 1;
138     }
139
140     /* Call back anybody that has connect or read activity and wants to know. */
141     for (nn=0; nn<fds_size; nn++) {
142         ioset_events(fds[nn], FD_ISSET(nn, &read_fds), FD_ISSET(nn, &write_fds));
143     }
144     return 0;
145 }
146
147 struct io_engine io_engine_select = {
148     .name = "select",
149     .init = ioset_select_init,
150     .add = ioset_select_add,
151     .remove = ioset_select_remove,
152     .update = ioset_select_update,
153     .loop = ioset_select_loop,
154     .cleanup = ioset_select_cleanup,
155 };