[PATCH] rtems_termios_puts: Copy and write more than one char at once

Joel Sherrill joel.sherrill at oarcorp.com
Mon Aug 18 23:41:36 UTC 2014


I committed this.  Thanks.

If there is something I missed, please let me know.

--joel

On 8/14/2014 10:02 AM, Kolja Waschk wrote:
> Renamed startXmit(), nToSend is unsigned, just check FL_ORCVXOF, no (void) cast anymore, compute nToSend in single if/else if/else.
>
>
> ---
>  cpukit/libcsupport/src/termios.c | 135 ++++++++++++++++++++++++---------------
>  1 file changed, 85 insertions(+), 50 deletions(-)
>
> diff --git a/cpukit/libcsupport/src/termios.c b/cpukit/libcsupport/src/termios.c
> index 2448ea1..216834c 100644
> --- a/cpukit/libcsupport/src/termios.c
> +++ b/cpukit/libcsupport/src/termios.c
> @@ -974,6 +974,49 @@ rtems_termios_ioctl (void *arg)
>  }
>  
>  /*
> + * Send as many chars at once as possible to device-specific code.
> + * If transmitting==true then assume transmission is already running and
> + * an explicit write(0) is needed if output has to stop for flow control.
> + */
> +static unsigned int
> +startXmit (
> +  struct rtems_termios_tty *tty,
> +  unsigned int newTail,
> +  bool transmitting
> +)
> +{
> +  unsigned int nToSend;
> +
> +  tty->rawOutBufState = rob_busy;
> +
> +  /* if XOFF was received, do not (re)start output */
> +  if (tty->flow_ctrl & FL_ORCVXOF) {
> +    /* set flag, that output has been stopped */
> +    tty->flow_ctrl |= FL_OSTOP;
> +    nToSend = 0;
> +    /* stop transmitter */
> +    if (transmitting) {
> +      (*tty->handler.write) (tty, NULL, 0);
> +    }
> +  } else {
> +    /* 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;
> +    else if (newTail > tty->rawOutBuf.Head)
> +      nToSend = tty->rawOutBuf.Size - newTail;
> +    else
> +      nToSend = tty->rawOutBuf.Head - newTail;
> +
> +    (*tty->handler.write)(
> +        tty, &tty->rawOutBuf.theBuf[newTail], nToSend);
> +  }
> +
> +  return nToSend;
> +}
> +
> +/*
>   * Send characters to device-specific code
>   */
>  void
> @@ -989,21 +1032,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 +1052,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 it simple, utilize
> +         only the free space 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;
> +      startXmit (tty, tty->rawOutBuf.Tail, false);
>      }
> +
>      rtems_termios_interrupt_lock_release (tty, &lock_context);
> -    len--;
> +
> +    buf += nToCopy;
> +    len -= nToCopy;
>    }
>  }
>  
> @@ -1678,35 +1736,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 = startXmit (tty, newTail, true);
>      }
> -    tty->rawOutBuf.Tail = newTail; /*apm*/
>    }
>  
>    rtems_termios_interrupt_lock_release (tty, &lock_context);

-- 
Joel Sherrill, Ph.D.             Director of Research & Development
joel.sherrill at OARcorp.com        On-Line Applications Research
Ask me about RTEMS: a free RTOS  Huntsville AL 35805
Support Available                (256) 722-9985




More information about the devel mailing list