This patch adds select-like services support to xenomai core. Changes: - the xnselect function now ignores null fd_sets, which makes it faster in the common case when several fd_sets are null; - the timeout is now passed to xnselect as an (xnticks_t, xntmode_t) couple, which avoids xnselect to suspend forever the caller when a computed timeout happens to be XN_INFINITE.
Stats: include/nucleus/select.h | 111 ++++++++++++ ksrc/nucleus/Makefile | 4 ksrc/nucleus/select.c | 412 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 525 insertions(+), 2 deletions(-) -- Gilles Chanteperdrix.
--- include/nucleus/select.h (revision 0) +++ include/nucleus/select.h (revision 0) @@ -0,0 +1,111 @@ +/*!\file select.h + * \brief file descriptors events multiplexing header. + * \author Gilles Chanteperdrix + * + * Copyright (C) 2008 Efixo <[EMAIL PROTECTED]> + * + * Xenomai is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * Xenomai 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 Xenomai; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * \ingroup select + */ + +#ifndef XNSELECT_H +#define XNSELECT_H + +/*! \addtogroup select + [EMAIL PROTECTED]/ + +#include <nucleus/thread.h> + +#define XNSELECT_READ 0 +#define XNSELECT_WRITE 1 +#define XNSELECT_EXCEPT 2 +#define XNSELECT_MAX_TYPES 3 + +struct xnselector { + xnsynch_t synchbase; + struct fds { + fd_set expected; + fd_set pending; + } fds [XNSELECT_MAX_TYPES]; + xnqueue_t bindings; /* only used by xnselector_destroy */ +}; + +struct xnselect { + xnqueue_t bindings; +}; + +struct xnselect_binding { + struct xnselector *selector; + struct xnselect *fd; + unsigned type; + unsigned bit_index; + xnholder_t link; /* link in selected fds list. */ + xnholder_t slink; /* link in selector list */ +}; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void xnselect_init(struct xnselect *select_block); + +int xnselect_bind(struct xnselect *select_block, + struct xnselect_binding *binding, + struct xnselector *selector, + unsigned type, + unsigned bit_index, + unsigned state); + +int __xnselect_signal(struct xnselect *select_block, unsigned state); + +/** + * Signal a file descriptor state change. + * + * @param select_block pointer to an @a xnselect structure representing the file + * descriptor whose state changed; + * @param state new value of the state. + * + * @retval 1 if rescheduling is needed; + * @retval 0 otherwise. + */ +static inline int +xnselect_signal(struct xnselect *select_block, unsigned state) +{ + if (!emptyq_p(&select_block->bindings)) + return __xnselect_signal(select_block, state); + return 0; +} + +void xnselect_destroy(struct xnselect *select_block); + +int xnselector_init(struct xnselector *selector); + +int xnselect(struct xnselector *selector, + fd_set *out_fds[XNSELECT_MAX_TYPES], + fd_set *in_fds[XNSELECT_MAX_TYPES], + int nfds, + xnticks_t timeout, xntmode_t timeout_mode); + +void xnselector_destroy(struct xnselector *selector); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/[EMAIL PROTECTED]/ + +#endif /* XNSELECT_H */ --- ksrc/nucleus/select.c (revision 0) +++ ksrc/nucleus/select.c (revision 0) @@ -0,0 +1,412 @@ +/*!\file select.c + * \brief file descriptors events multiplexing. + * \author Gilles Chanteperdrix + * + * Copyright (C) 2008 Efixo <[EMAIL PROTECTED]> + * + * Xenomai is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * Xenomai 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 Xenomai; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * \ingroup select + */ + +/*! + * \ingroup nucleus + * \defgroup select File descriptors events multiplexing services. + * + * File descriptors events multiplexing services. + * + * This module implements the services needed for implementing the posix + * "select" service, or any other events multiplexing services. + * + * Following the implementation of the posix select service, this module defines + * three types of events: + * - \a XNSELECT_READ meaning that a file descriptor is ready for reading; + * - \a XNSELECT_WRITE meaning that a file descriptor is ready for writing; + * - \a XNSELECT_EXCEPT meaning that a file descriptor received an exceptional + * event. + * + * It works by defining two structures: + * - a @a struct @a xnselect structure, which should be added to every file + * descriptor for every event type (read, write, or except); + * - a @a struct @a xnselector structure, the selection structure, passed by + * the thread calling the xnselect service, where this service does all its + * housekeeping. + [EMAIL PROTECTED]/ + +#include <nucleus/heap.h> +#include <nucleus/pod.h> +#include <nucleus/synch.h> +#include <nucleus/select.h> +#include <linux/types.h> +#include <linux/bitops.h> /* For hweight_long */ + +#define link2binding(baddr, memb) \ + container_of(baddr, struct xnselect_binding, memb) + +/** + * Initialize a @a struct @a xnselect structure. + * + * This service must be called to initialize a @a struct @a xnselect structure + * before it is bound to a selector by the means of xnselect_bind(). + * + * @param select_block pointer to the xnselect structure to be initialized + */ +void xnselect_init(struct xnselect *select_block) +{ + initq(&select_block->bindings); +} +EXPORT_SYMBOL(xnselect_init); + +static inline int xnselect_wakeup(struct xnselector *selector) +{ + return xnsynch_flush(&selector->synchbase, 0) == XNSYNCH_RESCHED; +} + +/** + * Bind a file descriptor (represented by its @a xnselect structure) to a + * selector block. + * + * @param select_block pointer to the @a struct @a xnselect to be bound; + * + * @param binding pointer to a newly allocated (using xnmalloc) @a struct + * @a xnselect_binding; + * + * @param selector pointer to the selector structure; + * + * @param type type of events (@a XNSELECT_READ, @a XNSELECT_WRITE, or @a + * XNSELECT_EXCEPT); + * + * @param index index of the file descriptor (represented by @a select_block) in the bit fields used by the @a selector structure; + * + * @param state current state of the file descriptor>. + * + * @a select_block must have been initialized with xnselect_init(), + * the @a xnselector structure must have been initialized with + * xnselector_init(), @a binding may be uninitialized. + * + * This service must be called with nklock locked, irqs off. For this reason, + * the @a binding parameter must have been allocated by the caller outside the + * locking section. + * + * @retval -EINVAL if @a type or @a index is invalid; + * @retval 0 otherwise. + */ +int xnselect_bind(struct xnselect *select_block, + struct xnselect_binding *binding, + struct xnselector *selector, + unsigned type, + unsigned index, + unsigned state) +{ + if (type >= XNSELECT_MAX_TYPES || index > __FD_SETSIZE) + return -EINVAL; + + binding->selector = selector; + binding->fd = select_block; + binding->type = type; + binding->bit_index = index; + inith(&binding->link); + inith(&binding->slink); + + appendq(&selector->bindings, &binding->slink); + appendq(&select_block->bindings, &binding->link); + __FD_SET(index, &selector->fds[type].expected); + if (state) + __FD_SET(index, &selector->fds[type].pending); + + return 0; +} +EXPORT_SYMBOL(xnselect_bind); + +/* Must be called with nklock locked irqs off */ +int __xnselect_signal(struct xnselect *select_block, unsigned state) +{ + xnholder_t *holder; + int resched; + + for(resched = 0, holder = getheadq(&select_block->bindings); + holder; holder = nextq(&select_block->bindings, holder)) { + struct xnselect_binding *binding; + struct xnselector *selector; + + binding = link2binding(holder, link); + + selector = binding->selector; + if (state) { + if (!__FD_ISSET(binding->bit_index, + &selector->fds[binding->type].pending)) { + __FD_SET(binding->bit_index, + &selector->fds[binding->type].pending); + if (xnselect_wakeup(selector)) + resched = 1; + } + } else + __FD_CLR(binding->bit_index, + &selector->fds[binding->type].pending); + } + + return resched; +} +EXPORT_SYMBOL(__xnselect_signal); + +/** + * Destroy the @a xnselect structure associated with a file descriptor. + * + * Any binding with a @a xnselector block is destroyed. + * + * @param select_block pointer to the @a xnselect structure associated with a file descriptor + */ +void xnselect_destroy(struct xnselect *select_block) +{ + xnholder_t *holder; + spl_t s; + + xnlock_get_irqsave(&nklock, s); + while ((holder = getq(&select_block->bindings))) { + struct xnselect_binding *binding; + struct xnselector *selector; + + binding = link2binding(holder, link); + selector = binding->selector; + + __FD_CLR(binding->bit_index, + &selector->fds[binding->type].expected); + __FD_CLR(binding->bit_index, + &selector->fds[binding->type].pending); + removeq(&selector->bindings, &binding->slink); + xnlock_put_irqrestore(&nklock, s); + + xnfree(binding); + + xnlock_get_irqsave(&nklock, s); + } + xnlock_put_irqrestore(&nklock, s); +} +EXPORT_SYMBOL(xnselect_destroy); + +static unsigned +fd_set_andnot(fd_set *result, fd_set *first, fd_set *second, unsigned n) +{ + unsigned i, not_empty = 0; + + for (i = 0; i < __FDELT(n); i++) + if((result->fds_bits[i] = + first->fds_bits[i] & ~(second->fds_bits[i]))) + not_empty = 1; + + if (i < __FDSET_LONGS + && (result->fds_bits[i] = + first->fds_bits[i] & ~(second->fds_bits[i]) & (__FDMASK(n) - 1))) + not_empty = 1; + + return not_empty; +} + +static unsigned +fd_set_and(fd_set *result, fd_set *first, fd_set *second, unsigned n) +{ + unsigned i, not_empty = 0; + + for (i = 0; i < __FDELT(n); i++) + if((result->fds_bits[i] = + first->fds_bits[i] & second->fds_bits[i])) + not_empty = 1; + + if (i < __FDSET_LONGS + && (result->fds_bits[i] = + first->fds_bits[i] & second->fds_bits[i] & (__FDMASK(n) - 1))) + not_empty = 1; + + return not_empty; +} + +static void fd_set_zerofill(fd_set *set, unsigned n) +{ + unsigned i; + + i = __FDELT(n); + + if (i < __FDSET_LONGS) + set->fds_bits[i] &= (__FDMASK(n) - 1); + + for(i++; i < __FDSET_LONGS; i++) + set->fds_bits[i] = 0; +} + +static unsigned fd_set_popcount(fd_set *set, unsigned n) +{ + unsigned count = 0, i; + + for (i = 0; i < __FDELT(n); i++) + if (set->fds_bits[i]) + count += hweight_long(set->fds_bits[i]); + + if (i < __FDSET_LONGS && (set->fds_bits[i] & (__FDMASK(n) - 1))) + count += hweight_long(set->fds_bits[i] & (__FDMASK(n) - 1)); + + return count; +} + +/** + * Initialize a selector structure. + * + * @param selector The selector structure to be initialized. + * + * @retval 0 + */ +int xnselector_init(struct xnselector *selector) +{ + unsigned i; + + xnsynch_init(&selector->synchbase, XNSYNCH_FIFO | XNSYNCH_NOPIP); + for (i = 0; i < XNSELECT_MAX_TYPES; i++) { + __FD_ZERO(&selector->fds[i].expected); + __FD_ZERO(&selector->fds[i].pending); + } + initq(&selector->bindings); + return 0; +} +EXPORT_SYMBOL(xnselector_init); + +/** + * Check the state of a number of file descriptors, wait for a state change if + * no descriptor is ready. + * + * @param selector structure to check for pending events + * @param out_fds The set of descriptors with pending events if a strictly positive number is returned, or the set of descriptors not yet bound if -ECHRNG is returned; + * @param in_fds the set of descriptors which events should be checked + * @param nfds the highest-numbered descriptor in any of the @a in_fds sets, plus 1; + * @param timeout the timeout, whose meaning depends on @a timeout_mode, note + * that xnselect() pass @a timeout and @a timeout_mode unchanged to + * xnsynch_sleep_on, so passing a relative value different from XN_INFINITE as a + * timeout with @a timeout_mode set to XN_RELATIVE, will cause a longer sleep + * than expected if the sleep is interrupted. + * @param timeout_mode the mode of @a timeout. + * + * @retval -EINVAL if @nfds is negative; + * @retval -ECHRNG if some of the descriptors passed in @a in_fds have not yet + * been registered with xnselect_bind(), @a out_fds contains the set of such + * descriptors; + * @retval -EINTR if @a xnselect was interrupted while waiting; + * @retval 0 in case of timeout. + * @retval the number of file descriptors having received an event. + */ +int xnselect(struct xnselector *selector, + fd_set *out_fds[XNSELECT_MAX_TYPES], + fd_set *in_fds[XNSELECT_MAX_TYPES], + int nfds, + xnticks_t timeout, xntmode_t timeout_mode) +{ + unsigned i, not_empty = 0; + xnthread_t *thread; + spl_t s; + + if ((unsigned) nfds > __FD_SETSIZE) + return -EINVAL; + + thread = xnpod_current_thread(); + + xnlock_get_irqsave(&nklock, s); + for (i = 0; i < XNSELECT_MAX_TYPES; i++) + if (out_fds[i] + && fd_set_andnot(out_fds[i], in_fds[i], + &selector->fds[i].expected, nfds)) + not_empty = 1; + xnlock_put_irqrestore(&nklock, s); + + if (not_empty) { + for (i = 0; i < XNSELECT_MAX_TYPES; i++) + if (out_fds[i]) + fd_set_zerofill(out_fds[i], nfds); + return -ECHRNG; + } + + xnlock_get_irqsave(&nklock, s); + for (i = 0; i < XNSELECT_MAX_TYPES; i++) + if (out_fds[i] + && fd_set_and(out_fds[i], in_fds[i], + &selector->fds[i].pending, nfds)) + not_empty = 1; + + while (!not_empty) { + xnsynch_sleep_on(&selector->synchbase, timeout, timeout_mode); + + for (i = 0; i < XNSELECT_MAX_TYPES; i++) + if (out_fds[i] + && fd_set_and(out_fds[i], in_fds[i], + &selector->fds[i].pending, nfds)) + not_empty = 1; + + if (xnthread_test_info(thread, XNBREAK | XNTIMEO)) + break; + } + xnlock_put_irqrestore(&nklock, s); + + if (not_empty) { + unsigned count; + + for (i = 0; i < XNSELECT_MAX_TYPES; i++) + if (out_fds[i]) + fd_set_zerofill(out_fds[i], nfds); + + for (count = 0, i = 0; i < XNSELECT_MAX_TYPES; i++) + if (out_fds[i]) + count += fd_set_popcount(out_fds[i], nfds); + + return count; + } + + if (xnthread_test_info(thread, XNBREAK)) + return -EINTR; + + return 0; /* Timeout */ +} +EXPORT_SYMBOL(xnselect); + +/** + * Destroy a selector block. + * + * All bindings with file descriptor are destroyed. + * + * @param selector the selector block to be destroyed + */ +void xnselector_destroy(struct xnselector *selector) +{ + xnholder_t *holder; + spl_t s; + + xnlock_get_irqsave(&nklock, s); + while ((holder = getq(&selector->bindings))) { + struct xnselect_binding *binding; + struct xnselect *fd; + + binding = link2binding(holder, slink); + fd = binding->fd; + removeq(&fd->bindings, &binding->link); + xnlock_put_irqrestore(&nklock, s); + + xnfree(binding); + + xnlock_get_irqsave(&nklock, s); + } + xnlock_put_irqrestore(&nklock, s); + + if (xnsynch_destroy(&selector->synchbase) == XNSYNCH_RESCHED) + xnpod_schedule(); +} +EXPORT_SYMBOL(xnselector_destroy); + +/[EMAIL PROTECTED]/ --- ksrc/nucleus/Makefile (revision 3455) +++ ksrc/nucleus/Makefile (working copy) @@ -4,7 +4,7 @@ ifeq ($(PATCHLEVEL),6) obj-$(CONFIG_XENO_OPT_NUCLEUS) += xeno_nucleus.o -xeno_nucleus-y := heap.o intr.o module.o pod.o synch.o thread.o timebase.o timer.o +xeno_nucleus-y := heap.o intr.o module.o pod.o synch.o thread.o timebase.o timer.o select.o xeno_nucleus-$(CONFIG_XENO_OPT_PERVASIVE) += shadow.o @@ -26,7 +26,7 @@ obj-$(CONFIG_XENO_OPT_NUCLEUS) := xeno_n list-multi := xeno_nucleus.o -xeno_nucleus-objs := heap.o intr.o module.o pod.o synch.o thread.o timebase.o timer.o +xeno_nucleus-objs := heap.o intr.o module.o pod.o synch.o thread.o timebase.o timer.o select.o opt_objs-y := opt_objs-$(CONFIG_XENO_OPT_PERVASIVE) += shadow.o
_______________________________________________ Xenomai-core mailing list Xenomai-core@gna.org https://mail.gna.org/listinfo/xenomai-core