Module: xenomai-gch
Branch: for-forge
Commit: 0c2d552f45d3b1a5688129f515c489d04b9881e8
URL:    
http://git.xenomai.org/?p=xenomai-gch.git;a=commit;h=0c2d552f45d3b1a5688129f515c489d04b9881e8

Author: Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org>
Date:   Mon Dec 23 21:03:04 2013 +0100

cobalt/fd: add common fd implementation

---

 include/cobalt/kernel/fd.h    |  186 ++++++++++++++
 include/cobalt/kernel/ppd.h   |    3 +-
 include/cobalt/uapi/syscall.h |    6 +
 kernel/cobalt/Makefile        |    1 +
 kernel/cobalt/fd.c            |  533 +++++++++++++++++++++++++++++++++++++++++
 kernel/cobalt/init.c          |    3 +
 kernel/cobalt/posix/Makefile  |    1 +
 kernel/cobalt/posix/fdio.c    |   74 ++++++
 kernel/cobalt/posix/fdio.h    |   35 +++
 kernel/cobalt/posix/select.c  |    9 +
 kernel/cobalt/posix/syscall.c |    7 +
 kernel/cobalt/shadow.c        |    3 +
 lib/cobalt/rtdm.c             |   57 ++++-
 13 files changed, 907 insertions(+), 11 deletions(-)

diff --git a/include/cobalt/kernel/fd.h b/include/cobalt/kernel/fd.h
new file mode 100644
index 0000000..c2282d3
--- /dev/null
+++ b/include/cobalt/kernel/fd.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2005-2007 Jan Kiszka <jan.kis...@web.de>
+ * Copyright (C) 2005 Joerg Langenberg <joerg.langenb...@gmx.net>
+ * Copyright (C) 2008,2013,2014 Gilles Chanteperdrix <g...@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_KERNEL_FD_H
+#define _COBALT_KERNEL_FD_H
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <cobalt/kernel/tree.h>
+
+struct xnfd;
+struct xnselector;
+struct xnsys_ppd;
+
+/**
+ * IOCTL handler
+ *
+ * @param[in] fd File descriptor structure associated with opened device 
instance
+ * @param[in] request Request number as passed by the user
+ * @param[in,out] arg Request argument as passed by the user
+ *
+ * @return A positive value or 0 on success. On failure return either
+ * -ENOSYS, to request that the function be called again from the opposite
+ * realtime/non-realtime context, or another negative error code.
+ *
+ * @see @c ioctl() in IEEE Std 1003.1,
+ * http://www.opengroup.org/onlinepubs/009695399 
+ */
+typedef int xnfd_ioctl_t(struct xnfd *fd, unsigned int request, void __user 
*arg);
+
+/**
+ * Read handler
+ *
+ * @param[in] fd File descriptor structure associated with opened device 
instance
+ * @param[out] buf Input buffer as passed by the user
+ * @param[in] size Number of bytes the user requests to read
+ *
+ * @return On success, the number of bytes read. On failure return either
+ * -ENOSYS, to request that this handler be called again from the opposite
+ * realtime/non-realtime context, or another negative error code.
+ *
+ * @see @c read() in IEEE Std 1003.1,
+ * http://www.opengroup.org/onlinepubs/009695399 
+ */
+typedef ssize_t xnfd_read_t(struct xnfd *fd, void __user *buf, size_t size);
+
+/**
+ * Write handler
+ *
+ * @param[in] fd File descriptor structure associated with opened device 
instance
+ * @param[in] buf Output buffer as passed by the user
+ * @param[in] size Number of bytes the user requests to write
+ *
+ * @return On success, the number of bytes written. On failure return
+ * either -ENOSYS, to request that this handler be called again from the
+ * opposite realtime/non-realtime context, or another negative error code.
+ *
+ * @see @c write() in IEEE Std 1003.1,
+ * http://www.opengroup.org/onlinepubs/009695399 
+ */
+typedef ssize_t xnfd_write_t(struct xnfd *fd, const void __user *buf, size_t 
size);
+
+/**
+ * Receive message handler
+ *
+ * @param[in] fd File descriptor structure associated with opened device 
instance
+ * @param[in,out] msg Message descriptor as passed by the user, automatically
+ * mirrored to safe kernel memory in case of user mode call
+ * @param[in] flags Message flags as passed by the user
+ *
+ * @return On success, the number of bytes received. On failure return
+ * either -ENOSYS, to request that this handler be called again from the
+ * opposite realtime/non-realtime context, or another negative error code.
+ *
+ * @see @c recvmsg() in IEEE Std 1003.1,
+ * http://www.opengroup.org/onlinepubs/009695399 
+ */
+typedef ssize_t xnfd_recvmsg_t(struct xnfd *fd, struct msghdr *msg, int flags);
+
+/**
+ * Transmit message handler
+ *
+ * @param[in] fd File descriptor structure associated with opened device 
instance
+ * @param[in] user_info Opaque pointer to information about user mode caller,
+ * NULL if kernel mode call
+ * @param[in] msg Message descriptor as passed by the user, automatically
+ * mirrored to safe kernel memory in case of user mode call
+ * @param[in] flags Message flags as passed by the user
+ *
+ * @return On success, the number of bytes transmitted. On failure return
+ * either -ENOSYS, to request that this handler be called again from the
+ * opposite realtime/non-realtime context, or another negative error code.
+ *
+ * @see @c sendmsg() in IEEE Std 1003.1,
+ * http://www.opengroup.org/onlinepubs/009695399 
+ */
+typedef ssize_t xnfd_sendmsg_t(struct xnfd *fd, const struct msghdr *msg, int 
flags);
+
+struct xnfd_ops {
+       xnfd_ioctl_t *ioctl_rt;
+       xnfd_ioctl_t *ioctl_nrt;
+       xnfd_read_t *read_rt;
+       xnfd_read_t *read_nrt;
+       xnfd_write_t *write_rt;
+       xnfd_write_t *write_nrt;
+       xnfd_recvmsg_t *recvmsg_rt;
+       xnfd_recvmsg_t *recvmsg_nrt;
+       xnfd_sendmsg_t *sendmsg_rt;
+       xnfd_sendmsg_t *sendmsg_nrt;
+       int (*select_bind)(struct xnfd *fd, struct xnselector *selector,
+                       unsigned type, unsigned index);
+       void (*close)(struct xnfd *fd);
+};
+
+struct xnfd {
+       unsigned magic;
+       struct xnfd_ops *ops;
+       struct xnsys_ppd *cont;
+       unsigned refs;
+       struct list_head cleanup;
+};
+
+struct xnfd_index {
+       struct xnid id;
+       struct xnfd *fd;
+};     
+
+#define XNFD_MAGIC_ANY 0
+
+static inline struct xnsys_ppd *xnfd_owner(struct xnfd *fd)
+{
+       return fd->cont;
+}
+
+int xnfd_enter(struct xnsys_ppd *p, struct xnfd *xnfd, int ufd, 
+       unsigned magic, struct xnfd_ops *ops);
+
+struct xnfd *xnfd_get(struct xnsys_ppd *p, int ufd, unsigned magic);
+
+int xnfd_lock(struct xnfd *fd);
+
+void xnfd_put(struct xnfd *fd);
+
+void xnfd_unlock(struct xnfd *fd);
+
+int xnfd_ioctl(struct xnsys_ppd *p, int fd, unsigned request, ...);
+
+ssize_t xnfd_read(struct xnsys_ppd *p, int fd, void __user *buf, size_t size);
+
+ssize_t 
+xnfd_write(struct xnsys_ppd *p, int fd, const void __user *buf, size_t size);
+
+int xnfd_close(struct xnsys_ppd *p, int fd, unsigned magic);
+
+ssize_t 
+xnfd_recvmsg(struct xnsys_ppd *p, int fd, struct msghdr *msg, int flags);
+
+ssize_t 
+xnfd_sendmsg(struct xnsys_ppd *p, int fd, const struct msghdr *msg, int flags);
+
+int xnfd_valid_p(int ufd);
+
+int xnfd_select_bind(int ufd, struct xnselector *selector, unsigned type);
+
+void xnfd_cleanup(struct xnsys_ppd *p);
+
+void xnfd_init(void);
+
+#endif /* _COBALT_KERNEL_FD_H */
diff --git a/include/cobalt/kernel/ppd.h b/include/cobalt/kernel/ppd.h
index 4ddd045..c869421 100644
--- a/include/cobalt/kernel/ppd.h
+++ b/include/cobalt/kernel/ppd.h
@@ -25,10 +25,10 @@
 #include <cobalt/kernel/shadow.h>
 #include <cobalt/kernel/lock.h>
 #include <cobalt/kernel/heap.h>
+#include <cobalt/kernel/fd.h>
 
 #define NR_PERSONALITIES  4
 
-/* Called with nklock locked irqs off. */
 void *xnshadow_private_get(unsigned int muxid);
 
 struct xnsys_ppd {
@@ -36,6 +36,7 @@ struct xnsys_ppd {
        unsigned long mayday_addr;
        atomic_t refcnt;
        char *exe_path;
+       struct rb_root fds;
 };
 
 struct xnshadow_process {
diff --git a/include/cobalt/uapi/syscall.h b/include/cobalt/uapi/syscall.h
index d536c89..c67c0cf 100644
--- a/include/cobalt/uapi/syscall.h
+++ b/include/cobalt/uapi/syscall.h
@@ -113,5 +113,11 @@
 #define sc_cobalt_event_destroy         92
 #define sc_cobalt_sched_setconfig_np   93
 #define sc_cobalt_sched_getconfig_np   94
+#define sc_cobalt_ioctl                        95
+#define sc_cobalt_read                 96
+#define sc_cobalt_write                        97
+#define sc_cobalt_recvmsg              98
+#define sc_cobalt_sendmsg              99
+#define sc_cobalt_close                        100
 
 #endif /* !_COBALT_UAPI_SYSCALL_H */
diff --git a/kernel/cobalt/Makefile b/kernel/cobalt/Makefile
index af4c2e0..2dfda25 100644
--- a/kernel/cobalt/Makefile
+++ b/kernel/cobalt/Makefile
@@ -5,6 +5,7 @@ xenomai-y :=    apc.o           \
                assert.o        \
                bufd.o          \
                clock.o         \
+               fd.o            \
                heap.o          \
                init.o          \
                intr.o          \
diff --git a/kernel/cobalt/fd.c b/kernel/cobalt/fd.c
new file mode 100644
index 0000000..cf59ab7
--- /dev/null
+++ b/kernel/cobalt/fd.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) 2005 Jan Kiszka <jan.kis...@web.de>
+ * Copyright (C) 2005 Joerg Langenberg <joerg.langenb...@gmx.net>
+ * Copyright (C) 2013,2014 Gilles Chanteperdrix <g...@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/list.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/kthread.h>
+#include <cobalt/kernel/registry.h>
+#include <cobalt/kernel/lock.h>
+#include <cobalt/kernel/fd.h>
+#include <cobalt/kernel/ppd.h>
+
+static DEFINE_XNLOCK(__xnfd_lock);
+static LIST_HEAD(xnfd_cleanup_queue);
+static struct semaphore xnfd_cleanup_sem;
+
+extern int 
+__rt_dev_ioctl_fallback(struct xnfd *fd, unsigned request, void __user *arg);
+extern void __rt_dev_unref(struct xnfd *fd, unsigned idx);
+
+static int enosys(void)
+{
+       return -ENOSYS;
+}
+
+static int ebadf(void)
+{
+       return -EBADF;
+}
+
+static void nop_close(struct xnfd *fd)
+{
+}
+
+static inline struct xnfd_index *xnfd_index_fetch(struct xnsys_ppd *p, int ufd)
+{
+       struct xnid *id = xnid_fetch(&p->fds, ufd);
+       if (id == NULL)
+               return NULL;
+
+       return container_of(id, struct xnfd_index, id);
+}
+
+static struct xnfd *xnfd_fetch(struct xnsys_ppd *p, int ufd)
+{
+       struct xnfd_index *idx = xnfd_index_fetch(p, ufd);
+       if (idx == NULL)
+               return NULL;
+
+       return idx->fd;
+}
+
+int xnfd_enter(struct xnsys_ppd *p, struct xnfd *fd, int ufd, 
+       unsigned magic, struct xnfd_ops *ops)
+{
+       struct xnfd_index *idx;
+       spl_t s;
+       int err;
+       
+       if (magic == XNFD_MAGIC_ANY) {
+               err = -EINVAL;
+               goto err;
+       }
+
+       idx = kmalloc(sizeof(*idx), GFP_KERNEL);
+       if (idx == NULL) {
+               err = -ENOMEM;
+               goto err;
+       }
+
+       if (ops->ioctl_rt == NULL && ops->ioctl_nrt == NULL)
+               ops->ioctl_rt = ops->ioctl_nrt = (xnfd_ioctl_t *)ebadf;
+       else {
+               if (ops->ioctl_rt == NULL)
+                       ops->ioctl_rt = (xnfd_ioctl_t *)enosys;
+               if (ops->ioctl_nrt == NULL)
+                       ops->ioctl_nrt = (xnfd_ioctl_t *)enosys;
+       }
+
+       if (ops->read_rt == NULL && ops->read_nrt == NULL)
+               ops->read_rt = ops->read_nrt = (xnfd_read_t *)ebadf;
+       else {
+               if (ops->read_rt == NULL)
+                       ops->read_rt = (xnfd_read_t *)enosys;
+               if (ops->read_nrt == NULL)
+                       ops->read_nrt = (xnfd_read_t *)enosys;
+       }
+
+       if (ops->write_rt == NULL && ops->write_nrt == NULL)
+               ops->write_rt = ops->write_nrt = (xnfd_write_t *)ebadf;
+       else {
+               if (ops->write_rt == NULL)
+                       ops->write_rt = (xnfd_write_t *)enosys;
+               if (ops->write_nrt == NULL)
+                       ops->write_nrt = (xnfd_write_t *)enosys;
+       }
+
+       if (ops->recvmsg_rt == NULL && ops->recvmsg_nrt == NULL)
+               ops->recvmsg_rt = ops->recvmsg_nrt = (xnfd_recvmsg_t *)ebadf;
+       else {
+               if (ops->recvmsg_rt == NULL)
+                       ops->recvmsg_rt = (xnfd_recvmsg_t *)enosys;
+               if (ops->recvmsg_nrt == NULL)
+                       ops->recvmsg_nrt = (xnfd_recvmsg_t *)enosys;
+       }
+
+       if (ops->sendmsg_rt == NULL && ops->sendmsg_nrt == NULL)
+               ops->sendmsg_rt = ops->sendmsg_nrt = (xnfd_sendmsg_t *)ebadf;
+       else {
+               if (ops->sendmsg_rt == NULL)
+                       ops->sendmsg_rt = (xnfd_sendmsg_t *)enosys;
+               if (ops->sendmsg_nrt == NULL)
+                       ops->sendmsg_nrt = (xnfd_sendmsg_t *)enosys;
+       }
+
+       if (ops->select_bind == NULL)
+               ops->select_bind = (typeof(ops->select_bind))ebadf;
+
+       if (ops->close == NULL)
+               ops->close = nop_close;
+
+       fd->magic = magic;
+       fd->ops = ops;
+       fd->cont = p;
+       fd->refs = 1;
+
+       idx->fd = fd;
+
+       xnlock_get_irqsave(&__xnfd_lock, s);
+       err = xnid_enter(&p->fds, &idx->id, ufd);
+       if (err < 0) {
+               xnlock_put_irqrestore(&__xnfd_lock, s);
+               err = -EBUSY;
+               goto err_free_index;
+       }
+       xnlock_put_irqrestore(&__xnfd_lock, s);
+       
+       return 0;
+
+  err_free_index:
+       kfree(idx);
+  err:
+       if (ops->close)
+               ops->close(fd);
+       return err;
+}
+
+struct xnfd *xnfd_get(struct xnsys_ppd *p, int ufd, unsigned magic)
+{
+       struct xnfd *res;
+       spl_t s;
+       
+       xnlock_get_irqsave(&__xnfd_lock, s);
+       res = xnfd_fetch(p, ufd);
+       if (res == NULL || (magic != XNFD_MAGIC_ANY && res->magic != magic)) {
+               res = ERR_PTR(-EBADF);
+               goto err_unlock;
+       }
+       
+       ++res->refs;
+  err_unlock:
+       xnlock_put_irqrestore(&__xnfd_lock, s);
+       
+       return res;
+}
+EXPORT_SYMBOL_GPL(xnfd_get);
+
+struct lostage_trigger_close {
+       struct ipipe_work_header work; /* Must be first */
+};
+
+static void xnfd_do_close(struct xnfd *fd)
+{
+       fd->ops->close(fd);
+
+       if (!XENO_ASSERT(NUCLEUS, !spltest()))
+               splnone();
+}
+
+static int xnfd_cleanup_thread(void *data)
+{
+       struct xnfd *fd;
+       int err;
+       spl_t s;
+       
+       for (;;) {
+               set_cpus_allowed_ptr(current, cpu_online_mask);
+
+               do {
+                       err = down_killable(&xnfd_cleanup_sem);
+               } while (err && !kthread_should_stop());
+
+               if (kthread_should_stop())
+                       break;
+
+               xnlock_get_irqsave(&__xnfd_lock, s);
+               fd = list_first_entry(&xnfd_cleanup_queue, 
+                               struct xnfd, cleanup);
+               list_del(&fd->cleanup);
+               xnlock_put_irqrestore(&__xnfd_lock, s);
+
+               xnfd_do_close(fd);
+       }
+
+       return 0;
+}
+
+static void lostage_trigger_close(struct ipipe_work_header *work)
+{
+       up(&xnfd_cleanup_sem);
+}
+
+static void xnfd_put_inner(struct xnfd *fd, spl_t s)
+{
+       int destroy;
+
+       destroy = --fd->refs == 0;
+       xnlock_put_irqrestore(&__xnfd_lock, s);
+       
+       if (!destroy)
+               return;
+       
+       if (ipipe_root_p)
+               xnfd_do_close(fd);
+       else {
+               struct lostage_trigger_close closework = {
+                       .work = {
+                               .size = sizeof(closework),
+                               .handler = lostage_trigger_close,
+                       },
+               };
+               
+               xnlock_get_irqsave(&__xnfd_lock, s);
+               list_add_tail(&fd->cleanup, &xnfd_cleanup_queue);
+               xnlock_put_irqrestore(&__xnfd_lock, s);
+
+               ipipe_post_work_root(&closework, work);
+       }
+}
+
+void xnfd_put(struct xnfd *fd)
+{
+       spl_t s;
+       
+       xnlock_get_irqsave(&__xnfd_lock, s);
+       xnfd_put_inner(fd, s);
+}
+EXPORT_SYMBOL_GPL(xnfd_put);
+
+int xnfd_lock(struct xnfd *fd)
+{
+       spl_t s;
+
+       xnlock_get_irqsave(&__xnfd_lock, s);
+       if (fd->refs == 0) {
+               xnlock_put_irqrestore(&__xnfd_lock, s);
+               return -EIDRM;
+       }
+       ++fd->refs;
+       xnlock_put_irqrestore(&__xnfd_lock, s);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xnfd_lock);
+
+void xnfd_unlock(struct xnfd *fd)
+{
+       spl_t s;
+
+       xnlock_get_irqsave(&__xnfd_lock, s);
+/* just warn if context was a dangling pointer */
+       XENO_ASSERT(NUCLEUS, fd->refs > 0);
+       xnfd_put_inner(fd, s);
+}
+EXPORT_SYMBOL_GPL(xnfd_unlock);
+
+int xnfd_ioctl(struct xnsys_ppd *p, int ufd, unsigned request, ...)
+{
+       void __user *arg;
+       struct xnfd *fd;
+       va_list args;
+       int err;
+
+       va_start(args, request);
+       arg = va_arg(args, void __user *);
+       va_end(args);
+
+       trace_mark(xn_rtdm, ioctl, "sys_ppd %p fd %d request %d arg %p",
+                  p, ufd, request, arg);
+       
+       fd = xnfd_get(p, ufd, XNFD_MAGIC_ANY);
+       if (IS_ERR(fd))
+               return PTR_ERR(fd);
+       
+       if (ipipe_root_p)
+               err = fd->ops->ioctl_nrt(fd, request, arg);
+       else
+               err = fd->ops->ioctl_rt(fd, request, arg);
+       
+       if (!XENO_ASSERT(NUCLEUS, !spltest()))
+                   splnone();
+
+       if (err < 0) {
+               int ret = __rt_dev_ioctl_fallback(fd, request, arg);
+               if (ret != -ENOSYS)
+                       err = ret;
+       }
+
+       xnfd_put(fd);
+       
+       return err;
+}
+EXPORT_SYMBOL_GPL(xnfd_ioctl);
+
+ssize_t xnfd_read(struct xnsys_ppd *p, int ufd, void __user *buf, size_t size)
+{
+       struct xnfd *fd;
+       ssize_t err;
+       
+       trace_mark(xn_rtdm, read, "sys_ppd %p fd %d buf %p nbyte %zu",
+                  p, ufd, buf, size);
+
+       fd = xnfd_get(p, ufd, XNFD_MAGIC_ANY);
+       if (IS_ERR(fd))
+               return PTR_ERR(fd);
+       
+       if (ipipe_root_p)
+               err = fd->ops->read_nrt(fd, buf, size);
+       else
+               err = fd->ops->read_rt(fd, buf, size);
+       
+       if (!XENO_ASSERT(NUCLEUS, !spltest()))
+                   splnone();
+
+       xnfd_put(fd);
+       
+       return err;
+}
+EXPORT_SYMBOL_GPL(xnfd_read);
+
+ssize_t xnfd_write(struct xnsys_ppd *p, int ufd,
+               const void __user *buf, size_t size)
+{
+       struct xnfd *fd;
+       ssize_t err;
+       
+       trace_mark(xn_rtdm, write, "sys_ppd %p fd %d buf %p nbyte %zu",
+                  p, ufd, buf, size);
+
+       fd = xnfd_get(p, ufd, XNFD_MAGIC_ANY);
+       if (IS_ERR(fd))
+               return PTR_ERR(fd);
+       
+       if (ipipe_root_p)
+               err = fd->ops->write_nrt(fd, buf, size);
+       else
+               err = fd->ops->write_rt(fd, buf, size);
+       
+       if (!XENO_ASSERT(NUCLEUS, !spltest()))
+                   splnone();
+
+       xnfd_put(fd);
+       
+       return err;
+}
+EXPORT_SYMBOL_GPL(xnfd_write);
+
+ssize_t 
+xnfd_recvmsg(struct xnsys_ppd *p, int ufd, struct msghdr *msg, int flags)
+{
+       struct xnfd *fd;
+       ssize_t err;
+       
+       trace_mark(xn_rtdm, recvmsg, "sys_ppd %p fd %d msg_name %p "
+                  "msg_namelen %u msg_iov %p msg_iovlen %zu "
+                  "msg_control %p msg_controllen %zu msg_flags %d",
+                  p, ufd, msg->msg_name, msg->msg_namelen,
+                  msg->msg_iov, msg->msg_iovlen, msg->msg_control,
+                  msg->msg_controllen, msg->msg_flags);
+
+       fd = xnfd_get(p, ufd, XNFD_MAGIC_ANY);
+       if (IS_ERR(fd))
+               return PTR_ERR(fd);
+       
+       if (ipipe_root_p)
+               err = fd->ops->recvmsg_nrt(fd, msg, flags);
+       else
+               err = fd->ops->recvmsg_rt(fd, msg, flags);
+       
+       if (!XENO_ASSERT(NUCLEUS, !spltest()))
+                   splnone();
+
+       xnfd_put(fd);
+       
+       return err;
+}
+EXPORT_SYMBOL_GPL(xnfd_recvmsg);
+
+ssize_t 
+xnfd_sendmsg(struct xnsys_ppd *p, int ufd, const struct msghdr *msg, int flags)
+{
+       struct xnfd *fd;
+       ssize_t err;
+       
+       trace_mark(xn_rtdm, sendmsg, "sys_ppd %p fd %d msg_name %p "
+                  "msg_namelen %u msg_iov %p msg_iovlen %zu "
+                  "msg_control %p msg_controllen %zu msg_flags %d",
+                  p, ufd, msg->msg_name, msg->msg_namelen,
+                  msg->msg_iov, msg->msg_iovlen, msg->msg_control,
+                  msg->msg_controllen, msg->msg_flags);
+
+       fd = xnfd_get(p, ufd, XNFD_MAGIC_ANY);
+       if (IS_ERR(fd))
+               return PTR_ERR(fd);
+       
+       if (ipipe_root_p)
+               err = fd->ops->sendmsg_nrt(fd, msg, flags);
+       else
+               err = fd->ops->sendmsg_rt(fd, msg, flags);
+       
+       if (!XENO_ASSERT(NUCLEUS, !spltest()))
+                   splnone();
+
+       xnfd_put(fd);
+       
+       return err;
+}
+EXPORT_SYMBOL_GPL(xnfd_sendmsg);
+
+static void 
+xnfd_close_inner(struct xnsys_ppd *p, struct xnfd_index *idx, spl_t s)
+{
+       xnid_remove(&p->fds, &idx->id);
+       xnfd_put_inner(idx->fd, s);
+
+       kfree(idx);
+}
+
+int xnfd_close(struct xnsys_ppd *p, int ufd, unsigned magic)
+{
+       struct xnfd_index *idx;
+       struct xnfd *fd;
+       spl_t s;
+
+       trace_mark(xn_rtdm, close, "sys_ppd %p fd %d", p, ufd);
+
+       xnlock_get_irqsave(&__xnfd_lock, s);
+       idx = xnfd_index_fetch(p, ufd);
+       if (idx == NULL)
+               goto ebadf;
+
+       fd = idx->fd;
+       if (magic != XNFD_MAGIC_ANY && fd->magic != magic) {
+         ebadf:
+               xnlock_put_irqrestore(&__xnfd_lock, s);
+               return -EBADF;
+       }
+       __rt_dev_unref(fd, xnid_id(&idx->id));
+       xnfd_close_inner(p, idx, s);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xnfd_close);
+
+int xnfd_valid_p(int ufd)
+{
+       struct xnfd *fd;
+       spl_t s;
+
+       xnlock_get_irqsave(&__xnfd_lock, s);
+       fd = xnfd_fetch(xnsys_ppd_get(0), ufd);
+       xnlock_put_irqrestore(&__xnfd_lock, s);
+       
+       return fd != NULL;
+}
+
+int xnfd_select_bind(int ufd, struct xnselector *selector, unsigned type)
+{
+       struct xnsys_ppd *p;
+       struct xnfd *fd;
+       int rc;
+       
+       p = xnsys_ppd_get(0);
+       fd = xnfd_get(p, ufd, XNFD_MAGIC_ANY);
+       if (IS_ERR(fd))
+               return PTR_ERR(fd);
+       
+       rc = fd->ops->select_bind(fd, selector, type, ufd);
+
+       xnfd_put(fd);
+       
+       return rc;
+}
+
+static void xnfd_destroy(void *cookie, struct xnid *id)
+{
+       struct xnsys_ppd *p = cookie;
+       struct xnfd_index *idx;
+       spl_t s;
+
+       idx = container_of(id, struct xnfd_index, id);
+       xnlock_get_irqsave(&__xnfd_lock, s);
+       xnfd_close_inner(p, idx, XNFD_MAGIC_ANY);
+}
+
+void xnfd_cleanup(struct xnsys_ppd *p)
+{
+       xntree_cleanup(&p->fds, p, xnfd_destroy);
+}
+
+void xnfd_init(void)
+{
+       sema_init(&xnfd_cleanup_sem, 0);
+       kthread_run(xnfd_cleanup_thread, NULL, "xnfd");
+}
diff --git a/kernel/cobalt/init.c b/kernel/cobalt/init.c
index bda790e..2f00aee 100644
--- a/kernel/cobalt/init.c
+++ b/kernel/cobalt/init.c
@@ -33,6 +33,7 @@
 #include <cobalt/kernel/pipe.h>
 #include <cobalt/kernel/select.h>
 #include <cobalt/kernel/vdso.h>
+#include <cobalt/kernel/fd.h>
 #include "rtdm/internal.h"
 #include "posix/internal.h"
 #include "procfs.h"
@@ -399,6 +400,8 @@ static int __init xenomai_init(void)
        if (ret)
                goto cleanup_rtdm;
 
+       xnfd_init();
+
        printk(XENO_INFO "Cobalt v%s enabled%s\n",
               XENO_VERSION_STRING, boot_notice);
 
diff --git a/kernel/cobalt/posix/Makefile b/kernel/cobalt/posix/Makefile
index aad94a6..5414110 100644
--- a/kernel/cobalt/posix/Makefile
+++ b/kernel/cobalt/posix/Makefile
@@ -5,6 +5,7 @@ posix-y :=              \
        cond.o          \
        cond_attr.o     \
        event.o         \
+       fdio.o          \
        init.o          \
        monitor.o       \
        mqueue.o        \
diff --git a/kernel/cobalt/posix/fdio.c b/kernel/cobalt/posix/fdio.c
new file mode 100644
index 0000000..1f72b7a
--- /dev/null
+++ b/kernel/cobalt/posix/fdio.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2005 Jan Kiszka <jan.kis...@web.de>.
+ * Copyright (C) 2005 Joerg Langenberg <joerg.langenb...@gmx.net>.
+ * Copyright (C) 2013,2014 Gilles Chanteperdrix <g...@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/kernel.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/ipipe.h>
+#include <cobalt/kernel/fd.h>
+#include <cobalt/kernel/ppd.h>
+#include "fdio.h"
+
+int cobalt_ioctl(int fd, unsigned int request, void __user *arg)
+{
+       return xnfd_ioctl(xnsys_ppd_get(0), fd, request, arg);
+}
+
+ssize_t cobalt_read(int fd, void __user *buf, size_t size)
+{
+       return xnfd_read(xnsys_ppd_get(0), fd, buf, size);
+}
+
+ssize_t cobalt_write(int fd, const void __user *buf, size_t size)
+{
+       return xnfd_write(xnsys_ppd_get(0), fd, buf, size);
+}
+
+ssize_t cobalt_recvmsg(int fd, struct msghdr __user *umsg, int flags)
+{
+       struct msghdr m;
+       int ret;
+
+       if (__xn_copy_from_user(&m, umsg, sizeof(m)))
+               return -EFAULT;
+
+       ret = xnfd_recvmsg(xnsys_ppd_get(0), fd, &m, flags);
+       if (ret < 0)
+               return ret;
+       
+       if (__xn_copy_to_user(umsg, &m, sizeof(*umsg)))
+               return -EFAULT;
+       
+       return ret;
+}
+
+ssize_t cobalt_sendmsg(int fd, struct msghdr __user *umsg, int flags)
+{
+       struct msghdr m;
+
+       if (__xn_copy_from_user(&m, umsg, sizeof(m)))
+               return -EFAULT;
+
+       return xnfd_sendmsg(xnsys_ppd_get(0), fd, &m, flags);
+}
+
+int cobalt_close(int fd)
+{
+       return xnfd_close(xnsys_ppd_get(0), fd, XNFD_MAGIC_ANY);
+}
diff --git a/kernel/cobalt/posix/fdio.h b/kernel/cobalt/posix/fdio.h
new file mode 100644
index 0000000..2947221
--- /dev/null
+++ b/kernel/cobalt/posix/fdio.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2005 Jan Kiszka <jan.kis...@web.de>.
+ * Copyright (C) 2005 Joerg Langenberg <joerg.langenb...@gmx.net>.
+ * Copyright (C) 2013,2014 Gilles Chanteperdrix <g...@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 FDIO_H
+#define FDIO_H
+
+int cobalt_ioctl(int fd, unsigned int request, void __user *arg);
+
+ssize_t cobalt_read(int fd, void __user *buf, size_t size);
+
+ssize_t cobalt_write(int fd, const void __user *buf, size_t size);
+
+ssize_t cobalt_recvmsg(int fd, struct msghdr __user *umsg, int flags);
+
+ssize_t cobalt_sendmsg(int fd, struct msghdr __user *umsg, int flags);
+
+int cobalt_close(int fd);
+
+#endif /* FDIO_H */
diff --git a/kernel/cobalt/posix/select.c b/kernel/cobalt/posix/select.c
index 6741331..d6d9e43 100644
--- a/kernel/cobalt/posix/select.c
+++ b/kernel/cobalt/posix/select.c
@@ -22,6 +22,7 @@
 #include <linux/types.h>
 #include <linux/err.h>
 #include <rtdm/driver.h>
+#include <cobalt/kernel/fd.h>
 #include "internal.h"
 #include "clock.h"
 #include "mqueue.h"
@@ -35,6 +36,9 @@ static int fd_valid_p(int fd)
        struct rtdm_dev_context *ctx;
        struct cobalt_process *cc;
 
+       if (xnfd_valid_p(fd))
+               return 1;
+
        if (fd >= rtdm_fd_start) {
                ctx = rtdm_context_get(fd - rtdm_fd_start);
                if (ctx == NULL)
@@ -69,6 +73,11 @@ 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;
+       int rc;
+
+       rc = xnfd_select_bind(fd, selector, type);
+       if (rc != -ENOENT)
+               return rc;
 
        if (fd >= rtdm_fd_start)
                return rtdm_select_bind(fd - rtdm_fd_start,
diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c
index 4f4759b..ee5b46e 100644
--- a/kernel/cobalt/posix/syscall.c
+++ b/kernel/cobalt/posix/syscall.c
@@ -39,6 +39,7 @@
 #include "clock.h"
 #include "event.h"
 #include "select.h"
+#include "fdio.h"
 
 int cobalt_muxid;
 
@@ -169,6 +170,12 @@ static struct xnsyscall cobalt_syscalls[] = {
        SKINCALL_DEF(sc_cobalt_event_sync, cobalt_event_sync, any),
        SKINCALL_DEF(sc_cobalt_sched_setconfig_np, cobalt_sched_setconfig_np, 
any),
        SKINCALL_DEF(sc_cobalt_sched_getconfig_np, cobalt_sched_getconfig_np, 
any),
+       SKINCALL_DEF(sc_cobalt_ioctl, cobalt_ioctl, probing),
+       SKINCALL_DEF(sc_cobalt_read, cobalt_read, probing),
+       SKINCALL_DEF(sc_cobalt_write, cobalt_write, probing),
+       SKINCALL_DEF(sc_cobalt_recvmsg, cobalt_recvmsg, probing),
+       SKINCALL_DEF(sc_cobalt_sendmsg, cobalt_sendmsg, probing),
+       SKINCALL_DEF(sc_cobalt_close, cobalt_close, lostage),
 };
 
 struct xnpersonality cobalt_personality = {
diff --git a/kernel/cobalt/shadow.c b/kernel/cobalt/shadow.c
index cea76bc..0b0ff34 100644
--- a/kernel/cobalt/shadow.c
+++ b/kernel/cobalt/shadow.c
@@ -58,6 +58,7 @@
 #include <cobalt/kernel/ppd.h>
 #include <cobalt/kernel/vdso.h>
 #include <cobalt/kernel/thread.h>
+#include <cobalt/kernel/fd.h>
 #include <asm/xenomai/features.h>
 #include <asm/xenomai/syscall.h>
 #include <asm-generic/xenomai/mayday.h>
@@ -1631,6 +1632,7 @@ static void user_process_detach(void *arg)
 
        if (p->exe_path)
                kfree(p->exe_path);
+       xnfd_cleanup(p);
        process_hash_remove(process);
        xnheap_destroy_mapped(&p->sem_heap, post_ppd_release, NULL);
        atomic_dec(&personalities[user_muxid]->refcnt);
@@ -1678,6 +1680,7 @@ static void *user_process_attach(void)
                exe_path = NULL; /* Not lethal, but weird. */
        }
        p->exe_path = exe_path;
+       xntree_init(&p->fds);
        atomic_set(&p->refcnt, 1);
        atomic_inc(&personalities[user_muxid]->refcnt);
 
diff --git a/lib/cobalt/rtdm.c b/lib/cobalt/rtdm.c
index e789d76..d253bb1 100644
--- a/lib/cobalt/rtdm.c
+++ b/lib/cobalt/rtdm.c
@@ -26,9 +26,11 @@
 #include <sys/socket.h>
 #include <rtdm/rtdm.h>
 #include <cobalt/uapi/rtdm/syscall.h>
+#include <cobalt/uapi/syscall.h>
 #include <asm/xenomai/syscall.h>
 
 extern int __rtdm_muxid;
+extern int __cobalt_muxid;
 extern int __rtdm_fd_start;
 
 static inline int set_errno(int ret)
@@ -109,6 +111,13 @@ COBALT_IMPL(int, close, (int fd))
 {
        int ret;
 
+       ret = XENOMAI_SKINCALL1(__cobalt_muxid, sc_cobalt_close, fd);
+       if (ret != -EBADF) {
+               if (ret == 0)
+                       __STD(close(fd));
+               return set_errno(ret);
+       }
+
        if (fd >= __rtdm_fd_start) {
                int oldtype;
 
@@ -131,11 +140,17 @@ COBALT_IMPL(int, ioctl, (int fd, unsigned long int 
request, ...))
 {
        va_list ap;
        void *arg;
+       int err;
 
        va_start(ap, request);
        arg = va_arg(ap, void *);
        va_end(ap);
 
+       err = XENOMAI_SKINCALL3(__cobalt_muxid,
+                               sc_cobalt_ioctl, fd, request, arg);
+       if (err != -EBADF)
+               return set_errno(err);
+
        if (fd >= __rtdm_fd_start)
                return set_errno(XENOMAI_SKINCALL3(__rtdm_muxid,
                                                   sc_rtdm_ioctl,
@@ -147,11 +162,19 @@ COBALT_IMPL(int, ioctl, (int fd, unsigned long int 
request, ...))
 
 COBALT_IMPL(ssize_t, read, (int fd, void *buf, size_t nbyte))
 {
-       if (fd >= __rtdm_fd_start) {
-               int ret, oldtype;
+       int ret, oldtype;
+       
+       pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
 
-               pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
+       ret = XENOMAI_SKINCALL3(__cobalt_muxid, sc_cobalt_read, 
+                               fd, buf, nbyte);
+
+       if (ret != -EBADF) {
+               pthread_setcanceltype(oldtype, NULL);
+               return set_errno(ret);
+       }
 
+       if (fd >= __rtdm_fd_start) {
                ret = set_errno(XENOMAI_SKINCALL3(__rtdm_muxid,
                                                  sc_rtdm_read,
                                                  fd - __rtdm_fd_start,
@@ -160,17 +183,28 @@ COBALT_IMPL(ssize_t, read, (int fd, void *buf, size_t 
nbyte))
                pthread_setcanceltype(oldtype, NULL);
 
                return ret;
-       } else
-               return __STD(read(fd, buf, nbyte));
+       }
+
+       pthread_setcanceltype(oldtype, NULL);
+               
+       return __STD(read(fd, buf, nbyte));
 }
 
 COBALT_IMPL(ssize_t, write, (int fd, const void *buf, size_t nbyte))
 {
-       if (fd >= __rtdm_fd_start) {
-               int ret, oldtype;
+       int ret, oldtype;
 
-               pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
+       pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
 
+       ret = XENOMAI_SKINCALL3(__cobalt_muxid, sc_cobalt_write,
+                               fd, buf, nbyte);
+
+       if (ret != -EBADF) {
+               pthread_setcanceltype(oldtype, NULL);
+               return set_errno(ret);
+       }
+       
+       if (fd >= __rtdm_fd_start) {
                ret = set_errno(XENOMAI_SKINCALL3(__rtdm_muxid,
                                                  sc_rtdm_write,
                                                  fd - __rtdm_fd_start,
@@ -179,8 +213,11 @@ COBALT_IMPL(ssize_t, write, (int fd, const void *buf, 
size_t nbyte))
                pthread_setcanceltype(oldtype, NULL);
 
                return ret;
-       } else
-               return __STD(write(fd, buf, nbyte));
+       }
+
+       pthread_setcanceltype(oldtype, NULL);
+
+       return __STD(write(fd, buf, nbyte));
 }
 
 COBALT_IMPL(ssize_t, recvmsg, (int fd, struct msghdr * msg, int flags))


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
http://www.xenomai.org/mailman/listinfo/xenomai-git

Reply via email to