summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-10-05 10:37:56 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2016-12-16 09:04:58 +0100
commitc3764ce80588461d086e844e68002142dbd1ead9 (patch)
treefc03d7a814a4995cff248b0a4c5c0acaa8a3da8b
parenta5c56afa35ab82353cab9fb9ad70ee957c558a96 (diff)
downloadrtems-c3764ce80588461d086e844e68002142dbd1ead9.tar.bz2
termios: Use mutex for task driven mode
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.
-rw-r--r--cpukit/libcsupport/include/rtems/termiostypes.h26
-rw-r--r--cpukit/libcsupport/src/termios.c78
2 files changed, 97 insertions, 7 deletions
diff --git a/cpukit/libcsupport/include/rtems/termiostypes.h b/cpukit/libcsupport/include/rtems/termiostypes.h
index a852c1dbed..81d28c283c 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 b972b4f34f..3bc5bb8e1d 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
*/