如何更改tcsetattr()的Linux中断计时器

时间:2015-03-27 04:18:49

标签: c linux timer

我正在使用serial port,在与此通信时,我必须使用tcsetattr()模式更改配置。

TCSDRAIN

在使用TCSADRAIN The change should take place after all output written to fd has been read by the master pseudoterminal. Use this value when changing terminal attributes that affect output. 调用tcsetattr()时,如果缓冲区中仍然存在输出数据,则Linux似乎被阻止,并在一段中断时间后再次检查缓冲区以更改配置。

我测试了这个,如下所示

  • 第一个Normall案件

    1. 将数据写入串行
    2. 使用tcsetattr()
    3. 更改配置
    4. 输出缓冲区中有剩余数据
    5. 在定期间隔期间阻止该过程,例如20ms
    6. 醒来。
  • 第二个案例

    1. 将数据写入串行
    2. 手动执行sleep()5ms,这意味着有足够的时间清除输出到Linux
    3. 没有剩余数据
    4. 使用tcsetattr()
    5. 更改配置
    6. 没有阻止

对我而言,中断时间太长,无法做我想要的事情

如何更改此中断计时器间隔? (在TCSDRAINUbuntu

1 个答案:

答案 0 :(得分:0)

我不认为termios结构的.cc[VTIME]字段会影响刷新超时,如果这就是你要求的那样。据我所知,它只影响read()行为。

但是,在放弃之前,有几种方法可以控制内核尝试排空/刷新的间隔。

一种选择是使用fcntl(fd, F_SETFL, O_NONBLOCK)(暂时)将描述符设置为非阻塞状态,并使用clock_gettime(CLOCK_MONOTONIC, &now)nanosleep()重试tcsetattr(fd, TCSADRAIN, &attrs)几次合适的时间间隔,直到成功为止。然后使用fcntl(fd, F_SETFL, 0)将描述符恢复为正常模式。如果tcsetattr()调用因errno == EWOULDBLOCK || errno == EAGAIN而失败,请使用tcsetattr(fd, TCSANOW, &attrs)放弃所有未读/未发送的数据。

请注意,我没有在RPi上测试过上面的内容!它可能不适用于某些特定的体系结构/串行端口驱动程序,因为可以将刷新/排出间隔硬编码到驱动程序中,并忽略描述符处于非阻塞模式的事实。然而,这将是一个错误,并且可以通过内核补丁修复。 (换句话说,这应该可行,但是一些串口驱动程序可能很糟糕,并且忽略上面的非阻塞性质,并且会阻塞直到一些未指定的间隔。)

另一个选择是使用计时器来发出信号。如果您安装了一个函数来处理没有SA_RESTART标志的信号,那么信号的传递将中断阻塞tcdrain() / tcflush() / tcsetattr()调用。 (如果进程使用多个线程,则应该在所有其他线程中阻塞信号,否则内核将只选择一个进程'线程来传递信号。如果它不是阻塞调用中的线程,则阻塞调用不会被打断。)

因为信号是一种非常可靠的方法来中断大多数系统调用和库函数(参见{em>信号处理程序中断系统调用和库函数} - termios函数相当于ioctl()在Linux中调用),我个人更喜欢有一个单独的线程,除了维持这些超时之外什么都不做。这样的线程非常轻量级,除非超时或添加超时,否则不占用CPU时间。我还可以有多个并发超时,具有检查,取消和添加超时的简单界面,这使得设计其余应用程序变得更加容易和高效。