真实面经题目 · 原创解析
Linux 驱动如何用异步通知把设备数据准备好这件事通知用户程序?
这题考 Linux 驱动事件通知机制,回答要讲清用户进程开启异步通知、驱动维护 fasync 队列、数据就绪时发送信号并由用户再读取数据。
真实面经题目 · 原创解析
这题考 Linux 驱动事件通知机制,回答要讲清用户进程开启异步通知、驱动维护 fasync 队列、数据就绪时发送信号并由用户再读取数据。
驱动异步通知可以理解成:用户程序先告诉内核“这个文件描述符有事件时通知我”。用户态通常打开设备后用 fcntl 设置 F_SETOWN 为当前进程,再设置 O_ASYNC。驱动的 file_operations 里实现 .fasync,在里面调用 fasync_helper,把当前文件和进程关系挂到驱动维护的 fasync 队列。之后设备中断或底半部发现数据准备好时,不是直接把数据塞给用户,而是调用 kill_fasync 发送 SIGIO,并带上 POLL_IN 等事件类型。用户态收到信号后再调用 read 或用 signalfd 处理,把数据真正读走。面试里要强调异步通知只是事件提醒,不是可靠数据队列;仍要处理并发、缓冲区、丢信号、进程退出和 close 时从 fasync 队列移除,实际项目常和 poll/epoll、wait queue 一起设计。
应用打开设备文件后设置 owner 和 O_ASYNC,告诉内核该文件描述符发生异步事件时向哪个进程或进程组发信号。没有这个订阅动作,驱动即使调用通知也找不到目标。
驱动实现 .fasync 回调,并用 fasync_helper 维护 fasync_struct 链表。open/close 或标志变化时都会更新这条链,避免进程退出后仍通知旧对象。
中断处理或工作线程发现缓冲区有数据后,调用 kill_fasync 发送 SIGIO。信号告诉应用可以读,但数据仍在驱动缓冲区里,应用必须继续 read 才能消费。
信号可能合并,不能把每个信号等同于一条数据。驱动要用环形缓冲或队列保存数据,用锁保护状态,并支持 poll/阻塞 read 作为更稳妥的事件消费方式。
异步通知通过信号主动提醒进程;poll/epoll 是应用等待文件描述符就绪。实际项目中 epoll 更容易统一管理多个 fd,异步信号要小心处理重入和信号合并。
不建议。传统信号处理函数可安全调用的函数有限,常见做法是记录标志、写 eventfd,或用 signalfd 在主循环里处理。
我会先看 dmesg 和返回码,再查 /sys 下设备、驱动和资源状态,必要时加 trace/ftrace 或最小日志,先证明问题出在设备生成、匹配、资源获取、回调路径还是用户态交互。