Beside copying more than one char at once, rtems_termios_refill_transmitter() and rtems_termios_puts() now use a common helper that (after checking ORCVXOF) calls write() with as much chars as are available consecutively in rawOutBuf. Integer types used in new rtems_termios_start_xmit might not be ideal but resemble what is used in existing rtems_refill_transmitter code.
--- cpukit/libcsupport/src/termios.c | 133 ++++++++++++++++++++++++--------------- 1 file changed, 83 insertions(+), 50 deletions(-) diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c index 2448ea1..f14f138 100644 --- a/cpukit/libcsupport/src/termios.c +++ b/cpukit/libcsupport/src/termios.c @@ -974,6 +974,47 @@ rtems_termios_ioctl (void *arg) } /* + * Send as many chars at once as possible to device-specific code. + * If stopXmit==true then explicitly write(0) to stop transmitter. + */ +static int +rtems_termios_start_xmit ( + struct rtems_termios_tty *tty, unsigned int newTail, bool stopXmit) +{ + int nToSend; + + /* if XOFF was received, do not start output resp. stop */ + if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF)) + == (FL_MDXON | FL_ORCVXOF)) { + /* Buffer not empty, but output stops due to XOFF */ + /* set flag, that output has been stopped */ + tty->flow_ctrl |= FL_OSTOP; + nToSend = 0; + tty->rawOutBufState = rob_busy; + if (stopXmit) { + (*tty->handler.write) (tty, NULL, 0); + } + } else { + if (newTail > tty->rawOutBuf.Head) + nToSend = tty->rawOutBuf.Size - newTail; + else + nToSend = tty->rawOutBuf.Head - newTail; + /* when flow control XON or XOF, don't send blocks of data */ + /* to allow fast reaction on incoming flow ctrl and low latency*/ + /* for outgoing flow control */ + if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) { + nToSend = 1; + } + + tty->rawOutBufState = rob_busy; + (*tty->handler.write)( + tty, &tty->rawOutBuf.theBuf[newTail], nToSend); + } + + return nToSend; +} + +/* * Send characters to device-specific code */ void @@ -989,21 +1030,16 @@ rtems_termios_puts ( (*tty->handler.write)(tty, buf, len); return; } - newHead = tty->rawOutBuf.Head; + while (len) { - /* - * Performance improvement could be made here. - * Copy multiple bytes to raw buffer: - * if (len > 1) && (space to buffer end, or tail > 1) - * ncopy = MIN (len, space to buffer end or tail) - * memcpy (raw buffer, buf, ncopy) - * buf += ncopy - * len -= ncopy - * - * To minimize latency, the memcpy should be done - * with interrupts enabled. - */ - newHead = (newHead + 1) % tty->rawOutBuf.Size; + size_t nToCopy; + size_t nAvail; + + /* Check space for at least one char */ + newHead = tty->rawOutBuf.Head + 1; + if (newHead >= tty->rawOutBuf.Size) + newHead -= tty->rawOutBuf.Size; + rtems_termios_interrupt_lock_acquire (tty, &lock_context); while (newHead == tty->rawOutBuf.Tail) { tty->rawOutBufState = rob_wait; @@ -1014,21 +1050,41 @@ rtems_termios_puts ( rtems_fatal_error_occurred (sc); rtems_termios_interrupt_lock_acquire (tty, &lock_context); } - tty->rawOutBuf.theBuf[tty->rawOutBuf.Head] = *buf++; + + /* Determine free space up to current tail or end of ring buffer */ + nToCopy = len; + if (tty->rawOutBuf.Tail > tty->rawOutBuf.Head) { + /* Available space is contiguous from Head to Tail */ + nAvail = tty->rawOutBuf.Tail - tty->rawOutBuf.Head - 1; + } else { + /* Available space wraps at buffer end. To keep code simple, utilize + only the part from Head to end during this iteration */ + nAvail = tty->rawOutBuf.Size - tty->rawOutBuf.Head; + /* Head may not touch Tail after wraparound */ + if (tty->rawOutBuf.Tail == 0) + nAvail--; + } + if (nToCopy > nAvail) + nToCopy = nAvail; + + /* To minimize latency, the memcpy could be done + * with interrupts enabled or with limit on nToCopy (TBD) + */ + memcpy(&tty->rawOutBuf.theBuf[tty->rawOutBuf.Head], buf, nToCopy); + + newHead = tty->rawOutBuf.Head + nToCopy; + if (newHead >= tty->rawOutBuf.Size) + newHead -= tty->rawOutBuf.Size; tty->rawOutBuf.Head = newHead; + if (tty->rawOutBufState == rob_idle) { - /* check, whether XOFF has been received */ - if (!(tty->flow_ctrl & FL_ORCVXOF)) { - (*tty->handler.write)( - tty, &tty->rawOutBuf.theBuf[tty->rawOutBuf.Tail],1); - } else { - /* remember that output has been stopped due to flow ctrl*/ - tty->flow_ctrl |= FL_OSTOP; - } - tty->rawOutBufState = rob_busy; + (void)rtems_termios_start_xmit (tty, tty->rawOutBuf.Tail, false); } + rtems_termios_interrupt_lock_release (tty, &lock_context); - len--; + + buf += nToCopy; + len -= nToCopy; } } @@ -1678,35 +1734,12 @@ rtems_termios_refill_transmitter (struct rtems_termios_tty *tty) if ( tty->tty_snd.sw_pfn != NULL) { (*tty->tty_snd.sw_pfn)(&tty->termios, tty->tty_snd.sw_arg); } - } - /* check, whether output should stop due to received XOFF */ - else if ((tty->flow_ctrl & (FL_MDXON | FL_ORCVXOF)) - == (FL_MDXON | FL_ORCVXOF)) { - /* Buffer not empty, but output stops due to XOFF */ - /* set flag, that output has been stopped */ - tty->flow_ctrl |= FL_OSTOP; - tty->rawOutBufState = rob_busy; /*apm*/ - (*tty->handler.write) (tty, NULL, 0); - nToSend = 0; } else { /* - * Buffer not empty, start tranmitter + * Buffer not empty, check flow control, start transmitter */ - if (newTail > tty->rawOutBuf.Head) - nToSend = tty->rawOutBuf.Size - newTail; - else - nToSend = tty->rawOutBuf.Head - newTail; - /* when flow control XON or XOF, don't send blocks of data */ - /* to allow fast reaction on incoming flow ctrl and low latency*/ - /* for outgoing flow control */ - if (tty->flow_ctrl & (FL_MDXON | FL_MDXOF)) { - nToSend = 1; - } - tty->rawOutBufState = rob_busy; /*apm*/ - (*tty->handler.write)( - tty, &tty->rawOutBuf.theBuf[newTail], nToSend); + nToSend = rtems_termios_start_xmit (tty, newTail, true); } - tty->rawOutBuf.Tail = newTail; /*apm*/ } rtems_termios_interrupt_lock_release (tty, &lock_context); -- 1.9.1 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel