From c3764ce80588461d086e844e68002142dbd1ead9 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 5 Oct 2016 10:37:56 +0200 Subject: 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. --- 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 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 */ -- cgit v1.2.3