Module: xenomai-forge Branch: next Commit: 6410988c1ea883daaaa011ba021f295f564d9b40 URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=6410988c1ea883daaaa011ba021f295f564d9b40
Author: Philippe Gerum <r...@xenomai.org> Date: Sun Aug 4 16:28:53 2013 +0200 cobalt/posix/select: move implementation to dedicated file --- kernel/cobalt/posix/Makefile | 1 + kernel/cobalt/posix/select.c | 212 +++++++++++++++++++++++++++++++++++++++++ kernel/cobalt/posix/select.h | 31 ++++++ kernel/cobalt/posix/syscall.c | 192 +------------------------------------ 4 files changed, 246 insertions(+), 190 deletions(-) diff --git a/kernel/cobalt/posix/Makefile b/kernel/cobalt/posix/Makefile index 070bb90..d08442d 100644 --- a/kernel/cobalt/posix/Makefile +++ b/kernel/cobalt/posix/Makefile @@ -12,6 +12,7 @@ posix-y := \ mutex_attr.o \ registry.o \ sem.o \ + select.o \ signal.o \ syscall.o \ thread.o \ diff --git a/kernel/cobalt/posix/select.c b/kernel/cobalt/posix/select.c new file mode 100644 index 0000000..ff94f98 --- /dev/null +++ b/kernel/cobalt/posix/select.c @@ -0,0 +1,212 @@ +/** + * @file + * This file is part of the Xenomai project. + * + * Copyright (C) 2005 Philippe Gerum <r...@xenomai.org> + * Copyright (C) 2005 Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org> + * + * This program 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. + * + * 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 <linux/types.h> +#include <linux/err.h> +#include <rtdm/rtdm_driver.h> +#include "internal.h" +#include "clock.h" +#include "mqueue.h" +#include "select.h" + +#define RTDM_FD_MAX CONFIG_XENO_OPT_RTDM_FILDES + +static int fd_valid_p(int fd) +{ + const int rtdm_fd_start = __FD_SETSIZE - RTDM_FD_MAX; + struct rtdm_dev_context *ctx; + struct cobalt_process *cc; + + if (fd >= rtdm_fd_start) { + ctx = rtdm_context_get(fd - rtdm_fd_start); + if (ctx == NULL) + return 0; + rtdm_context_unlock(ctx); + return 1; + } + + cc = cobalt_process_context(); + if (cc == NULL) + return 0; + + return cobalt_assoc_lookup(&cc->uqds, fd) != NULL; +} + +static int first_fd_valid_p(fd_set *fds[XNSELECT_MAX_TYPES], int nfds) +{ + int i, fd; + + for (i = 0; i < XNSELECT_MAX_TYPES; i++) + if (fds[i] + && (fd = find_first_bit(fds[i]->fds_bits, nfds)) < nfds) + return fd_valid_p(fd); + + /* All empty is correct, used as a "sleep" mechanism by strange + applications. */ + return 1; +} + +static int select_bind_one(struct xnselector *selector, unsigned type, int fd) +{ + const int rtdm_fd_start = __FD_SETSIZE - RTDM_FD_MAX; + struct cobalt_process *cc; + cobalt_assoc_t *assoc; + + if (fd >= rtdm_fd_start) + return rtdm_select_bind(fd - rtdm_fd_start, + selector, type, fd); + + cc = cobalt_process_context(); + if (cc == NULL) + return -EPERM; + + assoc = cobalt_assoc_lookup(&cc->uqds, fd); + if (assoc == NULL) + return -EBADF; + + return cobalt_mq_select_bind(assoc2ufd(assoc)->kfd, selector, type, fd); +} + +static int select_bind_all(struct xnselector *selector, + fd_set *fds[XNSELECT_MAX_TYPES], int nfds) +{ + unsigned fd, type; + int err; + + for (type = 0; type < XNSELECT_MAX_TYPES; type++) { + fd_set *set = fds[type]; + if (set) + for (fd = find_first_bit(set->fds_bits, nfds); + fd < nfds; + fd = find_next_bit(set->fds_bits, nfds, fd + 1)) { + err = select_bind_one(selector, type, fd); + if (err) + return err; + } + } + + return 0; +} + +/* int select(int, fd_set *, fd_set *, fd_set *, struct timeval *) */ +int cobalt_select(int nfds, + fd_set __user *u_rfds, + fd_set __user *u_wfds, + fd_set __user *u_xfds, + struct timeval __user *u_tv) +{ + fd_set __user *ufd_sets[XNSELECT_MAX_TYPES] = { + [XNSELECT_READ] = u_rfds, + [XNSELECT_WRITE] = u_wfds, + [XNSELECT_EXCEPT] = u_xfds + }; + fd_set *in_fds[XNSELECT_MAX_TYPES] = {NULL, NULL, NULL}; + fd_set *out_fds[XNSELECT_MAX_TYPES] = {NULL, NULL, NULL}; + fd_set in_fds_storage[XNSELECT_MAX_TYPES], + out_fds_storage[XNSELECT_MAX_TYPES]; + xnticks_t timeout = XN_INFINITE; + xntmode_t mode = XN_RELATIVE; + struct xnselector *selector; + struct timeval tv; + xnthread_t *thread; + size_t fds_size; + int i, err; + + thread = xnsched_current_thread(); + if (!thread) + return -EPERM; + + if (u_tv) { + if (!access_wok(u_tv, sizeof(tv)) + || __xn_copy_from_user(&tv, u_tv, sizeof(tv))) + return -EFAULT; + + if (tv.tv_usec > 1000000) + return -EINVAL; + + timeout = clock_get_ticks(CLOCK_MONOTONIC) + tv2ns(&tv); + mode = XN_ABSOLUTE; + } + + fds_size = __FDELT__(nfds + __NFDBITS__ - 1) * sizeof(long); + + for (i = 0; i < XNSELECT_MAX_TYPES; i++) + if (ufd_sets[i]) { + in_fds[i] = &in_fds_storage[i]; + out_fds[i] = & out_fds_storage[i]; + if (!access_wok((void __user *) ufd_sets[i], + sizeof(fd_set)) + || __xn_copy_from_user(in_fds[i], + (void __user *) ufd_sets[i], + fds_size)) + return -EFAULT; + } + + selector = thread->selector; + if (!selector) { + /* This function may be called from pure Linux fd_sets, we want + to avoid the xnselector allocation in this case, so, we do a + simple test: test if the first file descriptor we find in the + fd_set is an RTDM descriptor or a message queue descriptor. */ + if (!first_fd_valid_p(in_fds, nfds)) + return -EBADF; + + selector = xnmalloc(sizeof(*thread->selector)); + if (selector == NULL) + return -ENOMEM; + xnselector_init(selector); + thread->selector = selector; + + /* Bind directly the file descriptors, we do not need to go + through xnselect returning -ECHRNG */ + if ((err = select_bind_all(selector, in_fds, nfds))) + return err; + } + + do { + err = xnselect(selector, out_fds, in_fds, nfds, timeout, mode); + + if (err == -ECHRNG) { + int err = select_bind_all(selector, out_fds, nfds); + if (err) + return err; + } + } while (err == -ECHRNG); + + if (u_tv && (err > 0 || err == -EINTR)) { + xnsticks_t diff = timeout - clock_get_ticks(CLOCK_MONOTONIC); + if (diff > 0) + ticks2tv(&tv, diff); + else + tv.tv_sec = tv.tv_usec = 0; + + if (__xn_copy_to_user(u_tv, &tv, sizeof(tv))) + return -EFAULT; + } + + if (err >= 0) + for (i = 0; i < XNSELECT_MAX_TYPES; i++) + if (ufd_sets[i] + && __xn_copy_to_user((void __user *) ufd_sets[i], + out_fds[i], sizeof(fd_set))) + return -EFAULT; + return err; +} diff --git a/kernel/cobalt/posix/select.h b/kernel/cobalt/posix/select.h new file mode 100644 index 0000000..0131ba9 --- /dev/null +++ b/kernel/cobalt/posix/select.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2013 Philippe Gerum <r...@xenomai.org> + * + * This program 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. + * + * 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. + */ + +#ifndef _COBALT_POSIX_SELECT_H +#define _COBALT_POSIX_SELECT_H + +#include <linux/types.h> +#include <linux/time.h> + +int cobalt_select(int nfds, + fd_set __user *u_rfds, + fd_set __user *u_wfds, + fd_set __user *u_xfds, + struct timeval __user *u_tv); + +#endif /* !_COBALT_POSIX_SELECT_H */ diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c index 5b96f9c..7123dee 100644 --- a/kernel/cobalt/posix/syscall.c +++ b/kernel/cobalt/posix/syscall.c @@ -37,198 +37,10 @@ #include "monitor.h" #include "clock.h" #include "event.h" - -#define RTDM_FD_MAX CONFIG_XENO_OPT_RTDM_FILDES +#include "select.h" int cobalt_muxid; -static int fd_valid_p(int fd) -{ - const int rtdm_fd_start = __FD_SETSIZE - RTDM_FD_MAX; - struct rtdm_dev_context *ctx; - struct cobalt_process *cc; - - if (fd >= rtdm_fd_start) { - ctx = rtdm_context_get(fd - rtdm_fd_start); - if (ctx == NULL) - return 0; - rtdm_context_unlock(ctx); - return 1; - } - - cc = cobalt_process_context(); - if (cc == NULL) - return 0; - - return cobalt_assoc_lookup(&cc->uqds, fd) != NULL; -} - -static int first_fd_valid_p(fd_set *fds[XNSELECT_MAX_TYPES], int nfds) -{ - int i, fd; - - for (i = 0; i < XNSELECT_MAX_TYPES; i++) - if (fds[i] - && (fd = find_first_bit(fds[i]->fds_bits, nfds)) < nfds) - return fd_valid_p(fd); - - /* All empty is correct, used as a "sleep" mechanism by strange - applications. */ - return 1; -} - -static int select_bind_one(struct xnselector *selector, unsigned type, int fd) -{ - const int rtdm_fd_start = __FD_SETSIZE - RTDM_FD_MAX; - struct cobalt_process *cc; - cobalt_assoc_t *assoc; - - if (fd >= rtdm_fd_start) - return rtdm_select_bind(fd - rtdm_fd_start, - selector, type, fd); - - cc = cobalt_process_context(); - if (cc == NULL) - return -EPERM; - - assoc = cobalt_assoc_lookup(&cc->uqds, fd); - if (assoc == NULL) - return -EBADF; - - return cobalt_mq_select_bind(assoc2ufd(assoc)->kfd, selector, type, fd); -} - -static int select_bind_all(struct xnselector *selector, - fd_set *fds[XNSELECT_MAX_TYPES], int nfds) -{ - unsigned fd, type; - int err; - - for (type = 0; type < XNSELECT_MAX_TYPES; type++) { - fd_set *set = fds[type]; - if (set) - for (fd = find_first_bit(set->fds_bits, nfds); - fd < nfds; - fd = find_next_bit(set->fds_bits, nfds, fd + 1)) { - err = select_bind_one(selector, type, fd); - if (err) - return err; - } - } - - return 0; -} - -/* int select(int, fd_set *, fd_set *, fd_set *, struct timeval *) */ -static int __select(int nfds, - fd_set __user *u_rfds, - fd_set __user *u_wfds, - fd_set __user *u_xfds, - struct timeval __user *u_tv) -{ - fd_set __user *ufd_sets[XNSELECT_MAX_TYPES] = { - [XNSELECT_READ] = u_rfds, - [XNSELECT_WRITE] = u_wfds, - [XNSELECT_EXCEPT] = u_xfds - }; - fd_set *in_fds[XNSELECT_MAX_TYPES] = {NULL, NULL, NULL}; - fd_set *out_fds[XNSELECT_MAX_TYPES] = {NULL, NULL, NULL}; - fd_set in_fds_storage[XNSELECT_MAX_TYPES], - out_fds_storage[XNSELECT_MAX_TYPES]; - xnticks_t timeout = XN_INFINITE; - xntmode_t mode = XN_RELATIVE; - struct xnselector *selector; - struct timeval tv; - xnthread_t *thread; - size_t fds_size; - int i, err; - - thread = xnsched_current_thread(); - if (!thread) - return -EPERM; - - if (u_tv) { - if (!access_wok(u_tv, sizeof(tv)) - || __xn_copy_from_user(&tv, u_tv, sizeof(tv))) - return -EFAULT; - - if (tv.tv_usec > 1000000) - return -EINVAL; - - timeout = clock_get_ticks(CLOCK_MONOTONIC) + tv2ns(&tv); - mode = XN_ABSOLUTE; - } - - fds_size = __FDELT__(nfds + __NFDBITS__ - 1) * sizeof(long); - - for (i = 0; i < XNSELECT_MAX_TYPES; i++) - if (ufd_sets[i]) { - in_fds[i] = &in_fds_storage[i]; - out_fds[i] = & out_fds_storage[i]; - if (!access_wok((void __user *) ufd_sets[i], - sizeof(fd_set)) - || __xn_copy_from_user(in_fds[i], - (void __user *) ufd_sets[i], - fds_size)) - return -EFAULT; - } - - selector = thread->selector; - if (!selector) { - /* This function may be called from pure Linux fd_sets, we want - to avoid the xnselector allocation in this case, so, we do a - simple test: test if the first file descriptor we find in the - fd_set is an RTDM descriptor or a message queue descriptor. */ - if (!first_fd_valid_p(in_fds, nfds)) - return -EBADF; - - selector = xnmalloc(sizeof(*thread->selector)); - if (selector == NULL) - return -ENOMEM; - xnselector_init(selector); - thread->selector = selector; - - /* Bind directly the file descriptors, we do not need to go - through xnselect returning -ECHRNG */ - if ((err = select_bind_all(selector, in_fds, nfds))) - return err; - } - - do { - err = xnselect(selector, out_fds, in_fds, nfds, timeout, mode); - - if (err == -ECHRNG) { - int err = select_bind_all(selector, out_fds, nfds); - if (err) - return err; - } - } while (err == -ECHRNG); - - if (u_tv && (err > 0 || err == -EINTR)) { - xnsticks_t diff = timeout - clock_get_ticks(CLOCK_MONOTONIC); - if (diff > 0) - ticks2tv(&tv, diff); - else - tv.tv_sec = tv.tv_usec = 0; - - if (__xn_copy_to_user(u_tv, &tv, sizeof(tv))) - return -EFAULT; - } - - if (err >= 0) - for (i = 0; i < XNSELECT_MAX_TYPES; i++) - if (ufd_sets[i] - && __xn_copy_to_user((void __user *) ufd_sets[i], - out_fds[i], sizeof(fd_set))) - return -EFAULT; - return err; -} - -int __cobalt_call_not_available(void) -{ - return -ENOSYS; -} - static struct xnshadow_ppd *cobalt_process_attach(void) { struct cobalt_process *cc; @@ -340,7 +152,7 @@ static struct xnsyscall cobalt_syscalls[] = { SKINCALL_DEF(sc_cobalt_condattr_setclock, cobalt_condattr_setclock, any), SKINCALL_DEF(sc_cobalt_condattr_getpshared, cobalt_condattr_getpshared, any), SKINCALL_DEF(sc_cobalt_condattr_setpshared, cobalt_condattr_setpshared, any), - SKINCALL_DEF(sc_cobalt_select, __select, primary), + SKINCALL_DEF(sc_cobalt_select, cobalt_select, primary), SKINCALL_DEF(sc_cobalt_sched_minprio, cobalt_sched_min_prio, any), SKINCALL_DEF(sc_cobalt_sched_maxprio, cobalt_sched_max_prio, any), SKINCALL_DEF(sc_cobalt_monitor_init, cobalt_monitor_init, any), _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org http://www.xenomai.org/mailman/listinfo/xenomai-git