Changeset a165a96 in rtems


Ignore:
Timestamp:
02/23/17 14:43:41 (7 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
5, master
Children:
36635433
Parents:
c41b47e3
git-author:
Sebastian Huber <sebastian.huber@…> (02/23/17 14:43:41)
git-committer:
Sebastian Huber <sebastian.huber@…> (02/28/17 08:09:19)
Message:

termios: Make write POSIX compatible

Currently only blocking read/write operations are implemented. A
blocking write must transfer at least one character. It should not wait
for the device for the second character and so on.

Close #2917.

Files:
2 edited

Legend:

Unmodified
Added
Removed
  • cpukit/libcsupport/src/termios.c

    rc41b47e3 ra165a96  
    10211021 * Send characters to device-specific code
    10221022 */
    1023 static void
    1024 doTransmit (const char *buf, size_t len, rtems_termios_tty *tty)
     1023static size_t
     1024doTransmit (const char *buf, size_t len, rtems_termios_tty *tty,
     1025            bool wait, bool nextWait)
    10251026{
    10261027  unsigned int newHead;
     
    10281029  rtems_interrupt_lock_context lock_context;
    10291030  rtems_status_code sc;
     1031  size_t todo;
    10301032
    10311033  if (tty->handler.mode == TERMIOS_POLLED) {
    10321034    (*tty->handler.write)(ctx, buf, len);
    1033     return;
    1034   }
    1035 
    1036   while (len) {
     1035    return len;
     1036  }
     1037
     1038  todo = len;
     1039
     1040  while (todo > 0) {
    10371041    size_t nToCopy;
    10381042    size_t nAvail;
     
    10441048
    10451049    rtems_termios_device_lock_acquire (ctx, &lock_context);
    1046     while (newHead == tty->rawOutBuf.Tail) {
    1047       tty->rawOutBufState = rob_wait;
    1048       rtems_termios_device_lock_release (ctx, &lock_context);
    1049       sc = rtems_semaphore_obtain(
    1050         tty->rawOutBuf.Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    1051       if (sc != RTEMS_SUCCESSFUL)
    1052         rtems_fatal_error_occurred (sc);
    1053       rtems_termios_device_lock_acquire (ctx, &lock_context);
     1050    if (newHead == tty->rawOutBuf.Tail) {
     1051      if (wait) {
     1052        do {
     1053          tty->rawOutBufState = rob_wait;
     1054          rtems_termios_device_lock_release (ctx, &lock_context);
     1055          sc = rtems_semaphore_obtain(
     1056            tty->rawOutBuf.Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     1057          if (sc != RTEMS_SUCCESSFUL)
     1058            rtems_fatal_error_occurred (sc);
     1059          rtems_termios_device_lock_acquire (ctx, &lock_context);
     1060        } while (newHead == tty->rawOutBuf.Tail);
     1061      } else {
     1062        rtems_termios_device_lock_release (ctx, &lock_context);
     1063        return len - todo;
     1064      }
    10541065    }
    10551066
    10561067    /* Determine free space up to current tail or end of ring buffer */
    1057     nToCopy = len;
     1068    nToCopy = todo;
    10581069    if (tty->rawOutBuf.Tail > tty->rawOutBuf.Head) {
    10591070      /* Available space is contiguous from Head to Tail */
     
    10871098
    10881099    buf += nToCopy;
    1089     len -= nToCopy;
    1090   }
     1100    todo -= nToCopy;
     1101    wait = nextWait;
     1102  }
     1103
     1104  return len;
    10911105}
    10921106
     
    10951109  const void *_buf, size_t len, struct rtems_termios_tty *tty)
    10961110{
    1097   doTransmit (_buf, len, tty);
     1111  doTransmit (_buf, len, tty, true, true);
     1112}
     1113
     1114static bool
     1115canTransmit (rtems_termios_tty *tty, bool wait, size_t len)
     1116{
     1117  rtems_termios_device_context *ctx;
     1118  rtems_interrupt_lock_context lock_context;
     1119  unsigned int capacity;
     1120
     1121  if (wait || tty->handler.mode == TERMIOS_POLLED) {
     1122    return true;
     1123  }
     1124
     1125  ctx = tty->device_context;
     1126  rtems_termios_device_lock_acquire (ctx, &lock_context);
     1127  capacity = (tty->rawOutBuf.Tail - tty->rawOutBuf.Head - 1) %
     1128    tty->rawOutBuf.Size;
     1129  rtems_termios_device_lock_release (ctx, &lock_context);
     1130  return capacity >= len;
    10981131}
    10991132
     
    11011134 * Handle output processing
    11021135 */
    1103 static void
    1104 oproc (unsigned char c, struct rtems_termios_tty *tty)
     1136static bool
     1137oproc (unsigned char c, rtems_termios_tty *tty, bool wait)
    11051138{
    11061139  char buf[8];
     
    11191152        columnAdj = -oldColumn;
    11201153      if (tty->termios.c_oflag & ONLCR) {
     1154        len = 2;
     1155
     1156        if (!canTransmit (tty, wait, len)) {
     1157          return false;
     1158        }
     1159
    11211160        columnAdj = -oldColumn;
    11221161        buf[0] = '\r';
    11231162        buf[1] = c;
    1124         len = 2;
    11251163      }
    11261164      break;
     
    11281166    case '\r':
    11291167      if ((tty->termios.c_oflag & ONOCR) && (oldColumn == 0))
    1130         return;
     1168        return true;
    11311169      if (tty->termios.c_oflag & OCRNL) {
    11321170        buf[0] = '\n';
     
    11451183        len = (size_t) columnAdj;
    11461184
     1185        if (!canTransmit (tty, wait, len)) {
     1186          return false;
     1187        }
     1188
    11471189        for (i = 0; i < columnAdj; ++i) {
    11481190          buf[i] = ' ';
     
    11691211  }
    11701212
    1171   doTransmit (buf, len, tty);
     1213  return doTransmit (buf, len, tty, wait, true) > 0;
    11721214}
    11731215
    11741216static uint32_t
    1175 rtems_termios_write_tty (struct rtems_termios_tty *tty, const char *buffer,
    1176   uint32_t initial_count)
    1177 {
     1217rtems_termios_write_tty (rtems_termios_tty *tty, const char *buf, uint32_t len)
     1218{
     1219  bool wait = true;
    11781220
    11791221  if (tty->termios.c_oflag & OPOST) {
    1180     uint32_t count;
    1181 
    1182     count = initial_count;
    1183 
    1184     while (count--)
    1185       oproc (*buffer++, tty);
     1222    uint32_t todo = len;
     1223
     1224    while (todo > 0) {
     1225      if (!oproc (*buf, tty, wait)) {
     1226        break;
     1227      }
     1228
     1229      ++buf;
     1230      --todo;
     1231      wait = false;
     1232    }
     1233
     1234    return len - todo;
    11861235  } else {
    1187     doTransmit (buffer, initial_count, tty);
    1188   }
    1189 
    1190   return initial_count;
     1236    return doTransmit (buf, len, tty, wait, false);
     1237  }
    11911238}
    11921239
     
    12231270    echobuf[0] = '^';
    12241271    echobuf[1] = c ^ 0x40;
    1225     doTransmit (echobuf, 2, tty);
     1272    doTransmit (echobuf, 2, tty, true, true);
    12261273    tty->column += 2;
    12271274  } else {
    1228     oproc (c, tty);
     1275    oproc (c, tty, true);
    12291276  }
    12301277}
     
    12831330         */
    12841331        while (tty->column > col) {
    1285           doTransmit ("\b", 1, tty);
     1332          doTransmit ("\b", 1, tty, true, true);
    12861333          tty->column--;
    12871334        }
     
    12891336      else {
    12901337        if (iscntrl (c) && (tty->termios.c_lflag & ECHOCTL)) {
    1291           doTransmit ("\b \b", 3, tty);
     1338          doTransmit ("\b \b", 3, tty, true, true);
    12921339          if (tty->column)
    12931340            tty->column--;
    12941341        }
    12951342        if (!iscntrl (c) || (tty->termios.c_lflag & ECHOCTL)) {
    1296           doTransmit ("\b \b", 3, tty);
     1343          doTransmit ("\b \b", 3, tty, true, true);
    12971344          if (tty->column)
    12981345            tty->column--;
  • testsuites/libtests/termios09/init.c

    rc41b47e3 ra165a96  
    5656  int fds[DEVICE_COUNT];
    5757  struct termios term[DEVICE_COUNT];
     58  int context_switch_counter;
     59  rtems_id flush_task_id;
    5860} test_context;
    5961
     
    909911    clear_set_oflag(ctx, i, oflags, 0);
    910912  }
     913}
     914
     915static void
     916set_self_prio(rtems_task_priority prio)
     917{
     918  rtems_status_code sc;
     919
     920  sc = rtems_task_set_priority(RTEMS_SELF, prio, &prio);
     921  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     922}
     923
     924static void flush_task(rtems_task_argument arg)
     925{
     926  test_context *ctx = (test_context *) arg;
     927
     928  while (true) {
     929    set_self_prio(1);
     930    flush_output(ctx, INTERRUPT);
     931    set_self_prio(2);
     932  }
     933}
     934
     935static void test_write(test_context *ctx)
     936{
     937  tcflag_t oflags = OPOST | ONLCR | XTABS;
     938  rtems_status_code sc;
     939  size_t i = INTERRUPT;
     940  device_context *dev = &ctx->devices[i];
     941  char buf[OUTPUT_BUFFER_SIZE];
     942  ssize_t n;
     943
     944  ctx->context_switch_counter = 0;
     945
     946  sc = rtems_task_create(
     947    rtems_build_name('F', 'L', 'S', 'H'),
     948    2,
     949    RTEMS_MINIMUM_STACK_SIZE,
     950    RTEMS_DEFAULT_MODES,
     951    RTEMS_DEFAULT_ATTRIBUTES,
     952    &ctx->flush_task_id
     953  );
     954  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     955
     956  sc = rtems_task_start(
     957    ctx->flush_task_id,
     958    flush_task,
     959    (rtems_task_argument) ctx
     960  );
     961  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     962
     963  clear_output(ctx, i);
     964  memset(buf, 'a', OUTPUT_BUFFER_SIZE);
     965
     966  n = write(ctx->fds[i], &buf[0], OUTPUT_BUFFER_SIZE);
     967  rtems_test_assert(n == OUTPUT_BUFFER_SIZE - 1);
     968
     969  rtems_test_assert(ctx->context_switch_counter == 0);
     970
     971  n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 1], 1);
     972  rtems_test_assert(n == 1);
     973
     974  rtems_test_assert(ctx->context_switch_counter == 2);
     975  rtems_test_assert(dev->output_count == OUTPUT_BUFFER_SIZE);
     976  rtems_test_assert(memcmp(dev->output_buf, buf, OUTPUT_BUFFER_SIZE) == 0);
     977
     978  clear_set_oflag(ctx, i, 0, oflags);
     979
     980  /* Ensure that ONLCR output expansion is taken into account */
     981
     982  dev->tty->column = 0;
     983  clear_output(ctx, i);
     984  memset(buf, 'b', OUTPUT_BUFFER_SIZE - 1);
     985  buf[OUTPUT_BUFFER_SIZE - 2] = '\n';
     986
     987  n = write(ctx->fds[i], &buf[0], OUTPUT_BUFFER_SIZE - 3);
     988  rtems_test_assert(n == OUTPUT_BUFFER_SIZE - 3);
     989
     990  rtems_test_assert(ctx->context_switch_counter == 2);
     991
     992  n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 3], 2);
     993  rtems_test_assert(n == 1);
     994
     995  rtems_test_assert(ctx->context_switch_counter == 2);
     996
     997  n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 2], 1);
     998  rtems_test_assert(n == 1);
     999
     1000  rtems_test_assert(ctx->context_switch_counter == 4);
     1001  rtems_test_assert(dev->output_count == OUTPUT_BUFFER_SIZE);
     1002  buf[OUTPUT_BUFFER_SIZE - 2] = '\r';
     1003  buf[OUTPUT_BUFFER_SIZE - 1] = '\n';
     1004  rtems_test_assert(memcmp(dev->output_buf, buf, OUTPUT_BUFFER_SIZE) == 0);
     1005
     1006  /* Ensure that XTABS output expansion is taken into account */
     1007
     1008  dev->tty->column = 0;
     1009  clear_output(ctx, i);
     1010  memset(buf, 'c', OUTPUT_BUFFER_SIZE - 8);
     1011  buf[OUTPUT_BUFFER_SIZE - 8] = '\t';
     1012
     1013  n = write(ctx->fds[i], &buf[0], OUTPUT_BUFFER_SIZE - 9);
     1014  rtems_test_assert(n == OUTPUT_BUFFER_SIZE - 9);
     1015
     1016  rtems_test_assert(ctx->context_switch_counter == 4);
     1017
     1018  n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 9], 2);
     1019  rtems_test_assert(n == 1);
     1020
     1021  rtems_test_assert(ctx->context_switch_counter == 4);
     1022
     1023  n = write(ctx->fds[i], &buf[OUTPUT_BUFFER_SIZE - 8], 1);
     1024  rtems_test_assert(n == 1);
     1025
     1026  rtems_test_assert(ctx->context_switch_counter == 6);
     1027  rtems_test_assert(dev->output_count == OUTPUT_BUFFER_SIZE);
     1028  memset(&buf[OUTPUT_BUFFER_SIZE - 8], ' ', 8);
     1029  rtems_test_assert(memcmp(dev->output_buf, buf, OUTPUT_BUFFER_SIZE) == 0);
     1030
     1031  clear_set_oflag(ctx, i, oflags, 0);
     1032
     1033  sc = rtems_task_delete(ctx->flush_task_id);
     1034  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    9111035}
    9121036
     
    9331057  test_xtabs(ctx);
    9341058  test_olcuc(ctx);
     1059  test_write(ctx);
    9351060
    9361061  TEST_END();
     
    9381063}
    9391064
     1065static void switch_extension(Thread_Control *executing, Thread_Control *heir)
     1066{
     1067  test_context *ctx = &test_instance;
     1068
     1069  ++ctx->context_switch_counter;
     1070}
     1071
    9401072#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
    9411073#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
     
    9431075#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 5
    9441076
    945 #define CONFIGURE_MAXIMUM_TASKS 1
     1077#define CONFIGURE_MAXIMUM_TASKS 2
    9461078
    9471079#define CONFIGURE_MAXIMUM_SEMAPHORES 7
    9481080
    949 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
     1081#define CONFIGURE_INITIAL_EXTENSIONS \
     1082  { .thread_switch = switch_extension }, \
     1083  RTEMS_TEST_INITIAL_EXTENSION
    9501084
    9511085#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
Note: See TracChangeset for help on using the changeset viewer.