[rtems commit] Filesystem: IO control based select() support

Sebastian Huber sebh at rtems.org
Mon Jul 9 08:39:09 UTC 2012


Module:    rtems
Branch:    master
Commit:    92a35861d4795075dcff3ebab177812c7422753f
Changeset: http://git.rtems.org/rtems/commit/?id=92a35861d4795075dcff3ebab177812c7422753f

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Tue Apr  3 15:14:50 2012 +0200

Filesystem: IO control based select() support

This is a hack.  The Termios write facility has a severe issue with the
lacking support of non-blocking writes.

---

 cpukit/libcsupport/include/sys/ioccom.h   |   25 ++++++++++-
 cpukit/libcsupport/src/termios.c          |   71 +++++++++++++++++++++++++++++
 cpukit/libnetworking/rtems/rtems_select.c |   32 ++++++++++++-
 3 files changed, 124 insertions(+), 4 deletions(-)

diff --git a/cpukit/libcsupport/include/sys/ioccom.h b/cpukit/libcsupport/include/sys/ioccom.h
index 09b4728..6d97c67 100644
--- a/cpukit/libcsupport/include/sys/ioccom.h
+++ b/cpukit/libcsupport/include/sys/ioccom.h
@@ -36,7 +36,7 @@
 #ifndef	_SYS_IOCCOM_H_
 #define	_SYS_IOCCOM_H_
 
-#include <sys/types.h>
+#include <rtems.h>
 
 /*
  * Ioctl's have the command encoded in the lower word, and the size of
@@ -76,6 +76,29 @@
 #define       RTEMS_IO_RCVWAKEUP      4
 #define       RTEMS_IO_SNDWAKEUP      5
 
+typedef enum {
+  RTEMS_IOCTL_SELECT_OTHER,
+  RTEMS_IOCTL_SELECT_READ,
+  RTEMS_IOCTL_SELECT_WRITE
+} rtems_ioctl_select_kind;
+
+/**
+ * @brief IO control request for select() support.
+ *
+ * The driver shall return
+ *   - 1, when the request can be fullfilled immediately,
+ *   - 0, when the request task must wait, and
+ *   - -1, in case of an error.
+ */
+typedef struct {
+  rtems_ioctl_select_kind kind;
+  rtems_id request_task_id;
+} rtems_ioctl_select_request;
+
+#define RTEMS_IOCTL_SELECT _IOW('R', 0, rtems_ioctl_select_request)
+
+#define RTEMS_IOCTL_SELECT_EVENT RTEMS_EVENT_24
+
 /* copied from libnetworking/sys/filio.h and commented out there */
 /* Generic file-descriptor ioctl's. */
 #define FIOCLEX          _IO('f', 1)            /* set close on exec on fd */
diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c
index 17fa5ef..823a2cb 100644
--- a/cpukit/libcsupport/src/termios.c
+++ b/cpukit/libcsupport/src/termios.c
@@ -509,6 +509,73 @@ termios_set_flowctrl(struct rtems_termios_tty *tty)
   }
 }
 
+static bool
+rtems_termios_can_read (const struct rtems_termios_tty *tty)
+{
+  if (tty->cindex == tty->ccount) {
+    if (tty->device.outputUsesInterrupts == TERMIOS_IRQ_DRIVEN) {
+      return tty->rawInBuf.Head != tty->rawInBuf.Tail;
+    } else {
+      return true;
+    }
+  } else {
+    return tty->cindex < tty->ccount;
+  }
+}
+
+static bool
+rtems_termios_can_write (const struct rtems_termios_tty *tty)
+{
+  /*
+   * Termios has no non-blocking writes.  In case the raw output buffer is
+   * full, we wait for the interrupt or poll.
+   */
+  return true;
+}
+
+static void
+rtems_termios_select_wakeup (struct termios *tty, void *arg)
+{
+  rtems_id task_id = (rtems_id) arg;
+  rtems_status_code sc = rtems_event_send (task_id, RTEMS_IOCTL_SELECT_EVENT);
+  if (sc != RTEMS_SUCCESSFUL)
+    rtems_fatal_error_occurred (sc);
+}
+
+static int
+rtems_termios_select (struct rtems_termios_tty *tty,
+                      const rtems_ioctl_select_request *request)
+{
+  int rv = 0;
+
+  rtems_interrupt_level level;
+  rtems_interrupt_disable(level);
+  switch (request->kind) {
+    case RTEMS_IOCTL_SELECT_READ:
+      if (rtems_termios_can_read (tty)) {
+        rv = 1;
+      } else {
+        tty->tty_rcvwakeup = 0;
+        tty->tty_rcv.sw_pfn = rtems_termios_select_wakeup;
+        tty->tty_rcv.sw_arg = (void *) request->request_task_id;
+      }
+      break;
+    case RTEMS_IOCTL_SELECT_WRITE:
+      if (rtems_termios_can_write (tty)) {
+        rv = 1;
+      } else {
+        tty->tty_snd.sw_pfn = rtems_termios_select_wakeup;
+        tty->tty_snd.sw_arg = (void *) request->request_task_id;
+      }
+      break;
+    default:
+      break;
+  }
+  rtems_interrupt_enable(level);
+
+  return rv;
+}
+
 rtems_status_code
 rtems_termios_ioctl (void *arg)
 {
@@ -532,6 +599,10 @@ rtems_termios_ioctl (void *arg)
     }
     break;
 
+  case RTEMS_IOCTL_SELECT:
+    args->ioctl_return = rtems_termios_select (tty, args->buffer);
+    break;
+
   case RTEMS_IO_GET_ATTRIBUTES:
     *(struct termios *)args->buffer = tty->termios;
     break;
diff --git a/cpukit/libnetworking/rtems/rtems_select.c b/cpukit/libnetworking/rtems/rtems_select.c
index 927c07d..b8915b6 100644
--- a/cpukit/libnetworking/rtems/rtems_select.c
+++ b/cpukit/libnetworking/rtems/rtems_select.c
@@ -30,6 +30,11 @@
 #include <net/if.h>
 #include <net/route.h>
 
+RTEMS_STATIC_ASSERT(RTEMS_IOCTL_SELECT_OTHER == 0, other);
+RTEMS_STATIC_ASSERT(RTEMS_IOCTL_SELECT_READ == FREAD, fread);
+RTEMS_STATIC_ASSERT(RTEMS_IOCTL_SELECT_WRITE == FWRITE, fwrite);
+RTEMS_STATIC_ASSERT(RTEMS_IOCTL_SELECT_EVENT == SBWAIT_EVENT, sbwait_event);
+
 /*
  *********************************************************************
  *            RTEMS implementation of select() system call           *
@@ -88,6 +93,11 @@ selscan (rtems_id tid, fd_mask **ibits, fd_mask **obits, int nfd, int *retval)
 	fd_mask bits, bit;
 	int n = 0;
 	static int flag[3] = { FREAD, FWRITE, 0 };
+	int update_obits;
+	int rv;
+	rtems_ioctl_select_request select_request;
+
+	select_request.request_task_id = tid;
 
 	for (msk = 0; msk < 3; msk++) {
 		if (ibits[msk] == NULL)
@@ -98,10 +108,26 @@ selscan (rtems_id tid, fd_mask **ibits, fd_mask **obits, int nfd, int *retval)
 				if ((bits & bit) == 0)
 					continue;
 				bits &= ~bit;
+				update_obits = 0;
 				so = rtems_bsdnet_fdToSocket (fd);
-				if (so == NULL)
-					return (EBADF);
-				if (socket_select (so, flag[msk], tid)) {
+				if (so != NULL) {
+					if (socket_select (so, flag[msk], tid)) {
+						update_obits = 1;
+					}
+				} else {
+					select_request.kind = flag[msk];
+
+					rtems_bsdnet_semaphore_release();
+					rv = ioctl (fd, RTEMS_IOCTL_SELECT, &select_request);
+					rtems_bsdnet_semaphore_obtain();
+					if (rv == 1) {
+						update_obits = 1;
+					} else if (rv != 0) {
+						return (EBADF);
+					}
+				}
+
+				if (update_obits) {
 					obits[msk][fd/NFDBITS] |=
 							(1 << (fd % NFDBITS));
 					n++;




More information about the vc mailing list