forked from Imagelibrary/rtems
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:
@@ -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 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user