blob: 477ff66269aad3459d97e8f12bf33d971a570b45 [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
Harald Welteba6988b2011-08-17 12:46:48 +0200101/*! \brief select main loop integration
102 * \param[in] polling should we pollonly (1) or block on select (0)
103 */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200104int osmo_select_main(int polling)
Harald Welteec8b4502010-02-20 20:34:29 +0100105{
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200106 struct osmo_fd *ufd, *tmp;
Harald Welteec8b4502010-02-20 20:34:29 +0100107 fd_set readset, writeset, exceptset;
108 int work = 0, rc;
109 struct timeval no_time = {0, 0};
110
111 FD_ZERO(&readset);
112 FD_ZERO(&writeset);
113 FD_ZERO(&exceptset);
114
115 /* prepare read and write fdsets */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200116 llist_for_each_entry(ufd, &osmo_fds, list) {
Harald Welteec8b4502010-02-20 20:34:29 +0100117 if (ufd->when & BSC_FD_READ)
118 FD_SET(ufd->fd, &readset);
119
120 if (ufd->when & BSC_FD_WRITE)
121 FD_SET(ufd->fd, &writeset);
122
123 if (ufd->when & BSC_FD_EXCEPT)
124 FD_SET(ufd->fd, &exceptset);
125 }
126
Pablo Neira Ayuso0b21c1c2011-05-07 12:42:28 +0200127 osmo_timers_check();
Harald Welteec8b4502010-02-20 20:34:29 +0100128
129 if (!polling)
Pablo Neira Ayuso0b21c1c2011-05-07 12:42:28 +0200130 osmo_timers_prepare();
131 rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : osmo_timers_nearest());
Harald Welteec8b4502010-02-20 20:34:29 +0100132 if (rc < 0)
133 return 0;
134
135 /* fire timers */
Pablo Neira Ayuso0b21c1c2011-05-07 12:42:28 +0200136 osmo_timers_update();
Harald Welteec8b4502010-02-20 20:34:29 +0100137
138 /* call registered callback functions */
139restart:
140 unregistered_count = 0;
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200141 llist_for_each_entry_safe(ufd, tmp, &osmo_fds, list) {
Harald Welteec8b4502010-02-20 20:34:29 +0100142 int flags = 0;
143
144 if (FD_ISSET(ufd->fd, &readset)) {
145 flags |= BSC_FD_READ;
146 FD_CLR(ufd->fd, &readset);
147 }
148
149 if (FD_ISSET(ufd->fd, &writeset)) {
150 flags |= BSC_FD_WRITE;
151 FD_CLR(ufd->fd, &writeset);
152 }
153
154 if (FD_ISSET(ufd->fd, &exceptset)) {
155 flags |= BSC_FD_EXCEPT;
156 FD_CLR(ufd->fd, &exceptset);
157 }
158
159 if (flags) {
160 work = 1;
161 ufd->cb(ufd, flags);
162 }
Holger Hans Peter Freyther92e1e702014-04-09 17:24:00 +0200163 /* ugly, ugly hack. If more than one filedescriptor was
Harald Welteec8b4502010-02-20 20:34:29 +0100164 * unregistered, they might have been consecutive and
165 * llist_for_each_entry_safe() is no longer safe */
Holger Hans Peter Freyther23ba4742010-04-11 17:33:19 +0200166 /* this seems to happen with the last element of the list as well */
167 if (unregistered_count >= 1)
Harald Welteec8b4502010-02-20 20:34:29 +0100168 goto restart;
169 }
170 return work;
171}
172
Harald Welte6c33ae22016-03-19 21:17:58 +0100173/*! \brief find an osmo_fd based on the integer fd */
174struct osmo_fd *osmo_fd_get_by_fd(int fd)
175{
176 struct osmo_fd *ofd;
177
178 llist_for_each_entry(ofd, &osmo_fds, list) {
179 if (ofd->fd == fd)
180 return ofd;
181 }
182 return NULL;
183}
184
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200185/*! @} */
Harald Welteba6988b2011-08-17 12:46:48 +0200186
Harald Welteec8b4502010-02-20 20:34:29 +0100187#endif /* _HAVE_SYS_SELECT_H */