';关闭';linux中串行端口描述符块上的函数

';关闭';linux中串行端口描述符块上的函数,linux,serial-port,embedded-linux,Linux,Serial Port,Embedded Linux,最近我发现了一个对我来说很新的问题,我非常感谢你的建议。我正在Linux上使用termios函数进行串行通信。我实际上不使用真正的串行端口,而是使用虚拟小工具串行驱动程序/dev/ttyGS0。文件描述符以非阻塞方式打开 我的程序定期生成数据并将其发送到/dev/ttyGS0。如果另一端读取或不读取,则没有信息。否则,一些内部fifo将填满,写入返回“将阻塞”错误。到目前为止一切都很好,我对此没有任何问题 问题是,当我想用填充的fifo关闭这样的文件描述符时,关闭函数块!不是无限期,而是大约10

最近我发现了一个对我来说很新的问题,我非常感谢你的建议。我正在Linux上使用termios函数进行串行通信。我实际上不使用真正的串行端口,而是使用虚拟小工具串行驱动程序
/dev/ttyGS0
。文件描述符以非阻塞方式打开

我的程序定期生成数据并将其发送到/dev/ttyGS0。如果另一端读取或不读取,则没有信息。否则,一些内部fifo将填满,写入返回“将阻塞”错误。到目前为止一切都很好,我对此没有任何问题

问题是,当我想用填充的fifo关闭这样的文件描述符时,关闭函数块!不是无限期,而是大约10秒钟

我试图在关闭之前执行
tcflush(uart->fd,tcflush)
,但没有任何效果


这对我来说是如此奇怪的行为,我没有发现任何描述,以至于关闭可能会阻塞。有没有办法避免这种情况?或者至少减少这个超时?我应该在哪里查找此超时?VTIME属性对此也没有影响。

正如Amardeep提到的,close()调用由驱动程序处理。Close本身总是阻塞调用,但通常是快速调用

因此,答案是延迟是特定于虚拟小工具驱动程序的。我没有这方面的经验


关闭文件有多重要?如果延迟是一个主要问题,并且需要关闭文件(例如在长时间运行的进程中避免文件描述符泄漏),那么可能需要在单独的线程中调用关闭。显然,最好的答案是针对那个司机的;也许那里的研究可能会给出一个答案,比如一个ioctl()调用,它会清除虚拟设备的状态。

我也面临同样的问题,在我的情况下,在关闭设备之前禁用flowcontrol会有所帮助。可以使用以下功能执行此操作:

int set_flowcontrol(int fd, int control) 
{
    struct termios tty;
    memset(&tty, 0, sizeof tty);
    if (tcgetattr(fd, &tty) != 0) 
    {
        perror("error from tggetattr");
        return -1;
    }

    if(control) tty.c_cflag |= CRTSCTS;
    else tty.c_cflag &= ~CRTSCTS;

    if (tcsetattr(fd, TCSANOW, &tty) != 0)
    {
        perror("error setting term attributes");
        return -1;
    }
    return 0;
}
请在结束前打电话:

...
rc = set_flowcontrol(fd, 0);
if (rc != 0)
{
    perror("error setting flowcontrol: ");
    exit(-1);
}

rc = close(fd);
if (rc != 0)
{
    perror("error closing fd: ");
    exit(-1);
}
...

您可能需要配置端口的closing_wait参数。从setserial手册:

关闭\u等待延迟 指定内核等待数据传输的时间量(百分之一秒) 串行端口正在运行 关闭端口。如果指定“无”,则不会发生延迟。如果指定“无限”,内核将等待 无限期 要传输的缓冲数据。默认设置为3000秒或30秒延迟。此默认值通常为 适合大多数人 设备。如果选择的延迟太长,则如果使用 未连接,以及 已挂起数据,已关闭。如果选择的延迟太短,则存在部分传输数据丢失的风险 输出。 如果设备速度非常慢(如绘图仪),关闭等待时间可能需要更长

使用setserial检查端口的参数:

$ setserial -g -a /dev/ttyS0
/dev/ttyS0, Line 0, UART: 16550A, Port: 0x03f8, IRQ: 4
        Baud_base: 115200, close_delay: 50, divisor: 0
        closing_wait: 3000
        Flags: spd_normal skip_test
在我的例子中,发生故障的设备没有收到我发送的最后一个字节,因此关闭端口总是需要30秒。例如,您可以使用setserial将此超时更改为1秒:

$ sudo setserial /dev/ttyS0 closing_wait 100

当然,您可能希望在启动时在/etc/rc.local或发行版用于配置端口的任何脚本中发出此命令。

close()映射到设备驱动程序中的调用,该调用可能会发生延迟。如果你有驱动程序的源代码,你可以修改它的行为。还要查找该设备支持的任何自定义ioctl()调用,这些调用可能允许修改行为。我认为,在飞行数据的情况下,
close()
会阻塞—并且我不认为非阻塞IO的POSIX语义也会扩展到
close()
。我希望在
close()
之后,设备将处于启动状态,准备再次
open()
启动。由于这是通过USB的虚拟串行,我开始怀疑端点的无序破坏,10秒是超时。