diff options
| author | Harald Welte <laforge@gnumonks.org> | 2010-02-20 20:34:29 +0100 | 
|---|---|---|
| committer | Harald Welte <laforge@gnumonks.org> | 2010-02-20 20:34:29 +0100 | 
| commit | ec8b4501c7b0bfb286db7789635168d1b84f9105 (patch) | |
| tree | 0db0073e589513d803d2b5be80580191e215dbe3 /src/select.c | |
intial checkin of the libosmocore project
Diffstat (limited to 'src/select.c')
| -rw-r--r-- | src/select.c | 128 | 
1 files changed, 128 insertions, 0 deletions
| diff --git a/src/select.c b/src/select.c new file mode 100644 index 00000000..4f5d7ed9 --- /dev/null +++ b/src/select.c @@ -0,0 +1,128 @@ +/* select filedescriptor handling, taken from: + * userspace logging daemon for the iptables ULOG target + * of the linux 2.4 netfilter subsystem. + * + * (C) 2000-2009 by Harald Welte <laforge@gnumonks.org> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License version 2  + *  as published by the Free Software Foundation + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <fcntl.h> +#include <osmocore/select.h> +#include <osmocore/linuxlist.h> +#include <osmocore/timer.h> + +#ifdef HAVE_SYS_SELECT_H + +static int maxfd = 0; +static LLIST_HEAD(bsc_fds); +static int unregistered_count; + +int bsc_register_fd(struct bsc_fd *fd) +{ +	int flags; + +	/* make FD nonblocking */ +	flags = fcntl(fd->fd, F_GETFL); +	if (flags < 0) +		return flags; +	flags |= O_NONBLOCK; +	flags = fcntl(fd->fd, F_SETFL, flags); +	if (flags < 0) +		return flags; + +	/* Register FD */ +	if (fd->fd > maxfd) +		maxfd = fd->fd; + +	llist_add_tail(&fd->list, &bsc_fds); + +	return 0; +} + +void bsc_unregister_fd(struct bsc_fd *fd) +{ +	unregistered_count++; +	llist_del(&fd->list); +} + +int bsc_select_main(int polling) +{ +	struct bsc_fd *ufd, *tmp; +	fd_set readset, writeset, exceptset; +	int work = 0, rc; +	struct timeval no_time = {0, 0}; + +	FD_ZERO(&readset); +	FD_ZERO(&writeset); +	FD_ZERO(&exceptset); + +	/* prepare read and write fdsets */ +	llist_for_each_entry(ufd, &bsc_fds, list) { +		if (ufd->when & BSC_FD_READ) +			FD_SET(ufd->fd, &readset); + +		if (ufd->when & BSC_FD_WRITE) +			FD_SET(ufd->fd, &writeset); + +		if (ufd->when & BSC_FD_EXCEPT) +			FD_SET(ufd->fd, &exceptset); +	} + +	bsc_timer_check(); + +	if (!polling) +		bsc_prepare_timers(); +	rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : bsc_nearest_timer()); +	if (rc < 0) +		return 0; + +	/* fire timers */ +	bsc_update_timers(); + +	/* call registered callback functions */ +restart: +	unregistered_count = 0; +	llist_for_each_entry_safe(ufd, tmp, &bsc_fds, list) { +		int flags = 0; + +		if (FD_ISSET(ufd->fd, &readset)) { +			flags |= BSC_FD_READ; +			FD_CLR(ufd->fd, &readset); +		} + +		if (FD_ISSET(ufd->fd, &writeset)) { +			flags |= BSC_FD_WRITE; +			FD_CLR(ufd->fd, &writeset); +		} + +		if (FD_ISSET(ufd->fd, &exceptset)) { +			flags |= BSC_FD_EXCEPT; +			FD_CLR(ufd->fd, &exceptset); +		} + +		if (flags) { +			work = 1; +			ufd->cb(ufd, flags); +		} +		/* ugly, ugly hack. If more than one filedescriptors were +		 * unregistered, they might have been consecutive and +		 * llist_for_each_entry_safe() is no longer safe */ +		if (unregistered_count > 1) +			goto restart; +	} +	return work; +} + +#endif /* _HAVE_SYS_SELECT_H */ | 
