JavaScript is required to for searching.
跳过导航链接
退出打印视图
编写设备驱动程序     Oracle Solaris 10 1/13 Information Library (简体中文)
search filter icon
search icon

文档信息

前言

第 1 部分针对 Oracle Solaris 平台设计设备驱动程序

1.  Oracle Solaris 设备驱动程序概述

2.  Oracle Solaris 内核和设备树

3.  多线程

锁定原语

驱动程序数据的存储类

互斥锁

设置互斥锁

使用互斥锁

读取器/写入器锁

信号

线程同步

线程同步中的条件变量

初始化条件变量

等待条件

发出条件信号

cv_wait()cv_timedwait() 函数

cv_wait_sig() 函数

cv_timedwait_sig() 函数

选择锁定方案

潜在的锁定缺点

线程无法接收信号

4.  属性

5.  管理事件和排队任务

6.  驱动程序自动配置

7.  设备访问:程控 I/O

8.  中断处理程序

9.  直接内存访问 (Direct Memory Access, DMA)

10.  映射设备和内核内存

11.  设备上下文管理

12.  电源管理

13.  强化 Oracle Solaris 驱动程序

14.  分层驱动程序接口 (Layered Driver Interface, LDI)

第 2 部分设计特定种类的设备驱动程序

15.  字符设备驱动程序

16.  块设备驱动程序

17.  SCSI 目标驱动程序

18.  SCSI 主机总线适配器驱动程序

19.  网络设备驱动程序

20.  USB 驱动程序

21.  SR-IOV 驱动程序

第 3 部分生成设备驱动程序

22.  编译、装入、打包和测试驱动程序

23.  调试、测试和调优设备驱动程序

24.  推荐的编码方法

第 4 部分附录

A.  硬件概述

B.  Solaris DDI/DKI 服务汇总

C.  使设备驱动程序支持 64 位

D.  控制台帧缓存器驱动程序

E.  pci.conf 文件

索引

选择锁定方案

在设计大多数设备驱动程序时,都应该确保锁定方案简单易懂。使用额外的锁允许更多并发,但会增加开销。使用的锁越少,占用的时间越短,但允许的并发会更少。通常,对每个数据结构使用一个互斥锁,对驱动程序必须等待的每个事件或条件使用一个条件变量,对驱动程序的每个主要全局数据集使用一个互斥锁。请避免长时间持有互斥锁。选择锁定方案时,请遵循以下指导原则:

要查看锁的用法,请使用 lockstat(1M)lockstat(1M) 可监视所有内核锁定事件、收集有关事件的频率和计时数据,并显示这些数据。

有关多线程操作的更多详细信息,请参见《多线程编程指南》

潜在的锁定缺点

同一线程不可重复获取互斥锁。如果已持有互斥锁,则再次尝试声明此互斥锁会导致产生以下故障消息:

panic: recursive mutex_enter. mutex %x caller %x

释放当前线程未持有的互斥锁会产生以下故障消息:

panic: mutex_adaptive_exit: mutex not held by thread

以下故障消息仅在单处理器上出现:

panic: lock_set: lock held and only one CPU

lock_set 故障消息指明线程持有自旋互斥锁 (spin mutex),并且该锁将会永久旋转,因为没有其他 CPU 可以释放此互斥锁。如果驱动程序忘记释放某个代码路径上的互斥锁,或在持有互斥锁时阻塞,则会发生此情况。

具有高级中断的设备所调用的例程(如 cv_wait(9F))阻塞时通常会导致出现 lock_set 故障消息。另一个常见原因是高级处理程序通过调用 mutex_enter(9F) 获取自适应互斥锁。

线程无法接收信号

线程收到信号时,可以唤醒 sema_p_sig()cv_wait_sig()cv_timedwait_sig() 函数。由于某些线程无法接收信号,因此可能会出现问题。例如,如果由于应用程序调用 close(2) 而导致调用 close(9E),则可以收到信号。但是,如果是从 exit(2) 处理(关闭所有打开的文件描述符)中调用 close(9E),则线程无法收到信号。如果线程无法收到信号,则 sema_p_sig() 的行为与 sema_p() 相同,cv_wait_sig() 的行为与 cv_wait() 相同,cv_timedwait_sig() 的行为与 cv_timedwait() 相同。

对于可能永远不会发生的事件,请注意避免永久休眠。永远不会发生的事件会创建不可中止 (defunct) 的线程并使设备不可用,除非重新引导系统。失效进程无法接收信号。

要检测当前线程是否可接收信号,请使用 ddi_can_receive_sig(9F) 函数。如果 ddi_can_receive_sig() 函数返回 B_TRUE,则以上函数可在收到信号时唤醒。如果 ddi_can_receive_sig() 函数返回 B_FALSE,则以上函数无法在收到信号时唤醒。如果 ddi_can_receive_sig() 函数返回 B_FALSE,则驱动程序会使用替代方法(如 timeout(9F) 函数)重新唤醒。

出现此问题的一个重要情况是使用串行端口。如果远程系统声明了流量控制,并且 close(9E) 函数在尝试清空输出数据时阻塞,则端口会堵塞,直到解决流量控制情况或重新引导系统为止。此类驱动程序应检测到此情况并设置计时器,以便在流量控制情况持续过长时间时中止清空操作。

此问题还会影响 qwait_sig(9F) 函数。此函数将在《STREAMS Programming Guide》中的第 7  章 "STREAMS Framework – Kernel Level"中介绍。