Wrap up version 1.3.3.
[minidlna.git] / select.c
blobe287760b96849a7e5c5935aef14d0c7ed90ecda3
1 /*
2 * Copyright (c) 2017 Gleb Smirnoff <glebius@FreeBSD.org>
3 * Copyright (c) 2002-2017 Igor Sysoev
4 * Copyright (c) 2011-2017 Nginx, Inc.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
29 #include <sys/types.h>
30 #include <sys/select.h>
31 #include <stdlib.h>
32 #include <assert.h>
33 #include <errno.h>
34 #include <stdio.h>
35 #include <string.h>
37 #include "event.h"
38 #include "log.h"
40 static event_module_init_t select_init;
41 static event_module_fini_t select_fini;
42 static event_module_add_t select_add;
43 static event_module_del_t select_del;
44 static event_module_process_t select_process;
46 static fd_set master_read_fd_set;
47 static fd_set master_write_fd_set;
48 static fd_set work_read_fd_set;
49 static fd_set work_write_fd_set;
51 static struct event **events;
52 static int nevents;
53 static int max_fd;
55 struct event_module event_module = {
56 .add = select_add,
57 .del = select_del,
58 .process = select_process,
59 .init = select_init,
60 .fini = select_fini,
63 static int
64 select_init(void)
67 events = calloc(FD_SETSIZE, sizeof(struct event *));
68 if (events == NULL)
69 return (ENOMEM);
71 FD_ZERO(&master_read_fd_set);
72 FD_ZERO(&master_write_fd_set);
73 max_fd = 0;
74 nevents = 0;
76 return (0);
80 static void
81 select_fini(void)
84 free(events);
85 events = NULL;
88 static int
89 select_add(struct event *ev)
92 assert(ev->fd < FD_SETSIZE);
94 switch (ev->rdwr) {
95 case EVENT_READ:
96 FD_SET(ev->fd, &master_read_fd_set);
97 break;
98 case EVENT_WRITE:
99 FD_SET(ev->fd, &master_write_fd_set);
100 break;
103 if (max_fd != -1 && max_fd < ev->fd)
104 max_fd = ev->fd;
106 events[nevents] = ev;
107 ev->index = nevents++;
109 assert(nevents < FD_SETSIZE);
111 return (0);
114 static int
115 select_del(struct event *ev, int flags)
118 assert(ev->fd < FD_SETSIZE);
120 switch (ev->rdwr) {
121 case EVENT_READ:
122 FD_CLR(ev->fd, &master_read_fd_set);
123 break;
124 case EVENT_WRITE:
125 FD_CLR(ev->fd, &master_write_fd_set);
126 break;
129 if (max_fd == ev->fd)
130 max_fd = -1;
132 if (ev->index < --nevents) {
133 struct event *ev0;
135 ev0 = events[nevents];
136 events[ev->index] = ev0;
137 ev0->index = ev->index;
139 ev->index = -1;
141 return (0);
144 static int
145 select_process(struct timeval *tv)
147 struct event *ev;
148 int ready, i;
150 /* Need to rescan for max_fd. */
151 if (max_fd == -1)
152 for (i = 0; i < nevents; i++) {
153 if (max_fd < events[i]->fd)
154 max_fd = events[i]->fd;
157 work_read_fd_set = master_read_fd_set;
158 work_write_fd_set = master_write_fd_set;
160 ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tv);
162 if (ready == -1) {
163 if (errno == EINTR)
164 return (errno);
165 DPRINTF(E_FATAL, L_GENERAL, "select(): %s. EXITING\n", strerror(errno));
168 if (ready == 0)
169 return (0);
171 for (i = 0; i < nevents; i++) {
172 ev = events[i];
174 switch (ev->rdwr) {
175 case EVENT_READ:
176 if (FD_ISSET(ev->fd, &work_read_fd_set))
177 ev->process(ev);
178 break;
179 case EVENT_WRITE:
180 if (FD_ISSET(ev->fd, &work_write_fd_set))
181 ev->process(ev);
182 break;
186 return (0);