blob: 02bc2cc302e2437629d8e0513cefc6c6306332df [file] [log] [blame]
Harald Welteec8b4502010-02-20 20:34:29 +01001/* select filedescriptor handling, taken from:
2 * userspace logging daemon for the iptables ULOG target
3 * of the linux 2.4 netfilter subsystem.
4 *
5 * (C) 2000-2009 by Harald Welte <laforge@gnumonks.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
Harald Welte9d92f0e2010-10-31 13:56:45 +01008 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
Harald Welteec8b4502010-02-20 20:34:29 +010011 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
Jaroslav Škarvada2b82c1c2015-11-11 16:02:54 +010019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
Harald Welteec8b4502010-02-20 20:34:29 +010021 */
22
23#include <fcntl.h>
Holger Hans Peter Freyther43558312010-08-06 06:48:43 +080024#include <stdio.h>
Harald Welte9e166e82014-03-10 17:28:33 +010025#include <string.h>
26#include <sys/select.h>
Holger Hans Peter Freyther43558312010-08-06 06:48:43 +080027
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010028#include <osmocom/core/select.h>
29#include <osmocom/core/linuxlist.h>
30#include <osmocom/core/timer.h>
Harald Welteec8b4502010-02-20 20:34:29 +010031
Harald Welte54844802010-02-20 22:23:08 +010032#include "../config.h"
33
Harald Welteec8b4502010-02-20 20:34:29 +010034#ifdef HAVE_SYS_SELECT_H
35
Harald Welteba6988b2011-08-17 12:46:48 +020036/*! \addtogroup select
37 * @{
38 */
39
40/*! \file select.c
41 * \brief select loop abstraction
42 */
43
Harald Welteec8b4502010-02-20 20:34:29 +010044static int maxfd = 0;
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020045static LLIST_HEAD(osmo_fds);
Harald Welteec8b4502010-02-20 20:34:29 +010046static int unregistered_count;
47
Harald Welteba6988b2011-08-17 12:46:48 +020048/*! \brief Register a new file descriptor with select loop abstraction
49 * \param[in] fd osmocom file descriptor to be registered
50 */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020051int osmo_fd_register(struct osmo_fd *fd)
Harald Welteec8b4502010-02-20 20:34:29 +010052{
53 int flags;
54
55 /* make FD nonblocking */
56 flags = fcntl(fd->fd, F_GETFL);
57 if (flags < 0)
58 return flags;
59 flags |= O_NONBLOCK;
60 flags = fcntl(fd->fd, F_SETFL, flags);
61 if (flags < 0)
62 return flags;
63
Harald Welte32e1f232011-06-26 13:07:18 +020064 /* set close-on-exec flag */
65 flags = fcntl(fd->fd, F_GETFD);
66 if (flags < 0)
67 return flags;
68 flags |= FD_CLOEXEC;
69 flags = fcntl(fd->fd, F_SETFD, flags);
70 if (flags < 0)
71 return flags;
72
Harald Welteec8b4502010-02-20 20:34:29 +010073 /* Register FD */
74 if (fd->fd > maxfd)
75 maxfd = fd->fd;
76
Holger Hans Peter Freyther43558312010-08-06 06:48:43 +080077#ifdef BSC_FD_CHECK
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020078 struct osmo_fd *entry;
79 llist_for_each_entry(entry, &osmo_fds, list) {
Holger Hans Peter Freyther43558312010-08-06 06:48:43 +080080 if (entry == fd) {
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020081 fprintf(stderr, "Adding a osmo_fd that is already in the list.\n");
Holger Hans Peter Freyther43558312010-08-06 06:48:43 +080082 return 0;
83 }
84 }
85#endif
86
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020087 llist_add_tail(&fd->list, &osmo_fds);
Harald Welteec8b4502010-02-20 20:34:29 +010088
89 return 0;
90}
91
Harald Welteba6988b2011-08-17 12:46:48 +020092/*! \brief Unregister a file descriptor from select loop abstraction
93 * \param[in] fd osmocom file descriptor to be unregistered
94 */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020095void osmo_fd_unregister(struct osmo_fd *fd)
Harald Welteec8b4502010-02-20 20:34:29 +010096{
97 unregistered_count++;
98 llist_del(&fd->list);
99}
100
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100101inline int osmo_fd_fill_fds(void *_rset, void *_wset, void *_eset)
Harald Welteec8b4502010-02-20 20:34:29 +0100102{
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100103 fd_set *readset = _rset, *writeset = _wset, *exceptset = _eset;
104 struct osmo_fd *ufd;
Harald Welteec8b4502010-02-20 20:34:29 +0100105
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200106 llist_for_each_entry(ufd, &osmo_fds, list) {
Harald Welteec8b4502010-02-20 20:34:29 +0100107 if (ufd->when & BSC_FD_READ)
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100108 FD_SET(ufd->fd, readset);
Harald Welteec8b4502010-02-20 20:34:29 +0100109
110 if (ufd->when & BSC_FD_WRITE)
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100111 FD_SET(ufd->fd, writeset);
Harald Welteec8b4502010-02-20 20:34:29 +0100112
113 if (ufd->when & BSC_FD_EXCEPT)
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100114 FD_SET(ufd->fd, exceptset);
Harald Welteec8b4502010-02-20 20:34:29 +0100115 }
116
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100117 return maxfd;
118}
Harald Welteec8b4502010-02-20 20:34:29 +0100119
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100120inline int osmo_fd_disp_fds(void *_rset, void *_wset, void *_eset)
121{
122 struct osmo_fd *ufd, *tmp;
123 int work = 0;
124 fd_set *readset = _rset, *writeset = _wset, *exceptset = _eset;
Harald Welteec8b4502010-02-20 20:34:29 +0100125
Harald Welteec8b4502010-02-20 20:34:29 +0100126restart:
127 unregistered_count = 0;
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200128 llist_for_each_entry_safe(ufd, tmp, &osmo_fds, list) {
Harald Welteec8b4502010-02-20 20:34:29 +0100129 int flags = 0;
130
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100131 if (FD_ISSET(ufd->fd, readset)) {
Harald Welteec8b4502010-02-20 20:34:29 +0100132 flags |= BSC_FD_READ;
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100133 FD_CLR(ufd->fd, readset);
Harald Welteec8b4502010-02-20 20:34:29 +0100134 }
135
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100136 if (FD_ISSET(ufd->fd, writeset)) {
Harald Welteec8b4502010-02-20 20:34:29 +0100137 flags |= BSC_FD_WRITE;
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100138 FD_CLR(ufd->fd, writeset);
Harald Welteec8b4502010-02-20 20:34:29 +0100139 }
140
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100141 if (FD_ISSET(ufd->fd, exceptset)) {
Harald Welteec8b4502010-02-20 20:34:29 +0100142 flags |= BSC_FD_EXCEPT;
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100143 FD_CLR(ufd->fd, exceptset);
Harald Welteec8b4502010-02-20 20:34:29 +0100144 }
145
146 if (flags) {
147 work = 1;
148 ufd->cb(ufd, flags);
149 }
Holger Hans Peter Freyther92e1e702014-04-09 17:24:00 +0200150 /* ugly, ugly hack. If more than one filedescriptor was
Harald Welteec8b4502010-02-20 20:34:29 +0100151 * unregistered, they might have been consecutive and
152 * llist_for_each_entry_safe() is no longer safe */
Holger Hans Peter Freyther23ba4742010-04-11 17:33:19 +0200153 /* this seems to happen with the last element of the list as well */
154 if (unregistered_count >= 1)
Harald Welteec8b4502010-02-20 20:34:29 +0100155 goto restart;
156 }
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100157
Harald Welteec8b4502010-02-20 20:34:29 +0100158 return work;
159}
160
Holger Hans Peter Freyther61f28882016-03-21 09:55:05 +0100161/*! \brief select main loop integration
162 * \param[in] polling should we pollonly (1) or block on select (0)
163 */
164int osmo_select_main(int polling)
165{
166 fd_set readset, writeset, exceptset;
167 int rc;
168 struct timeval no_time = {0, 0};
169
170 FD_ZERO(&readset);
171 FD_ZERO(&writeset);
172 FD_ZERO(&exceptset);
173
174 /* prepare read and write fdsets */
175 osmo_fd_fill_fds(&readset, &writeset, &exceptset);
176
177 osmo_timers_check();
178
179 if (!polling)
180 osmo_timers_prepare();
181 rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : osmo_timers_nearest());
182 if (rc < 0)
183 return 0;
184
185 /* fire timers */
186 osmo_timers_update();
187
188 /* call registered callback functions */
189 return osmo_fd_disp_fds(&readset, &writeset, &exceptset);
190}
191
Harald Welte6c33ae22016-03-19 21:17:58 +0100192/*! \brief find an osmo_fd based on the integer fd */
193struct osmo_fd *osmo_fd_get_by_fd(int fd)
194{
195 struct osmo_fd *ofd;
196
197 llist_for_each_entry(ofd, &osmo_fds, list) {
198 if (ofd->fd == fd)
199 return ofd;
200 }
201 return NULL;
202}
203
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200204/*! @} */
Harald Welteba6988b2011-08-17 12:46:48 +0200205
Harald Welteec8b4502010-02-20 20:34:29 +0100206#endif /* _HAVE_SYS_SELECT_H */