Reh*_*b11 2 linux signals serial-port linux-kernel interrupt-handling
我有两个设备通过串行端口相互连接。一个作为主人,另一个作为奴隶。
主设备是一个基于 ARM 的套件,运行 Linux。
目前的情况是master发送命令然后轮询com端口直到slave回复。
现在我不想使用轮询。我需要处理器执行其他任务,直到从机回复。
我知道解决方案是使用中断,但找不到更多详细信息。我找到了一些使用信号的解决方案。它以非阻塞模式读取 tty,然后在数据准备好时发送 io 信号。
那么,串行通信中中断和信号有什么区别呢?当使用中断时我应该编写设备驱动程序或内核模块等吗?为了不使用轮询,还有其他有效的解决方案吗?
为了不使用轮询,还有其他有效的解决方案吗?
前段时间我遇到了同样的任务,我发现解决它的最好方法是使用pthreads。基本上,我接下来做了:
pthread_cond_signal()pthread_cond_wait()函数);一旦醒来——从循环缓冲区读取新数据(消耗数据)并正确处理它poll()。如果您不需要这个——您可以以阻塞模式打开串行端口,然后仅使用阻塞read()调用(如@sawdust 在评论中建议的那样)这样你就不会浪费CPU时间等待新数据到达,同时你也不需要弄乱信号(使用信号有很多复杂性,所以我决定避免它)。
唯一执行异步读取的其他 API 是POSIX AIO接口中的aio_read()。但据我了解,基于信号。唯一的区别是:aio_read()
SIGIO信号告诉你有新数据可供读取,需要你手动读取aio_read()为您提供读取数据(同样read(),只是异步)。我不建议您使用它,因为这个 API 似乎并不广泛,并且与信号驱动方法相比没有任何好处。
那么,串行通信中中断和信号有什么区别呢?
换句话说,当你的串口硬件产生中断时,它会在内核中处理,并且内核产生SIGIO信号,通知你的用户空间应用程序有新事件(例如,有新数据可供读取)。
当使用中断时我应该编写设备驱动程序或内核模块等吗?
通常是的,您只能在内核中处理中断。但在这种情况下你不需要。它已经在内核中为您完成,更具体地说,在行规则代码中。它为您生成信号(当发生中断时),您可以在用户空间应用程序中使用该信号。
如果您想要一些详细信息:
tty_schedule_flip()-> queue_work(...)-> flush_to_ldisc()-> receive_buf()-> tty_ldisc_receive_buf()->.receive_buf2()n_tty_receive_buf2()-> n_tty_receive_buf_common()->__receive_buf()__receive_buf()做:
if (read_cnt(ldata)) {
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
}
Run Code Online (Sandbox Code Playgroud)它发送SIGIO信号,如下所示:kill_fasync()-> kill_fasync_rcu()-> send_sigio()-> send_sigio_to_task()-> do_send_sig_info()->send_signal()
因此,当串口驱动程序中发生相应的中断时,您可以依靠内核向您传递消息(通过信号)。
[2] TTY 揭秘
[3] LDD3:异步通知