termios: Protect raw input buffer with device lock

Use the device lock to protect the raw input buffer management, e.g.
tail, head and buffer content updates.

Close #2914.
This commit is contained in:
Sebastian Huber
2017-02-23 10:06:52 +01:00
parent d60c2d7943
commit bb087cb0f9

View File

@@ -1424,14 +1424,19 @@ fillBufferPoll (struct rtems_termios_tty *tty)
static void static void
fillBufferQueue (struct rtems_termios_tty *tty) fillBufferQueue (struct rtems_termios_tty *tty)
{ {
rtems_termios_device_context *ctx = tty->device_context;
rtems_interval timeout = tty->rawInBufSemaphoreFirstTimeout; rtems_interval timeout = tty->rawInBufSemaphoreFirstTimeout;
rtems_status_code sc; bool wait = true;
int wait = 1;
while ( wait ) { while ( wait ) {
rtems_interrupt_lock_context lock_context;
/* /*
* Process characters read from raw queue * Process characters read from raw queue
*/ */
rtems_termios_device_lock_acquire (ctx, &lock_context);
while ((tty->rawInBuf.Head != tty->rawInBuf.Tail) && while ((tty->rawInBuf.Head != tty->rawInBuf.Tail) &&
(tty->ccount < (CBUFSIZE-1))) { (tty->ccount < (CBUFSIZE-1))) {
unsigned char c; unsigned char c;
@@ -1440,6 +1445,7 @@ fillBufferQueue (struct rtems_termios_tty *tty)
newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size; newHead = (tty->rawInBuf.Head + 1) % tty->rawInBuf.Size;
c = tty->rawInBuf.theBuf[newHead]; c = tty->rawInBuf.theBuf[newHead];
tty->rawInBuf.Head = newHead; tty->rawInBuf.Head = newHead;
if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size) if(((tty->rawInBuf.Tail-newHead+tty->rawInBuf.Size)
% tty->rawInBuf.Size) % tty->rawInBuf.Size)
< tty->lowwater) { < tty->lowwater) {
@@ -1461,22 +1467,30 @@ fillBufferQueue (struct rtems_termios_tty *tty)
} }
} }
rtems_termios_device_lock_release (ctx, &lock_context);
/* continue processing new character */ /* continue processing new character */
if (tty->termios.c_lflag & ICANON) { if (tty->termios.c_lflag & ICANON) {
if (siproc (c, tty)) if (siproc (c, tty))
wait = 0; wait = false;
} else { } else {
siproc (c, tty); siproc (c, tty);
if (tty->ccount >= tty->termios.c_cc[VMIN]) if (tty->ccount >= tty->termios.c_cc[VMIN])
wait = 0; wait = false;
} }
timeout = tty->rawInBufSemaphoreTimeout; timeout = tty->rawInBufSemaphoreTimeout;
rtems_termios_device_lock_acquire (ctx, &lock_context);
} }
rtems_termios_device_lock_release (ctx, &lock_context);
/* /*
* Wait for characters * Wait for characters
*/ */
if ( wait ) { if ( wait ) {
rtems_status_code sc;
sc = rtems_semaphore_obtain( sc = rtems_semaphore_obtain(
tty->rawInBuf.Semaphore, tty->rawInBufSemaphoreOptions, timeout); tty->rawInBuf.Semaphore, tty->rawInBufSemaphoreOptions, timeout);
if (sc != RTEMS_SUCCESSFUL) if (sc != RTEMS_SUCCESSFUL)
@@ -1555,7 +1569,6 @@ int
rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len) rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
{ {
struct rtems_termios_tty *tty = ttyp; struct rtems_termios_tty *tty = ttyp;
unsigned int newTail;
char c; char c;
int dropped = 0; int dropped = 0;
bool flow_rcv = false; /* true, if flow control char received */ bool flow_rcv = false; /* true, if flow control char received */
@@ -1620,12 +1633,19 @@ rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
rtems_termios_device_lock_release (ctx, &lock_context); rtems_termios_device_lock_release (ctx, &lock_context);
} }
} else { } else {
newTail = (tty->rawInBuf.Tail + 1) % tty->rawInBuf.Size; unsigned int head;
/* if chars_in_buffer > highwater */ unsigned int oldTail;
unsigned int newTail;
rtems_termios_device_lock_acquire (ctx, &lock_context); rtems_termios_device_lock_acquire (ctx, &lock_context);
if ((((newTail - tty->rawInBuf.Head + tty->rawInBuf.Size)
% tty->rawInBuf.Size) > tty->highwater) && head = tty->rawInBuf.Head;
!(tty->flow_ctrl & FL_IREQXOF)) { oldTail = tty->rawInBuf.Tail;
newTail = (oldTail + 1) % tty->rawInBuf.Size;
/* if chars_in_buffer > highwater */
if ((tty->flow_ctrl & FL_IREQXOF) != 0 && (((newTail - head
+ tty->rawInBuf.Size) % tty->rawInBuf.Size) > tty->highwater)) {
/* incoming data stream should be stopped */ /* incoming data stream should be stopped */
tty->flow_ctrl |= FL_IREQXOF; tty->flow_ctrl |= FL_IREQXOF;
if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF)) if ((tty->flow_ctrl & (FL_MDXOF | FL_ISNTXOF))
@@ -1647,15 +1667,12 @@ rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
} }
} }
/* reenable interrupts */ if (newTail != head) {
rtems_termios_device_lock_release (ctx, &lock_context);
if (newTail == tty->rawInBuf.Head) {
dropped++;
} else {
tty->rawInBuf.theBuf[newTail] = c; tty->rawInBuf.theBuf[newTail] = c;
tty->rawInBuf.Tail = newTail; tty->rawInBuf.Tail = newTail;
rtems_termios_device_lock_release (ctx, &lock_context);
/* /*
* check to see if rcv wakeup callback was set * check to see if rcv wakeup callback was set
*/ */
@@ -1663,6 +1680,9 @@ rtems_termios_enqueue_raw_characters (void *ttyp, const char *buf, int len)
(*tty->tty_rcv.sw_pfn)(&tty->termios, tty->tty_rcv.sw_arg); (*tty->tty_rcv.sw_pfn)(&tty->termios, tty->tty_rcv.sw_arg);
tty->tty_rcvwakeup = 1; tty->tty_rcvwakeup = 1;
} }
} else {
++dropped;
rtems_termios_device_lock_release (ctx, &lock_context);
} }
} }
} }