diff options
-rw-r--r-- | cpukit/libcsupport/src/termios.c | 155 | ||||
-rw-r--r-- | testsuites/libtests/termios01/init.c | 50 |
2 files changed, 132 insertions, 73 deletions
diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c index b70060dd85..2448ea1068 100644 --- a/cpukit/libcsupport/src/termios.c +++ b/cpukit/libcsupport/src/termios.c @@ -284,6 +284,82 @@ rtems_termios_callback_startRemoteTx (rtems_termios_tty *tty) (*tty->device.startRemoteTx) (tty->minor); } +/* + * Drain output queue + */ +static void +drainOutput (struct rtems_termios_tty *tty) +{ + rtems_interrupt_lock_context lock_context; + rtems_status_code sc; + + if (tty->handler.mode != TERMIOS_POLLED) { + rtems_termios_interrupt_lock_acquire (tty, &lock_context); + while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) { + tty->rawOutBufState = rob_wait; + rtems_termios_interrupt_lock_release (tty, &lock_context); + sc = rtems_semaphore_obtain( + tty->rawOutBuf.Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (sc); + rtems_termios_interrupt_lock_acquire (tty, &lock_context); + } + rtems_termios_interrupt_lock_release (tty, &lock_context); + } +} + +static void +rtems_termios_destroy_tty (rtems_termios_tty *tty, void *arg, bool last_close) +{ + rtems_status_code sc; + + if (rtems_termios_linesw[tty->t_line].l_close != NULL) { + /* + * call discipline-specific close + */ + sc = rtems_termios_linesw[tty->t_line].l_close(tty); + } else if (last_close) { + /* + * default: just flush output buffer + */ + sc = rtems_semaphore_obtain(tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) { + rtems_fatal_error_occurred (sc); + } + drainOutput (tty); + rtems_semaphore_release (tty->osem); + } + + if (tty->handler.mode == TERMIOS_TASK_DRIVEN) { + /* + * send "terminate" to I/O tasks + */ + sc = rtems_event_send( tty->rxTaskId, TERMIOS_RX_TERMINATE_EVENT ); + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (sc); + sc = rtems_event_send( tty->txTaskId, TERMIOS_TX_TERMINATE_EVENT ); + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (sc); + } + if (last_close && tty->handler.last_close) + (*tty->handler.last_close)(tty, arg); + + if (tty->device_node != NULL) + tty->device_node->tty = NULL; + + rtems_semaphore_delete (tty->isem); + rtems_semaphore_delete (tty->osem); + rtems_semaphore_delete (tty->rawOutBuf.Semaphore); + if ((tty->handler.poll_read == NULL) || + (tty->handler.mode == TERMIOS_TASK_DRIVEN)) + rtems_semaphore_delete (tty->rawInBuf.Semaphore); + rtems_interrupt_lock_destroy (&tty->interrupt_lock); + free (tty->rawInBuf.theBuf); + free (tty->rawOutBuf.theBuf); + free (tty->cbuf); + free (tty); +} + static rtems_termios_tty * rtems_termios_open_tty( rtems_device_major_number major, @@ -486,8 +562,11 @@ rtems_termios_open_tty( } args->iop->data1 = tty; if (!tty->refcount++) { - if (tty->handler.first_open) - (*tty->handler.first_open)(tty, args); + if (tty->handler.first_open && + !(*tty->handler.first_open)(tty, args)) { + rtems_termios_destroy_tty(tty, args, false); + return NULL; + } /* * start I/O tasks, if needed @@ -594,30 +673,6 @@ rtems_termios_open ( return RTEMS_SUCCESSFUL; } -/* - * Drain output queue - */ -static void -drainOutput (struct rtems_termios_tty *tty) -{ - rtems_interrupt_lock_context lock_context; - rtems_status_code sc; - - if (tty->handler.mode != TERMIOS_POLLED) { - rtems_termios_interrupt_lock_acquire (tty, &lock_context); - while (tty->rawOutBuf.Tail != tty->rawOutBuf.Head) { - tty->rawOutBufState = rob_wait; - rtems_termios_interrupt_lock_release (tty, &lock_context); - sc = rtems_semaphore_obtain( - tty->rawOutBuf.Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - if (sc != RTEMS_SUCCESSFUL) - rtems_fatal_error_occurred (sc); - rtems_termios_interrupt_lock_acquire (tty, &lock_context); - } - rtems_termios_interrupt_lock_release (tty, &lock_context); - } -} - static void flushOutput (struct rtems_termios_tty *tty) { @@ -644,54 +699,8 @@ flushInput (struct rtems_termios_tty *tty) static void rtems_termios_close_tty (rtems_termios_tty *tty, void *arg) { - rtems_status_code sc; - if (--tty->refcount == 0) { - if (rtems_termios_linesw[tty->t_line].l_close != NULL) { - /* - * call discipline-specific close - */ - sc = rtems_termios_linesw[tty->t_line].l_close(tty); - } else { - /* - * default: just flush output buffer - */ - sc = rtems_semaphore_obtain(tty->osem, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - if (sc != RTEMS_SUCCESSFUL) { - rtems_fatal_error_occurred (sc); - } - drainOutput (tty); - rtems_semaphore_release (tty->osem); - } - - if (tty->handler.mode == TERMIOS_TASK_DRIVEN) { - /* - * send "terminate" to I/O tasks - */ - sc = rtems_event_send( tty->rxTaskId, TERMIOS_RX_TERMINATE_EVENT ); - if (sc != RTEMS_SUCCESSFUL) - rtems_fatal_error_occurred (sc); - sc = rtems_event_send( tty->txTaskId, TERMIOS_TX_TERMINATE_EVENT ); - if (sc != RTEMS_SUCCESSFUL) - rtems_fatal_error_occurred (sc); - } - if (tty->handler.last_close) - (*tty->handler.last_close)(tty, arg); - - if (tty->device_node != NULL) - tty->device_node->tty = NULL; - - rtems_semaphore_delete (tty->isem); - rtems_semaphore_delete (tty->osem); - rtems_semaphore_delete (tty->rawOutBuf.Semaphore); - if ((tty->handler.poll_read == NULL) || - (tty->handler.mode == TERMIOS_TASK_DRIVEN)) - rtems_semaphore_delete (tty->rawInBuf.Semaphore); - rtems_interrupt_lock_destroy (&tty->interrupt_lock); - free (tty->rawInBuf.theBuf); - free (tty->rawOutBuf.theBuf); - free (tty->cbuf); - free (tty); + rtems_termios_destroy_tty (tty, arg, true); } } diff --git a/testsuites/libtests/termios01/init.c b/testsuites/libtests/termios01/init.c index 5010c38a05..896867895d 100644 --- a/testsuites/libtests/termios01/init.c +++ b/testsuites/libtests/termios01/init.c @@ -605,6 +605,55 @@ static void test_device_install_remove(void) rtems_test_assert( rtems_resource_snapshot_check( &snapshot ) ); } +static bool first_open_error( + rtems_termios_tty *tty, + rtems_libio_open_close_args_t *args +) +{ + bool *done = rtems_termios_get_device_context( tty ); + + (void) args; + + *done = true; + + return false; +} + +static void test_first_open_error(void) +{ + static const rtems_termios_device_handler handler = { + .first_open = first_open_error + }; + static const rtems_device_major_number major = 123456789; + static const rtems_device_minor_number minor = 0xdeadbeef; + static const char dev[] = "/foobar"; + + rtems_resource_snapshot snapshot; + rtems_status_code sc; + rtems_libio_t iop; + rtems_libio_open_close_args_t args; + bool done = false; + + rtems_resource_snapshot_take( &snapshot ); + + sc = rtems_termios_device_install( &dev[0], major, minor, &handler, &done ); + rtems_test_assert( sc == RTEMS_SUCCESSFUL ); + + memset( &iop, 0, sizeof( iop ) ); + memset( &args, 0, sizeof( args ) ); + args.iop = &iop; + + rtems_test_assert( !done ); + sc = rtems_termios_device_open( major, minor, &args ); + rtems_test_assert( sc == RTEMS_NO_MEMORY ); + rtems_test_assert( done ); + + sc = rtems_termios_device_remove( &dev[0], major, minor ); + rtems_test_assert( sc == RTEMS_SUCCESSFUL ); + + rtems_test_assert( rtems_resource_snapshot_check( &snapshot ) ); +} + static bool set_attributes_error( rtems_termios_tty *tty, const struct termios *term @@ -821,6 +870,7 @@ static rtems_task Init( puts( "" ); test_device_install_remove(); + test_first_open_error(); test_set_attributes_error(); TEST_END(); |