aboutsummaryrefslogtreecommitdiff
path: root/en_US.ISO8859-1/books/arch-handbook/sysinit/chapter.sgml
blob: 1d054e3b51ccf2c37534ca9ccac611e7a75ece3f (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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
<!--
     The FreeBSD Documentation Project

     $FreeBSD$
-->

<chapter id="sysinit">
  <title>The SYSINIT Framework</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 is the framework for a generic call sort and dispatch
    mechanism. FreeBSD currently uses it for the dynamic
    initialization of the kernel. SYSINIT allows FreeBSD's kernel
    subsystems to be reordered, and added, removed, and replaced at
    kernel link time when the kernel or one of its modules is loaded
    without having to edit a statically ordered initialization routing
    and recompile the kernel. This system also allows kernel modules,
    currently called <firstterm>KLD's</firstterm>, to be separately
    compiled, linked, and initialized at boot time and loaded even
    later while the system is already running. This is accomplished
    using the <quote>kernel linker</quote> and <quote>linker
    sets</quote>.</para>

  <sect1 id="sysinit-term">
    <title>Terminology</title>

    <variablelist>
      <varlistentry>
        <term>Linker Set</term>
        <listitem>
          <para>A linker technique in which the linker gathers
            statically declared data throughout a program's source files
            into a single contiguously addressable unit of
            data.</para>
        </listitem>
      </varlistentry>
    </variablelist>
  </sect1>

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

    <indexterm><primary>linker sets</primary></indexterm>

    <para>SYSINIT relies on the ability of the linker to take static
      data declared at multiple locations throughout a program's
      source and group it together as a single contiguous chunk of
      data. This linker technique is called a <quote>linker
      set</quote>. SYSINIT uses two linker sets to maintain two data
      sets containing each consumer's call order, function, and a
      pointer to the data to pass to that function.</para>

    <para>SYSINIT uses two priorities when ordering the functions for
      execution.  The first priority is a subsystem ID giving an
      overall order for SYSINIT's dispatch of functions. Current predeclared
      ID's are in <filename>&lt;sys/kernel.h&gt;</filename> in the enum
      list <literal>sysinit_sub_id</literal>. The second priority used
      is an element order within the subsystem. Current predeclared
      subsystem element orders are in
      <filename>&lt;sys/kernel.h&gt;</filename> in the enum list
      <literal>sysinit_elem_order</literal>.</para>

  <indexterm><primary>pseudo-devices</primary></indexterm>
  
  <para>There are currently two uses for SYSINIT. Function dispatch
      at system startup and kernel module loads, and function dispatch
      at system shutdown and kernel module unload.  Kernel subsystems
      often use system startup SYSINIT's to initialize data
      structures, for example the process scheduling subsystem
      uses a SYSINIT to initialize the run queue data structure.
      Device drivers should avoid using <literal>SYSINIT()</literal>
      directly.  Instead drivers for real devices that are part of a
      bus structure should use <literal>DRIVER_MODULE()</literal> to
      provide a function that detects the device and, if it is present,
      initializes the device.  It will do a few things specific to
      devices and then call <literal>SYSINIT()</literal> itself.
      For pseudo-devices, which are not part of a bus structure,
      use <literal>DEV_MODULE()</literal>.</para>
  </sect1>


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

    <sect2>
      <title>Interface</title>

      <sect3>
        <title>Headers</title>

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

      <sect3>
        <title>Macros</title>

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

    <sect2>
      <title>Startup</title>

      <para>The <literal>SYSINIT()</literal> macro creates the
        necessary SYSINIT data in SYSINIT's startup data set for
        SYSINIT to sort and dispatch a function at system startup and
        module load.  <literal>SYSINIT()</literal> takes a uniquifier
        that SYSINIT uses to identify the particular function dispatch
        data, the subsystem order, the subsystem element order, the
        function to call, and the data to pass the function. All
        functions must take a constant pointer argument.
        </para>

      <example>
	<title>Example of a <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>Note that <literal>SI_SUB_FOO</literal> and
	<literal>SI_ORDER_FOO</literal> need to be in the
	<literal>sysinit_sub_id</literal> and
	<literal>sysinit_elem_order</literal> enum's as mentioned
	above.  Either use existing ones or add your own to the
	enum's.  You can also use math for fine-tuning the order
	a SYSINIT will run in.  This example shows a SYSINIT that
	needs to be run just barely before the SYSINIT's that
	handle tuning kernel parameters.</para>

      <example>
	<title>Example of Adjusting <literal>SYSINIT()</literal> Order</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>Shutdown</title>

      <para>The <literal>SYSUNINIT()</literal> macro behaves similarly
        to the <literal>SYSINIT()</literal> macro except that it adds
        the SYSINIT data to SYSINIT's shutdown data set.</para>

      <example>
	<title>Example of a <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>

<!--
     Local Variables:
     mode: sgml
     sgml-declaration: "../chapter.decl"
     sgml-indent-data: t
     sgml-omittag: nil
     sgml-always-quote-attributes: t
     sgml-parent-document: ("../book.sgml" "part" "chapter")
     End:
-->