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

文档信息

前言

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

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

2.  Oracle Solaris 内核和设备树

3.  多线程

4.  属性

5.  管理事件和排队任务

管理事件

事件介绍

使用 ddi_log_sysevent() 记录事件

ddi_log_sysevent() 语法

记录事件的样例代码

定义事件特性

排队任务

任务队列简介

任务队列接口

观察任务队列

任务队列内核统计信息计数器

任务队列 DTrace SDT 探测器

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.  Oracle Solaris DDI/DKI 服务汇总

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

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

E.  pci.conf 文件

索引

请告诉我们如何提高我们的文档:
过于简略
不易阅读或难以理解
重要信息缺失
错误的内容
需要翻译的版本
其他
Your rating has been updated
感谢您的反馈!

您的反馈将非常有助于我们提供更好的文档。 您是否愿意参与我们的内容改进并提供进一步的意见?

排队任务

本节讨论如何使用任务队列来延迟处理某些任务并将这些任务的执行委托给另一个内核线程。

任务队列简介

内核编程中的一项常见操作是对某个任务进行调度,使它以后由另一线程执行。以下示例给出了可能需要以后由另一线程执行某个任务的一些原因:

对于上面的每种情况,任务都在不同的上下文中执行。不同的上下文通常是持有一组不同锁的不同内核线程,并可能具有不同的优先级。任务队列提供一个通用内核 API 来调度异步任务。

任务队列是一个任务列表,一个或多个线程为该列表提供服务。如果任务队列只有一个服务线程,则所有任务肯定会按照它们在列表中添加的先后顺序执行。如果任务队列有多个服务线程,则任务的执行顺序是未知的。


注 - 如果任务队列有多个服务线程,请确保某个任务的执行不依赖于其他任何任务的执行。任务之间的相关性会导致产生死锁。


任务队列接口

以下 DDI 接口管理任务队列。这些接口在 sys/sunddi.h 头文件中定义。有关这些接口的更多信息,请参见 taskq(9F) 手册页。

ddi_taskq_t
不透明句柄
TASKQ_DEFAULTPRI
系统缺省优先级
DDI_SLEEP
可以阻塞以获得内存
DDI_NOSLEEP
不能阻塞以获得内存
ddi_taskq_create()
创建任务队列
ddi_taskq_destroy()
销毁任务队列
ddi_taskq_dispatch()
在任务队列中添加任务
ddi_taskq_wait()
等待暂挂的任务完成
ddi_taskq_suspend()
暂挂任务队列
ddi_taskq_suspended()
检查任务队列是否已暂挂
ddi_taskq_resume()
恢复暂挂的任务队列

观察任务队列

在驱动程序中的典型应用是在调用 attach(9E) 时创建任务队列。大多数 taskq_dispatch() 调用都来自中断上下文。

本节介绍两种可用来监视任务队列所使用的系统资源的方法。任务队列会导出任务队列线程使用系统时间的相关统计信息。任务队列还会使用 DTrace SDT 探测器来确定任务队列何时开始执行某个任务,以及何时完成执行。

任务队列内核统计信息计数器

每个任务队列都有一组关联的 kstat 计数器。检查以下 kstat(1M) 命令的输出:

$ kstat -c taskq
module: unix                            instance: 0     
name:   ata_nexus_enum_tq               class:    taskq
        crtime                          53.877907833
        executed                        0
        maxtasks                        0
        nactive                         1
        nalloc                          0
        priority                        60
        snaptime                        258059.249256749
        tasks                           0
        threads                         1
        totaltime                       0

module: unix                            instance: 0     
name:   callout_taskq                   class:    taskq
        crtime                          0
        executed                        13956358
        maxtasks                        4
        nactive                         4
        nalloc                          0
        priority                        99
        snaptime                        258059.24981709
        tasks                           13956358
        threads                         2
        totaltime                       120247890619

以上所示的 kstat 输出包含以下信息:

以下示例说明如何使用 kstat 命令来观察计数器(已调度任务的数目)是如何随时间而递增的:

$ kstat -p unix:0:callout_taskq:tasks 1 5
unix:0:callout_taskq:tasks      13994642

unix:0:callout_taskq:tasks      13994711

unix:0:callout_taskq:tasks      13994784

unix:0:callout_taskq:tasks      13994855

unix:0:callout_taskq:tasks      13994926

任务队列 DTrace SDT 探测器

任务队列提供了若干个有用的 SDT 探测器。本节介绍的所有探测器都具有以下两个参数:

可以使用这些探测器来收集有关各个任务队列以及通过这些队列执行的各个任务的精确计时信息。例如,以下脚本每隔 10 秒列显通过任务队列调度的函数:

# !/usr/sbin/dtrace -qs

sdt:genunix::taskq-enqueue
{
  this->tq  = (taskq_t *)arg0;
  this->tqe = (taskq_ent_t *) arg1;
  @[this->tq->tq_name,
    this->tq->tq_instance,
    this->tqe->tqent_func] = count();
}

tick-10s
{
  printa ("%s(%d): %a called %@d times\n", @);
  trunc(@);
}

在特定的计算机上,以上 D 脚本生成以下输出:

callout_taskq(1): genunix`callout_execute called 51 times
callout_taskq(0): genunix`callout_execute called 701 times
kmem_taskq(0): genunix`kmem_update_timeout called 1 times
kmem_taskq(0): genunix`kmem_hash_rescale called 4 times
callout_taskq(1): genunix`callout_execute called 40 times
USB_hid_81_pipehndl_tq_1(14): usba`hcdi_cb_thread called 256 times
callout_taskq(0): genunix`callout_execute called 702 times
kmem_taskq(0): genunix`kmem_update_timeout called 1 times
kmem_taskq(0): genunix`kmem_hash_rescale called 4 times
callout_taskq(1): genunix`callout_execute called 28 times
USB_hid_81_pipehndl_tq_1(14): usba`hcdi_cb_thread called 228 times
callout_taskq(0): genunix`callout_execute called 706 times
callout_taskq(1): genunix`callout_execute called 24 times
USB_hid_81_pipehndl_tq_1(14): usba`hcdi_cb_thread called 141 times
callout_taskq(0): genunix`callout_execute called 708 times