[PATCH 1/6] termios: Use mutex for task driven mode

Sebastian Huber sebastian.huber at embedded-brains.de
Wed Dec 14 13:39:37 UTC 2016


Termios has a task driven mode (TERMIOS_TASK_DRIVEN). This mode aims to
avoid long sections with disabled interrupts. This is only partly
implemented since the device level state is still protected by disabled
interrupts. Use a mutex to protect the device level state in task driven
mode to fix this issue.

Update #2838.
---
 cpukit/libcsupport/include/rtems/termiostypes.h | 26 +++++++--
 cpukit/libcsupport/src/termios.c                | 78 ++++++++++++++++++++++++-
 2 files changed, 97 insertions(+), 7 deletions(-)

diff --git a/cpukit/libcsupport/include/rtems/termiostypes.h b/cpukit/libcsupport/include/rtems/termiostypes.h
index a852c1d..81d28c2 100644
--- a/cpukit/libcsupport/include/rtems/termiostypes.h
+++ b/cpukit/libcsupport/include/rtems/termiostypes.h
@@ -70,7 +70,23 @@ struct rtems_termios_tty;
  * rtems_termios_device_install().
  */
 typedef struct rtems_termios_device_context {
-  rtems_interrupt_lock interrupt_lock;
+  union {
+    /* Used for TERMIOS_POLLED and TERMIOS_IRQ_DRIVEN */
+    rtems_interrupt_lock interrupt;
+
+    /* Used for TERMIOS_TASK_DRIVEN */
+    rtems_id mutex;
+  } lock;
+
+  void ( *lock_acquire )(
+    struct rtems_termios_device_context *,
+    rtems_interrupt_lock_context *
+  );
+
+  void ( *lock_release )(
+    struct rtems_termios_device_context *,
+    rtems_interrupt_lock_context *
+  );
 } rtems_termios_device_context;
 
 /**
@@ -86,7 +102,7 @@ RTEMS_INLINE_ROUTINE void rtems_termios_device_context_initialize(
   const char                   *name
 )
 {
-  rtems_interrupt_lock_initialize( &context->interrupt_lock, name );
+  rtems_interrupt_lock_initialize( &context->lock.interrupt, name );
 }
 
 /**
@@ -96,7 +112,7 @@ RTEMS_INLINE_ROUTINE void rtems_termios_device_context_initialize(
  *   is only used if profiling is enabled.
  */
 #define RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER( name ) \
-  { RTEMS_INTERRUPT_LOCK_INITIALIZER( name ) }
+  { { RTEMS_INTERRUPT_LOCK_INITIALIZER( name ) } }
 
 /**
  * @brief Termios device handler.
@@ -408,7 +424,7 @@ RTEMS_INLINE_ROUTINE void rtems_termios_device_lock_acquire(
   rtems_interrupt_lock_context *lock_context
 )
 {
-  rtems_interrupt_lock_acquire( &context->interrupt_lock, lock_context );
+  ( *context->lock_acquire )( context, lock_context );
 }
 
 /**
@@ -423,7 +439,7 @@ RTEMS_INLINE_ROUTINE void rtems_termios_device_lock_release(
   rtems_interrupt_lock_context *lock_context
 )
 {
-  rtems_interrupt_lock_release( &context->interrupt_lock, lock_context );
+  ( *context->lock_release )( context, lock_context );
 }
 
 /**
diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c
index b972b4f..3bc5bb8 100644
--- a/cpukit/libcsupport/src/termios.c
+++ b/cpukit/libcsupport/src/termios.c
@@ -272,6 +272,12 @@ drainOutput (struct rtems_termios_tty *tty)
   }
 }
 
+static bool
+needDeviceMutex (rtems_termios_tty *tty)
+{
+  return tty->handler.mode == TERMIOS_TASK_DRIVEN;
+}
+
 static void
 rtems_termios_destroy_tty (rtems_termios_tty *tty, void *arg, bool last_close)
 {
@@ -318,8 +324,11 @@ rtems_termios_destroy_tty (rtems_termios_tty *tty, void *arg, bool last_close)
       (tty->handler.mode == TERMIOS_TASK_DRIVEN))
     rtems_semaphore_delete (tty->rawInBuf.Semaphore);
 
-  if (tty->device_context == &tty->legacy_device_context)
-    rtems_interrupt_lock_destroy (&tty->legacy_device_context.interrupt_lock);
+  if (needDeviceMutex (tty)) {
+    rtems_semaphore_delete (tty->device_context->lock.mutex);
+  } else if (tty->device_context == &tty->legacy_device_context) {
+    rtems_interrupt_lock_destroy (&tty->legacy_device_context.lock.interrupt);
+  }
 
   free (tty->rawInBuf.theBuf);
   free (tty->rawOutBuf.theBuf);
@@ -327,6 +336,50 @@ rtems_termios_destroy_tty (rtems_termios_tty *tty, void *arg, bool last_close)
   free (tty);
 }
 
+static void
+deviceAcquireMutex(
+  rtems_termios_device_context *ctx,
+  rtems_interrupt_lock_context *lock_context
+)
+{
+  rtems_status_code sc;
+
+  sc = rtems_semaphore_obtain (ctx->lock.mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+  _Assert (sc == RTEMS_SUCCESSFUL);
+  (void) sc;
+}
+
+static void
+deviceReleaseMutex(
+  rtems_termios_device_context *ctx,
+  rtems_interrupt_lock_context *lock_context
+)
+{
+  rtems_status_code sc;
+
+  sc = rtems_semaphore_release (ctx->lock.mutex);
+  _Assert (sc == RTEMS_SUCCESSFUL);
+  (void) sc;
+}
+
+static void
+deviceAcquireInterrupt(
+  rtems_termios_device_context *ctx,
+  rtems_interrupt_lock_context *lock_context
+)
+{
+  rtems_interrupt_lock_acquire (&ctx->lock.interrupt, lock_context);
+}
+
+static void
+deviceReleaseInterrupt(
+  rtems_termios_device_context *ctx,
+  rtems_interrupt_lock_context *lock_context
+)
+{
+  rtems_interrupt_lock_release (&ctx->lock.interrupt, lock_context);
+}
+
 static rtems_termios_tty *
 rtems_termios_open_tty(
   rtems_device_major_number      major,
@@ -341,6 +394,7 @@ rtems_termios_open_tty(
 
   if (tty == NULL) {
     static char c = 'a';
+    rtems_termios_device_context *ctx;
 
     /*
      * Create a new device
@@ -459,6 +513,26 @@ rtems_termios_open_tty(
       rtems_termios_device_context_initialize (tty->device_context, "Termios");
     }
 
+    ctx = tty->device_context;
+
+    if (needDeviceMutex (tty)) {
+      sc = rtems_semaphore_create (
+        rtems_build_name ('T', 'l', 'k', c),
+        1,
+        RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
+        0,
+        &ctx->lock.mutex);
+      if (sc != RTEMS_SUCCESSFUL) {
+        rtems_fatal_error_occurred (sc);
+      }
+
+      ctx->lock_acquire = deviceAcquireMutex;
+      ctx->lock_release = deviceReleaseMutex;
+    } else {
+      ctx->lock_acquire = deviceAcquireInterrupt;
+      ctx->lock_release = deviceReleaseInterrupt;
+    }
+
     /*
      * Create I/O tasks
      */
-- 
1.8.4.5



More information about the devel mailing list