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 文件

索引

锁定原语

在传统 UNIX 系统中,可以通过显式调用 sleep(1) 以放弃处理器或通过硬件中断来终止内核代码的每个部分。Oracle Solaris OS 的运行方式与此不同。系统可随时抢占内核线程以运行其他线程。由于所有内核线程共享内核地址空间,并且通常需要读取和修改相同的数据,因此内核提供了大量的锁定原语以防止线程损坏共享数据。这些机制包括互斥锁、读取器/写入器锁以及信号量。

驱动程序数据的存储类

数据的存储类用于指示驱动程序是否需要采取显式步骤控制对数据的访问。共有三个数据存储类:

互斥锁

互斥锁 (mutex) 通常与一组数据关联,并控制对这些数据的访问。互斥锁提供了一种一次仅允许一个线程访问这些数据的方法。互斥锁函数包括:

mutex_destroy(9F)

释放任何关联的存储空间。

mutex_enter(9F)

获取互斥锁。

mutex_exit(9F)

释放互斥锁。

mutex_init(9F)

初始化互斥锁。

mutex_owned(9F)

测试以确定当前线程是否持有互斥锁。仅限于在 ASSERT(9F) 中使用。

mutex_tryenter(9F)

获取互斥锁(如果可用),但不阻塞。

设置互斥锁

设备驱动程序通常会为每个驱动程序数据结构分配一个互斥锁。互斥锁通常是该结构中类型为 kmutex_t 的字段。调用 mutex_init(9F) 以初始化要使用的互斥锁。通常在执行 attach(9E) 时为每个设备互斥锁进行此调用,在执行 _init(9E) 时为全局驱动程序互斥锁进行此调用。

例如,

struct xxstate *xsp;
/* ... */
mutex_init(&xsp->mu, NULL, MUTEX_DRIVER, NULL);
/* ... */

有关互斥锁初始化的较完整示例,请参见第 6 章

驱动程序在卸载之前必须使用 mutex_destroy(9F) 销毁互斥锁。通常在执行 detach(9E) 时为每个设备互斥锁进行销毁操作,在执行 _fini(9E) 时为全局驱动程序互斥锁进行销毁操作。

使用互斥锁

驱动程序如果需要读写共享数据结构,必须执行以下操作:

互斥锁的作用域(即互斥锁保护的数据)完全由程序员决定。仅当访问数据结构的每个代码路径都保护数据结构并且同时持有互斥锁时,互斥锁才会保护该数据结构。

读取器/写入器锁

读取器/写入器锁可控制对数据集的访问。读取器/写入器锁之所以这样命名,是由于许多线程可同时持有读锁,但仅有一个线程可持有写锁。

大多数设备驱动程序不使用读取器/写入器锁。这些锁的速度比互斥锁要慢。这些锁仅当保护通常进行读取但不经常写入的数据时才会提高性能。在此情况下,对互斥锁的争用可能会成为一个瓶颈,因此使用读取器/写入器锁效率可能更高。下表概述了读取器/写入器函数。有关详细信息,请参见 rwlock(9F) 手册页。读取器/写入器锁函数包括:

rw_destroy(9F)

销毁读取器/写入器锁

rw_downgrade(9F)

将读取器/写入器锁的持有者从写入器降级为读取器

rw_enter(9F)

获取读取器/写入器锁

rw_exit(9F)

释放读取器/写入器锁

rw_init(9F)

初始化读取器/写入器锁

rw_read_locked(9F)

确定是否持有用于读/写操作的读取器/写入器锁

rw_tryenter(9F)

尝试在无需等待的情况下获取读取器/写入器锁

rw_tryupgrade(9F)

尝试将读取器/写入器锁的持有者从读取器升级为写入器

信号

计数信号量可用作管理设备驱动程序中线程的替代原语。有关更多信息,请参见 semaphore(9F) 手册页。信号函数包括:

sema_destroy(9F)

销毁信号。

sema_init(9F)

初始化信号。

sema_p(9F)

减小信号,可能会阻塞。

sema_p_sig(9F)

减小信号,但不会阻塞(如果信号处于待处理状态)。请参见线程无法接收信号

sema_tryp(9F)

尝试减小信号,但不阻塞。

sema_v(9F)

增加信号,可能会解除阻塞等待者。