如何更改tcsetattr Linux的中断定时器() [英] How to change Linux interrupt timer for tcsetattr()

查看:245
本文介绍了如何更改tcsetattr Linux的中断定时器()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用串口,在这个沟通,我一直在使用更改配置 tcsetattr() TCSDRAIN 模式。

  TCSADRAIN
    写到FD所有输出已经由主读伪终端后的变化应该发生。更改影响输出终端属性时,请使用此值。

和同时呼吁 tcsetattr() TCSDRAIN ,如果还停留在缓冲区中的输出数据,Linux的似乎受阻和一些中断时间后再次检查缓冲区更改配置。

我测试了这个像下面


  • 首先Normall案例


    1. 将数据写入到串行

    2. 使用tcsetattr()更改配置

    3. 有输出缓冲器的剩余数据

    4. 常规时间间隔内阻塞,例如20ms的过程

    5. 唤醒。


  • 第二个案例


    1. 将数据写入到串行

    2. 采取睡眠()手动为5毫秒,这意味着给予足够的时间来清除输出到Linux

    3. 没有剩余数据

    4. 使用tcsetattr()更改配置

    5. 没有块


对于我来说,中断时间太长,做我想做

我怎样才能改变这种定时器中断间隔?
(在的Ubuntu 树莓派


解决方案

我不认为的 .CC [VTIME] termios结构的影响领域冲洗超时,如果这是你的要求。据我所知,它仅影响阅读()行为。

然而,有几种方法可以控制内核试图排水/冲洗的时间间隔,放弃之前。

一种选择是使用 的fcntl(FD ,F_SETFL,O_NONBLOCK) 来(暂时)设置描述符非阻塞的状态,并且使用的 clock_gettime(CLOCK_MONOTONIC,&安培;现在) 和的 了nanosleep() 重试 tcsetattr(FD,TCSADRAIN,&安培; ATTRS)在一个合适的时间间隔几次,直到成功为止。然后,使用的fcntl恢复描述符到正常模式(FD,F_SETFL,0)。如果 tcsetattr()通话与的errno == EWOULDBLOCK失败||错误号== EAGAIN ,使用 tcsetattr(FD,TCSANOW,&安培; ATTRS)来放弃所有未读/未发送的数据

请注意,我没有测试RPI以上!它可能无法在一些具体的体系结构/串行端口驱动器的工作,因为这是可能的硬code中的冲洗/漏极间隔插入到驱动器和不顾事实描述符是在非阻塞模式。这将是一个错误,但是,是可以解决一个内核补丁。 (换言之,这应该工作,但某些串行端口驱动器可以是糟糕,并且忽略上述非阻塞性质,并且将阻塞,直到一些未指定的间隔。)

另一种选择是使用一个计时器来提高的信号。如果你安装了一个函数来处理,而不 SA_RESTART 标志信号,信号的传送将中断阻塞 tcdrain() / tcflush() / tcsetattr()电话。 (如果该过程使用多个线程,该信号应该阻止在所有其他线程,否则内核将只挑选方法的一个线程来传递信号,如果它不是一个阻塞调用,该阻塞调用线程不会中断。)

由于信号中断系统调用大部分和库函数的一个非常可靠的方法(见的系统调用和库函数信号处理程序中断的中的人7信号 - termios的功能等同于的ioctl()调用在Linux中),我亲自preFER到有一个单独的线程做什么,但维持这些超时。这样的线程是非常轻量级的,除非超时时间或加不占用CPU时间。我也可以有多个并发的超时,用一个简单的界面来检查,取消,并添加超时,这使得它更容易设计应用程序的其余部分是可靠和有效的。

I am using serial port, and while communicating with this, i have to change the configuration using tcsetattr() with TCSDRAIN mode.

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.

And while calling tcsetattr() with TCSDRAIN, if there still remain output data in buffer, Linux seems blocked and check the buffer again after a some interrupt time to change a configuration.

I tested for this like below

  • First Normall Case

    1. write data to serial
    2. change configuration using tcsetattr()
    3. there is a remaining data in output buffer
    4. the process blocked during regular interval, for example 20ms
    5. wake up.

  • Second Case

    1. write data to serial
    2. take sleep() manually for 5ms, it means give enough time to clear output to Linux
    3. there is no remaining data
    4. change configuration using tcsetattr()
    5. there is no block

And for me the interrupt time is too long to do what i want

How can i change this interrupt timer interval? (in Ubuntu and raspberrypi)

解决方案

I do not think that the .cc[VTIME] field of the termios structure affects the flush timeout, if that's what you are asking. As far as I know, it only affects the read() behaviour.

However, there are several ways you can control the interval the kernel tries to drain/flush, before giving up.

One option is to use fcntl(fd, F_SETFL, O_NONBLOCK) to (temporarily) set the descriptor to non-blocking state, and use clock_gettime(CLOCK_MONOTONIC, &now) and nanosleep() to retry tcsetattr(fd, TCSADRAIN, &attrs) a few times over a suitable time interval, until it succeeds. Then revert the descriptor to normal mode using fcntl(fd, F_SETFL, 0). If the tcsetattr() calls failed with errno == EWOULDBLOCK || errno == EAGAIN, use tcsetattr(fd, TCSANOW, &attrs) to discard all unread/unsent data.

Note that I have not tested the above on RPi! It might not work on some specific architectures/serial port drivers, as it is possible to hardcode the flush/drain interval into the driver and disregard the fact that the descriptor is in non-blocking mode. That would be a bug, however, and is fixable with a kernel patch. (In other words, this should work, but some serial port drivers may be crappy, and ignore the nonblocking nature above, and will block until some unspecified interval.)

Another option is to use a timer to raise a signal. If you install a function to handle that signal without the SA_RESTART flag, the delivery of the signal will interrupt the blocking tcdrain()/tcflush()/tcsetattr() call. (If the process uses multiple threads, the signal should be blocked in all other threads, as otherwise the kernel will just pick one of the process' threads to deliver the signal. If it is not the thread in a blocking call, the blocking call will not be interrupted.)

Because signals are a very reliable method to interrupt most syscalls and library functions (see section Interruption of system calls and library functions by signal handlers in man 7 signal -- termios functions are equivalent to ioctl() calls in Linux), I personally prefer to have a separate thread do nothing but maintain these timeouts. Such a thread is very lightweight, and does not consume CPU time unless a timeout elapses or is added. I can also have multiple concurrent timeouts, with a simple interface to check, cancel, and add timeouts, which makes it easier to design the rest of the application to be robust and efficient.

这篇关于如何更改tcsetattr Linux的中断定时器()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆