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.
This commit is contained in:
Sebastian Huber
2016-10-05 10:37:56 +02:00
parent a5c56afa35
commit c3764ce805
2 changed files with 97 additions and 7 deletions

View File

@@ -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 );
}
/**

View File

@@ -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
*/