blob: 9517778ce31d3061212911879973a822c461277d [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
8 * it under the terms of the GNU General Public License version 2
9 * as published by the Free Software Foundation
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 this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <fcntl.h>
22#include <osmocore/select.h>
23#include <osmocore/linuxlist.h>
24#include <osmocore/timer.h>
25
Harald Welte54844802010-02-20 22:23:08 +010026#include "../config.h"
27
Harald Welteec8b4502010-02-20 20:34:29 +010028#ifdef HAVE_SYS_SELECT_H
29
30static int maxfd = 0;
31static LLIST_HEAD(bsc_fds);
32static int unregistered_count;
33
34int bsc_register_fd(struct bsc_fd *fd)
35{
36 int flags;
37
38 /* make FD nonblocking */
39 flags = fcntl(fd->fd, F_GETFL);
40 if (flags < 0)
41 return flags;
42 flags |= O_NONBLOCK;
43 flags = fcntl(fd->fd, F_SETFL, flags);
44 if (flags < 0)
45 return flags;
46
47 /* Register FD */
48 if (fd->fd > maxfd)
49 maxfd = fd->fd;
50
51 llist_add_tail(&fd->list, &bsc_fds);
52
53 return 0;
54}
55
56void bsc_unregister_fd(struct bsc_fd *fd)
57{
58 unregistered_count++;
59 llist_del(&fd->list);
60}
61
62int bsc_select_main(int polling)
63{
64 struct bsc_fd *ufd, *tmp;
65 fd_set readset, writeset, exceptset;
66 int work = 0, rc;
67 struct timeval no_time = {0, 0};
68
69 FD_ZERO(&readset);
70 FD_ZERO(&writeset);
71 FD_ZERO(&exceptset);
72
73 /* prepare read and write fdsets */
74 llist_for_each_entry(ufd, &bsc_fds, list) {
75 if (ufd->when & BSC_FD_READ)
76 FD_SET(ufd->fd, &readset);
77
78 if (ufd->when & BSC_FD_WRITE)
79 FD_SET(ufd->fd, &writeset);
80
81 if (ufd->when & BSC_FD_EXCEPT)
82 FD_SET(ufd->fd, &exceptset);
83 }
84
85 bsc_timer_check();
86
87 if (!polling)
88 bsc_prepare_timers();
89 rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : bsc_nearest_timer());
90 if (rc < 0)
91 return 0;
92
93 /* fire timers */
94 bsc_update_timers();
95
96 /* call registered callback functions */
97restart:
98 unregistered_count = 0;
99 llist_for_each_entry_safe(ufd, tmp, &bsc_fds, list) {
100 int flags = 0;
101
102 if (FD_ISSET(ufd->fd, &readset)) {
103 flags |= BSC_FD_READ;
104 FD_CLR(ufd->fd, &readset);
105 }
106
107 if (FD_ISSET(ufd->fd, &writeset)) {
108 flags |= BSC_FD_WRITE;
109 FD_CLR(ufd->fd, &writeset);
110 }
111
112 if (FD_ISSET(ufd->fd, &exceptset)) {
113 flags |= BSC_FD_EXCEPT;
114 FD_CLR(ufd->fd, &exceptset);
115 }
116
117 if (flags) {
118 work = 1;
119 ufd->cb(ufd, flags);
120 }
121 /* ugly, ugly hack. If more than one filedescriptors were
122 * unregistered, they might have been consecutive and
123 * llist_for_each_entry_safe() is no longer safe */
124 if (unregistered_count > 1)
125 goto restart;
126 }
127 return work;
128}
129
130#endif /* _HAVE_SYS_SELECT_H */