aboutsummaryrefslogtreecommitdiff
path: root/zh_CN.GB2312/books/arch-handbook/sysinit/chapter.xml
blob: f62316c6e46467070559de1d51a15c13afb9ccad (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
<?xml version="1.0" encoding="gb2312"?>
<!--
     The FreeBSD Documentation Project
     The FreeBSD Simplified Chinese Project

     Original Revision: 1.12
     $FreeBSD$
-->

<chapter id="sysinit">
  <chapterinfo>
    <authorgroup>
      <author>
        &author.cn.intron;
        <contrib>&cnproj.translated.by;</contrib>
      </author>
    </authorgroup>
  </chapterinfo>
  <title>SYSINIT框架</title>

  <indexterm><primary>SYSINIT(系统初始化)</primary></indexterm>
  <indexterm><primary>dynamic initialization(动态初始化)</primary></indexterm>
  <indexterm><primary>kernel initialization(内核初始化)</primary>
    <secondary>dynamic(动态)</secondary></indexterm>
  <indexterm><primary>kernel modules(内核模块)</primary></indexterm>
  <indexterm><primary>kernel linker(内核链接器)</primary></indexterm>

  <para>SYSINIT是一个通用的调用排序与分别执行机制的框架。
    FreeBSD目前使用它来进行内核的动态初始化。
    SYSINIT使得FreeBSD的内核各子系统可以在内核或模块动态加载链接时被重整、
    添加、删除、替换,这样,内核和模块加载时就不必去修改一个静态的有序初始化
    安排表甚至重新编译内核。这个体系也使得内核模块
    (现在称为<firstterm>KLD</firstterm>可以与内核不同时编译、链接、
    在引导系统时加载,甚至在系统运行时加载。这些操作是通过
    <quote>内核链接器</quote>(kernel linker)和<quote>链接器集合</quote>
    (linker set)完成的。</para>

  <sect1 id="sysinit-term">
    <title>术语</title>

    <variablelist>
      <varlistentry>
        <term>链接器集合(Linker Set)</term>
        <listitem>
          <para>一种链接方法。这种方法将整个程序源文件中静态申明的数据收集到
             一个可邻近寻址的数据单元中。</para>
        </listitem>
      </varlistentry>
    </variablelist>
  </sect1>

  <sect1 id="sysinit-operation">
    <title>SYSINIT操作</title>

    <indexterm><primary>linker sets(链接器集合)</primary></indexterm>

    <para>SYSINIT要依靠链接器获取遍布整个程序源代码多处申明的静态数据
      并把它们组成一个彼此相邻的数据块。这种链接方法被称为
      <quote>链接器集合</quote>(linker set)。
      SYSINIT使用两个链接器集合以维护两个数据集合,
      包含每个数据条目的调用顺序、函数、一个会被提交给该函数的数据指针。</para>

    <para>SYSINIT按照两类优先级标识对函数排序以便执行。
      第一类优先级的标识是子系统的标识,
      给出SYSINIT分别执行子系统的函数的全局顺序,
      定义在<filename>&lt;sys/kernel.h&gt;</filename>中的枚举
      <literal>sysinit_sub_id</literal>内。第二类优先级标识在子系统中的元素的顺序,
      定义在<filename>&lt;sys/kernel.h&gt;</filename>中的枚举
      <literal>sysinit_elem_order</literal>内。</para>

  <indexterm><primary>pseudo-device(伪设备)</primary></indexterm>

    <para>有两种时刻需要使用SYSINIT:系统启动或内核模块加载时,
      系统析构或内核模块卸载时。内核子系统通常在系统启动时使用SYSINIT
      的定义项以初始化数据结构。例如,进程调度子系统使用一个SYSINIT
      定义项来初始化运行队列数据结构。设备驱动程序应避免直接使用
      <literal>SYSINIT()</literal>,对于总线结构上的物理真实设备应使用
      <literal>DRIVER_MODULE()</literal>调用的函数先侦测设备的存在,
      如果存在,再进行设备的初始化。这一系统过程中,
      会做一些专门针对设备的事情,然后调用<literal>SYSINIT()</literal>本身。
      对于非总线结构一部分的虚设备,应改用<literal>DEV_MODULE()</literal></para>
  </sect1>


  <sect1 id="sysinit-using">
    <title>使用SYSINIT</title>

    <sect2>
      <title>接口</title>

      <sect3>
        <title>头文件</title>

          <programlisting>&lt;sys/kernel.h&gt;</programlisting>
      </sect3>

      <sect3>
        <title></title>

        <programlisting>SYSINIT(uniquifier, subsystem, order, func, ident)
SYSUNINIT(uniquifier, subsystem, order, func, ident)</programlisting>
      </sect3>
    </sect2>

    <sect2>
      <title>启动</title>

      <para><literal>SYSINIT()</literal>在SYSINIT启动数据集合中
        建立一个SYSINIT数据项,以便SYSINIT在系统启动或模块加载时排序
        并执行其中的函数。<literal>SYSINIT()</literal>有一个参数uniquifier,
        SYSINIT用它来标识数据项,随后是子系统顺序号、子系统元素顺序号、
        待调用函数、传递给函数的数据。所有的函数必须有一个恒量指针参数。</para>

      <example>
	<title><literal>SYSINIT()</literal>的例子</title>

	<programlisting>#include &lt;sys/kernel.h&gt;

void foo_null(void *unused)
{
        foo_doo();
}
SYSINIT(foo, SI_SUB_FOO, SI_ORDER_FOO, foo_null, NULL);

struct foo foo_voodoo = {
        FOO_VOODOO;
}

void foo_arg(void *vdata)
{
        struct foo *foo = (struct foo *)vdata;
        foo_data(foo);
}
SYSINIT(bar, SI_SUB_FOO, SI_ORDER_FOO, foo_arg, &amp;foo_voodoo);
	</programlisting>
      </example>

      <para>注意,<literal>SI_SUB_FOO</literal><literal>SI_ORDER_FOO</literal>
         应当分别在上面提到的枚举<literal>sysinit_sub_id</literal><literal>sysinit_elem_order</literal>之中。既可以使用已有的枚举项,
         也可以将自己的枚举项添加到这两个枚举的定义之中。
         你可以使用数学表达式微调SYSINIT的执行顺序。
         以下的例子示例了一个需要刚好要在内核参数调整的SYSINIT之前执行的SYSINIT。</para>

      <example>
	<title>调整<literal>SYSINIT()</literal>顺序的例子</title>

	<programlisting>static void
mptable_register(void *dummy __unused)
{

	apic_register_enumerator(&amp;mptable_enumerator);
}

SYSINIT(mptable_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST,
    mptable_register, NULL);</programlisting>
      </example>
    </sect2>

    <sect2>
      <title>析构</title>

      <para><literal>SYSUNINIT()</literal>的行为与<literal>SYSINIT()</literal>的相当,
        只是它将数据项填加至SYSINIT的析构数据集合。</para>

      <example>
	<title><literal>SYSUNINIT()</literal>的例子</title>

	<programlisting>#include &lt;sys/kernel.h&gt;

void foo_cleanup(void *unused)
{
        foo_kill();
}
SYSUNINIT(foobar, SI_SUB_FOO, SI_ORDER_FOO, foo_cleanup, NULL);

struct foo_stack foo_stack = {
        FOO_STACK_VOODOO;
}

void foo_flush(void *vdata)
{
}
SYSUNINIT(barfoo, SI_SUB_FOO, SI_ORDER_FOO, foo_flush, &amp;foo_stack);
	</programlisting>
      </example>
    </sect2>
  </sect1>
</chapter>