blob: 6b73377a74b8398a2743326e6a5ccf5b75f838ba [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
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <fcntl.h>
Holger Hans Peter Freyther43558312010-08-06 06:48:43 +080023#include <stdio.h>
24
Pablo Neira Ayuso83419342011-03-22 16:36:13 +010025#include <osmocom/core/select.h>
26#include <osmocom/core/linuxlist.h>
27#include <osmocom/core/timer.h>
Harald Welteec8b4502010-02-20 20:34:29 +010028
Harald Welte54844802010-02-20 22:23:08 +010029#include "../config.h"
30
Harald Welteec8b4502010-02-20 20:34:29 +010031#ifdef HAVE_SYS_SELECT_H
32
Harald Welteba6988b2011-08-17 12:46:48 +020033/*! \addtogroup select
34 * @{
35 */
36
37/*! \file select.c
38 * \brief select loop abstraction
39 */
40
Harald Welteec8b4502010-02-20 20:34:29 +010041static int maxfd = 0;
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020042static LLIST_HEAD(osmo_fds);
Harald Welteec8b4502010-02-20 20:34:29 +010043static int unregistered_count;
44
Harald Welteba6988b2011-08-17 12:46:48 +020045/*! \brief Register a new file descriptor with select loop abstraction
46 * \param[in] fd osmocom file descriptor to be registered
47 */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020048int osmo_fd_register(struct osmo_fd *fd)
Harald Welteec8b4502010-02-20 20:34:29 +010049{
50 int flags;
51
52 /* make FD nonblocking */
53 flags = fcntl(fd->fd, F_GETFL);
54 if (flags < 0)
55 return flags;
56 flags |= O_NONBLOCK;
57 flags = fcntl(fd->fd, F_SETFL, flags);
58 if (flags < 0)
59 return flags;
60
Harald Welte32e1f232011-06-26 13:07:18 +020061 /* set close-on-exec flag */
62 flags = fcntl(fd->fd, F_GETFD);
63 if (flags < 0)
64 return flags;
65 flags |= FD_CLOEXEC;
66 flags = fcntl(fd->fd, F_SETFD, flags);
67 if (flags < 0)
68 return flags;
69
Harald Welteec8b4502010-02-20 20:34:29 +010070 /* Register FD */
71 if (fd->fd > maxfd)
72 maxfd = fd->fd;
73
Holger Hans Peter Freyther43558312010-08-06 06:48:43 +080074#ifdef BSC_FD_CHECK
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020075 struct osmo_fd *entry;
76 llist_for_each_entry(entry, &osmo_fds, list) {
Holger Hans Peter Freyther43558312010-08-06 06:48:43 +080077 if (entry == fd) {
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020078 fprintf(stderr, "Adding a osmo_fd that is already in the list.\n");
Holger Hans Peter Freyther43558312010-08-06 06:48:43 +080079 return 0;
80 }
81 }
82#endif
83
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020084 llist_add_tail(&fd->list, &osmo_fds);
Harald Welteec8b4502010-02-20 20:34:29 +010085
86 return 0;
87}
88
Harald Welteba6988b2011-08-17 12:46:48 +020089/*! \brief Unregister a file descriptor from select loop abstraction
90 * \param[in] fd osmocom file descriptor to be unregistered
91 */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +020092void osmo_fd_unregister(struct osmo_fd *fd)
Harald Welteec8b4502010-02-20 20:34:29 +010093{
94 unregistered_count++;
95 llist_del(&fd->list);
96}
97
Harald Welteba6988b2011-08-17 12:46:48 +020098/*! \brief select main loop integration
99 * \param[in] polling should we pollonly (1) or block on select (0)
100 */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200101int osmo_select_main(int polling)
Harald Welteec8b4502010-02-20 20:34:29 +0100102{
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200103 struct osmo_fd *ufd, *tmp;
Harald Welteec8b4502010-02-20 20:34:29 +0100104 fd_set readset, writeset, exceptset;
105 int work = 0, rc;
106 struct timeval no_time = {0, 0};
107
108 FD_ZERO(&readset);
109 FD_ZERO(&writeset);
110 FD_ZERO(&exceptset);
111
112 /* prepare read and write fdsets */
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200113 llist_for_each_entry(ufd, &osmo_fds, list) {
Harald Welteec8b4502010-02-20 20:34:29 +0100114 if (ufd->when & BSC_FD_READ)
115 FD_SET(ufd->fd, &readset);
116
117 if (ufd->when & BSC_FD_WRITE)
118 FD_SET(ufd->fd, &writeset);
119
120 if (ufd->when & BSC_FD_EXCEPT)
121 FD_SET(ufd->fd, &exceptset);
122 }
123
Pablo Neira Ayuso0b21c1c2011-05-07 12:42:28 +0200124 osmo_timers_check();
Harald Welteec8b4502010-02-20 20:34:29 +0100125
126 if (!polling)
Pablo Neira Ayuso0b21c1c2011-05-07 12:42:28 +0200127 osmo_timers_prepare();
128 rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : osmo_timers_nearest());
Harald Welteec8b4502010-02-20 20:34:29 +0100129 if (rc < 0)
130 return 0;
131
132 /* fire timers */
Pablo Neira Ayuso0b21c1c2011-05-07 12:42:28 +0200133 osmo_timers_update();
Harald Welteec8b4502010-02-20 20:34:29 +0100134
135 /* call registered callback functions */
136restart:
137 unregistered_count = 0;
Pablo Neira Ayusof7f89d02011-05-07 12:42:40 +0200138 llist_for_each_entry_safe(ufd, tmp, &osmo_fds, list) {
Harald Welteec8b4502010-02-20 20:34:29 +0100139 int flags = 0;
140
141 if (FD_ISSET(ufd->fd, &readset)) {
142 flags |= BSC_FD_READ;
143 FD_CLR(ufd->fd, &readset);
144 }
145
146 if (FD_ISSET(ufd->fd, &writeset)) {
147 flags |= BSC_FD_WRITE;
148 FD_CLR(ufd->fd, &writeset);
149 }
150
151 if (FD_ISSET(ufd->fd, &exceptset)) {
152 flags |= BSC_FD_EXCEPT;
153 FD_CLR(ufd->fd, &exceptset);
154 }
155
156 if (flags) {
157 work = 1;
158 ufd->cb(ufd, flags);
159 }
160 /* ugly, ugly hack. If more than one filedescriptors were
161 * unregistered, they might have been consecutive and
162 * llist_for_each_entry_safe() is no longer safe */
Holger Hans Peter Freyther23ba4742010-04-11 17:33:19 +0200163 /* this seems to happen with the last element of the list as well */
164 if (unregistered_count >= 1)
Harald Welteec8b4502010-02-20 20:34:29 +0100165 goto restart;
166 }
167 return work;
168}
169
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200170/*! @} */
Harald Welteba6988b2011-08-17 12:46:48 +0200171
Harald Welteec8b4502010-02-20 20:34:29 +0100172#endif /* _HAVE_SYS_SELECT_H */