~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/Documentation/translations/zh_CN/kernel-hacking/hacking.rst

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /Documentation/translations/zh_CN/kernel-hacking/hacking.rst (Version linux-6.12-rc7) and /Documentation/translations/zh_CN/kernel-hacking/hacking.rst (Version linux-5.19.17)


  1 .. include:: ../disclaimer-zh_CN.rst                1 .. include:: ../disclaimer-zh_CN.rst
  2                                                     2 
  3 :Original: Documentation/kernel-hacking/hackin      3 :Original: Documentation/kernel-hacking/hacking.rst
  4                                                     4 
  5 :译者:                                            5 :译者:
  6                                                     6 
  7  吴想成 Wu XiangCheng <bobwxc@email.cn>           7  吴想成 Wu XiangCheng <bobwxc@email.cn>
  8                                                     8 
  9 ==============                                      9 ==============
 10 内核骇客指北                                 10 内核骇客指北
 11 ==============                                     11 ==============
 12                                                    12 
 13 :作者: Rusty Russell                             13 :作者: Rusty Russell
 14                                                    14 
 15 引言                                             15 引言
 16 =====                                              16 =====
 17                                                    17 
 18 欢迎咱优雅的读者们来阅读Rusty的     18 欢迎咱优雅的读者们来阅读Rusty的非常不靠谱的Linux内核骇客(Hacking)指南。本文
 19 描述了内核代码的常见例程和一般     19 描述了内核代码的常见例程和一般要求:其目标是引导有经验的C程序员入门Linux内核
 20 开发。我回避了实现细节:这是代     20 开发。我回避了实现细节:这是代码要做的,也忽略了很多有用的例程。
 21                                                    21 
 22 在你读这篇文章之前,请理解我从     22 在你读这篇文章之前,请理解我从来没有想过要写这篇文章,因为我的资历太低了;
 23 但我一直想读这样的文章,自己写     23 但我一直想读这样的文章,自己写是唯一的方法。我希望它能成长为一个最佳实践、
 24 通用起点和其他信息的汇编。            24 通用起点和其他信息的汇编。
 25                                                    25 
 26 玩家                                             26 玩家
 27 =======                                            27 =======
 28                                                    28 
 29 在任何时候,系统中的每个CPU都可     29 在任何时候,系统中的每个CPU都可以:
 30                                                    30 
 31 -  与任何进程无关,服务于硬件中     31 -  与任何进程无关,服务于硬件中断;
 32                                                    32 
 33 -  与任何进程无关,服务于软件中     33 -  与任何进程无关,服务于软件中断(softirq)或子任务(tasklet);
 34                                                    34 
 35 -  运行于内核空间中,与进程(用     35 -  运行于内核空间中,与进程(用户上下文)相关联;
 36                                                    36 
 37 -  在用户空间中运行进程。               37 -  在用户空间中运行进程。
 38                                                    38 
 39 它们之间有优先级顺序。最下面的     39 它们之间有优先级顺序。最下面的两个可以互相抢占,但上面为严格的层次结构:
 40 每个层级只能被上方的抢占。例如     40 每个层级只能被上方的抢占。例如,当一个软中断在CPU上运行时,没有其他软中断
 41 会抢占它,但是硬件中断可以抢占     41 会抢占它,但是硬件中断可以抢占它。不过,系统中的任何其他CPU都是独立执行的。
 42                                                    42 
 43 我们将会看到许多方法,用户上下     43 我们将会看到许多方法,用户上下文可以阻止中断,从而成为真正的不可抢占。
 44                                                    44 
 45 用户上下文                                    45 用户上下文
 46 ------------                                       46 ------------
 47                                                    47 
 48 用户上下文是指当您从系统调用或     48 用户上下文是指当您从系统调用或其他陷阱进入时:就像用户空间一样,您可以被更
 49 重要的任务和中断抢占。您可以通     49 重要的任务和中断抢占。您可以通过调用 :c:func:`schedule()` 进行睡眠。
 50                                                    50 
 51 .. note::                                          51 .. note::
 52                                                    52 
 53     在模块加载和卸载以及块设备层     53     在模块加载和卸载以及块设备层上的操作时,你始终处于用户上下文中。
 54                                                    54 
 55 在用户上下文中,当前 ``current`` 指     55 在用户上下文中,当前 ``current`` 指针(指示我们当前正在执行的任务)是有效的,
 56 且 :c:func:`in_interrupt()` ( ``include/lin     56 且 :c:func:`in_interrupt()` ( ``include/linux/preempt.h`` )值为非(false)。
 57                                                    57 
 58 .. warning::                                       58 .. warning::
 59                                                    59 
 60     请注意,如果您禁用了抢占或软     60     请注意,如果您禁用了抢占或软中断(见下文),:c:func:`in_interrupt()` 会
 61     返回假阳性。                             61     返回假阳性。
 62                                                    62 
 63 硬件中断(Hard IRQs)                        63 硬件中断(Hard IRQs)
 64 ----------------------                             64 ----------------------
 65                                                    65 
 66 像定时器、网卡和键盘等都是可能     66 像定时器、网卡和键盘等都是可能在任意时刻产生中断的真实硬件。内核运行中断
 67 处理程序,为硬件提供服务。内核     67 处理程序,为硬件提供服务。内核确保处理程序永远不会重入:如果相同的中断到达,
 68 它将被排队(或丢弃)。因为它会     68 它将被排队(或丢弃)。因为它会关闭中断,所以处理程序必须很快:通常它只是
 69 确认中断,标记一个“软件中断”     69 确认中断,标记一个“软件中断”以执行并退出。
 70                                                    70 
 71 您可以通过 in_hardirq() 返回真来判     71 您可以通过 in_hardirq() 返回真来判断您处于硬件中断状态。
 72                                                    72 
 73 .. warning::                                       73 .. warning::
 74                                                    74 
 75     请注意,如果中断被禁用,这将     75     请注意,如果中断被禁用,这将返回假阳性(见下文)。
 76                                                    76 
 77 软件中断上下文:软中断(Softirqs     77 软件中断上下文:软中断(Softirqs)与子任务(Tasklets)
 78 ----------------------------------------------     78 -------------------------------------------------------
 79                                                    79 
 80 当系统调用即将返回用户空间或硬     80 当系统调用即将返回用户空间或硬件中断处理程序退出时,任何标记为挂起(通常通
 81 过硬件中断)的“软件中断”将运     81 过硬件中断)的“软件中断”将运行( ``kernel/softirq.c`` )。
 82                                                    82 
 83 此处完成了许多真正的中断处理工     83 此处完成了许多真正的中断处理工作。在向SMP过渡的早期,只有“bottom halves下半
 84 部”(BHs)机制,无法利用多个CPU !!  84 部”(BHs)机制,无法利用多个CPU的优势。在从那些一团糟的就电脑切换过来后不久,
 85 我们放弃了这个限制,转而使用“     85 我们放弃了这个限制,转而使用“软中断”。
 86                                                    86 
 87 ``include/linux/interrupt.h`` 列出了不同     87 ``include/linux/interrupt.h`` 列出了不同的软中断。定时器软中断是一个非常重要
 88 的软中断( ``include/linux/timer.h`` )     88 的软中断( ``include/linux/timer.h`` ):您可以注册它以在给定时间后为您调用
 89 函数。                                          89 函数。
 90                                                    90 
 91 软中断通常是一个很难处理的问题     91 软中断通常是一个很难处理的问题,因为同一个软中断将同时在多个CPU上运行。因此,
 92 子任务( ``include/linux/interrupt.h`` )     92 子任务( ``include/linux/interrupt.h`` )更常用:它们是动态可注册的(意味着
 93 您可以拥有任意数量),并且它们     93 您可以拥有任意数量),并且它们还保证任何子任务都只能在一个CPU上运行,不同的
 94 子任务也可以同时运行。                  94 子任务也可以同时运行。
 95                                                    95 
 96 .. warning::                                       96 .. warning::
 97                                                    97 
 98     “tasklet”这个名字是误导性的 !!  98     “tasklet”这个名字是误导性的:它们与“任务”无关,可能更多与当时
                                                   >>  99     阿列克谢·库兹涅佐夫享用的糟糕伏特加有关。
 99                                                   100 
100 你可以使用 :c:func:`in_softirq()` 宏(     101 你可以使用 :c:func:`in_softirq()` 宏( ``include/linux/preempt.h`` )来确认
101 是否处于软中断(或子任务)中。     102 是否处于软中断(或子任务)中。
102                                                   103 
103 .. warning::                                      104 .. warning::
104                                                   105 
105     注意,如果持有 :ref:`bottom half lo    106     注意,如果持有 :ref:`bottom half lock <local_bh_disable_zh>` 锁,这将返回
106     假阳性。                                  107     假阳性。
107                                                   108 
108 一些基本规则                                109 一些基本规则
109 ================                                  110 ================
110                                                   111 
111 缺少内存保护                                112 缺少内存保护
112     如果你损坏了内存,无论是在用    113     如果你损坏了内存,无论是在用户上下文还是中断上下文中,整个机器都会崩溃。
113     你确定你不能在用户空间里做你    114     你确定你不能在用户空间里做你想做的事吗?
114                                                   115 
115 缺少浮点或MMX                                116 缺少浮点或MMX
116     FPU上下文不会被保存;即使在用    117     FPU上下文不会被保存;即使在用户上下文中,FPU状态也可能与当前进程不一致:
117     您会弄乱某些用户进程的FPU状态    118     您会弄乱某些用户进程的FPU状态。如果真的要这样做,就必须显式地保存/恢复
118     完整的FPU状态(并避免上下文切    119     完整的FPU状态(并避免上下文切换)。这通常不是个好主意;请优先用定点算法。
119                                                   120 
120 严格的堆栈限制                             121 严格的堆栈限制
121     对于大多数32位体系结构,根据    122     对于大多数32位体系结构,根据配置选项的不同内核堆栈大约为3K到6K;对于大
122     多数64位机器,内核堆栈大约为1    123     多数64位机器,内核堆栈大约为14K,并且经常与中断共享,因此你无法使用全部。
123     应避免深度递归和栈上的巨型本    124     应避免深度递归和栈上的巨型本地数组(用动态分配它们来代替)。
124                                                   125 
125 Linux内核是可移植的                        126 Linux内核是可移植的
126     就这样吧。您的代码应该是纯64    127     就这样吧。您的代码应该是纯64位的,并且不依赖于字节序(endian)。您还应该
127     尽量减少CPU特定的东西,例如内    128     尽量减少CPU特定的东西,例如内联汇编(inline assembly)应该被干净地封装和
128     最小化以便于移植。一般来说,    129     最小化以便于移植。一般来说,它应该局限于内核树中有体系结构依赖的部分。
129                                                   130 
130 输入输出控制(ioctls):避免编写    131 输入输出控制(ioctls):避免编写新的系统调用
131 ==============================================    132 ==============================================
132                                                   133 
133 系统调用(system call)通常看起来    134 系统调用(system call)通常看起来像这样::
134                                                   135 
135     asmlinkage long sys_mycall(int arg)           136     asmlinkage long sys_mycall(int arg)
136     {                                             137     {
137             return 0;                             138             return 0;
138     }                                             139     }
139                                                   140 
140                                                   141 
141 首先,在大多数情况下,您无需创    142 首先,在大多数情况下,您无需创建新的系统调用。创建一个字符设备并为其实现适当
142 的输入输出控制(ioctls)。这比系    143 的输入输出控制(ioctls)。这比系统调用灵活得多,不必写进每个体系结构的
143 ``include/asm/unistd.h`` 和 ``arch/kernel/ent    144 ``include/asm/unistd.h`` 和 ``arch/kernel/entry.S`` 文件里,而且更容易被Linus
144 接受。                                         145 接受。
145                                                   146 
146 如果您的程序所做的只是读取或写    147 如果您的程序所做的只是读取或写入一些参数,请考虑实现 :c:func:`sysfs()` 接口。
147                                                   148 
148 在输入输出控制中,您处于进程的    149 在输入输出控制中,您处于进程的用户上下文。出现错误时,返回一个负的错误参数
149 (errno,请参阅 ``include/uapi/asm-generi    150 (errno,请参阅 ``include/uapi/asm-generic/errno-base.h`` 、
150 ``include/uapi/asm-generic/errno.h`` 和 ``inc    151 ``include/uapi/asm-generic/errno.h`` 和 ``include/linux/errno.h`` ),否则返
151 回0。                                           152 回0。
152                                                   153 
153 在睡眠之后,您应该检查是否出现    154 在睡眠之后,您应该检查是否出现了信号:Unix/Linux处理信号的方法是暂时退出系统
154 调用,并返回 ``-ERESTARTSYS`` 错误。    155 调用,并返回 ``-ERESTARTSYS`` 错误。系统调用入口代码将切换回用户上下文,处理
155 信号处理程序,然后系统调用将重    156 信号处理程序,然后系统调用将重新启动(除非用户禁用了该功能)。因此,您应该准
156 备好处理重新启动,例如若您处理    157 备好处理重新启动,例如若您处理某些数据结构到一半。
157                                                   158 
158 ::                                                159 ::
159                                                   160 
160     if (signal_pending(current))                  161     if (signal_pending(current))
161             return -ERESTARTSYS;                  162             return -ERESTARTSYS;
162                                                   163 
163                                                   164 
164 如果你要做更长时间的计算:优先    165 如果你要做更长时间的计算:优先考虑用户空间。如果你真的想在内核中做这件事,你
165 应该定期检查你是否需要让出CPU(    166 应该定期检查你是否需要让出CPU(请记得每个CPU都有协作多任务)。
166 习惯用法::                                    167 习惯用法::
167                                                   168 
168     cond_resched(); /* Will sleep */              169     cond_resched(); /* Will sleep */
169                                                   170 
170                                                   171 
171 接口设计的小注释:UNIX系统调用的    172 接口设计的小注释:UNIX系统调用的格言是“提供机制而不是策略
172 Provide mechanism not policy”。                173 Provide mechanism not policy”。
173                                                   174 
174 死锁的“配方”                             175 死锁的“配方”
175 ====================                              176 ====================
176                                                   177 
177 您不能调用任何可能睡眠的程序,    178 您不能调用任何可能睡眠的程序,除非:
178                                                   179 
179 - 您处于用户上下文中。                  180 - 您处于用户上下文中。
180                                                   181 
181 - 你未拥有任何自旋锁。                  182 - 你未拥有任何自旋锁。
182                                                   183 
183 - 您已经启用中断(实际上,Andi Kle    184 - 您已经启用中断(实际上,Andi Kleen说调度代码将为您启用它们,但这可能不是
184   您想要的)。                              185   您想要的)。
185                                                   186 
186 注意,有些函数可能隐式地睡眠:    187 注意,有些函数可能隐式地睡眠:常见的是用户空间访问函数(\*_user)和没有
187 ``GFP_ATOMIC`` 的内存分配函数。           188 ``GFP_ATOMIC`` 的内存分配函数。
188                                                   189 
189 您应该始终打开  ``CONFIG_DEBUG_ATOMIC_S    190 您应该始终打开  ``CONFIG_DEBUG_ATOMIC_SLEEP``  项来编译内核,如果您违反这些
190 规则,它将警告您。如果你 **真的*    191 规则,它将警告您。如果你 **真的** 违反了规则,你最终会锁住你的电脑。
191                                                   192 
192 真的会这样。                                193 真的会这样。
193                                                   194 
194                                                   195 
195 常用函数/程序                               196 常用函数/程序
196 ===============                                   197 ===============
197                                                   198 
198 :c:func:`printk()`                                199 :c:func:`printk()`
199 ------------------                                200 ------------------
200                                                   201 
201 定义于 ``include/linux/printk.h``              202 定义于 ``include/linux/printk.h``
202                                                   203 
203 :c:func:`printk()` 将内核消息提供给控    204 :c:func:`printk()` 将内核消息提供给控制台、dmesg和syslog守护进程。它对于调
204 试和报告错误很有用,并且可以在    205 试和报告错误很有用,并且可以在中断上下文中使用,但是使用时要小心:如果机器
205 的控制台中充斥着printk消息则会无    206 的控制台中充斥着printk消息则会无法使用。它使用与ANSI C printf基本兼容的格式
206 字符串,并通过C字符串串联为其提    207 字符串,并通过C字符串串联为其提供第一个“优先”参数::
207                                                   208 
208     printk(KERN_INFO "i = %u\n", i);              209     printk(KERN_INFO "i = %u\n", i);
209                                                   210 
210                                                   211 
211 参见 ``include/linux/kern_levels.h`` ;了    212 参见 ``include/linux/kern_levels.h`` ;了解其他 ``KERN_`` 值;syslog将这些值
212 解释为级别。特殊用法:打印IP地    213 解释为级别。特殊用法:打印IP地址使用::
213                                                   214 
214     __be32 ipaddress;                             215     __be32 ipaddress;
215     printk(KERN_INFO "my ip: %pI4\n", &ipaddre    216     printk(KERN_INFO "my ip: %pI4\n", &ipaddress);
216                                                   217 
217                                                   218 
218 :c:func:`printk()` 内部使用的1K缓冲区    219 :c:func:`printk()` 内部使用的1K缓冲区,不捕获溢出。请确保足够使用。
219                                                   220 
220 .. note::                                         221 .. note::
221                                                   222 
222     当您开始在用户程序中将printf打    223     当您开始在用户程序中将printf打成printk时,就知道自己是真正的内核程序员了
223     :)                                            224     :)
224                                                   225 
225 .. note::                                         226 .. note::
226                                                   227 
227     另一个注释:最初的unix第六版    228     另一个注释:最初的unix第六版源代码在其printf函数的顶部有一个注释:“printf
228     不应该用于叽叽喳喳”。你也应    229     不应该用于叽叽喳喳”。你也应该遵循此建议。
229                                                   230 
230 :c:func:`copy_to_user()` / :c:func:`copy_from_    231 :c:func:`copy_to_user()` / :c:func:`copy_from_user()` / :c:func:`get_user()` / :c:func:`put_user()`
231 ----------------------------------------------    232 ---------------------------------------------------------------------------------------------------
232                                                   233 
233 定义于 ``include/linux/uaccess.h`` / ``asm/    234 定义于 ``include/linux/uaccess.h`` / ``asm/uaccess.h``
234                                                   235 
235 **[睡眠]**                                      236 **[睡眠]**
236                                                   237 
237 :c:func:`put_user()` 和 :c:func:`get_user()`     238 :c:func:`put_user()` 和 :c:func:`get_user()` 用于从用户空间中获取和向用户空
238 间中传出单个值(如int、char或long    239 间中传出单个值(如int、char或long)。指向用户空间的指针永远不应该直接取消
239 引用:应该使用这些程序复制数据    240 引用:应该使用这些程序复制数据。两者都返回 ``-EFAULT`` 或 0。
240                                                   241 
241 :c:func:`copy_to_user()` 和 :c:func:`copy_fro    242 :c:func:`copy_to_user()` 和 :c:func:`copy_from_user()` 更通用:它们从/向用户
242 空间复制任意数量的数据。              243 空间复制任意数量的数据。
243                                                   244 
244 .. warning::                                      245 .. warning::
245                                                   246 
246     与 :c:func:`put_user()` 和 :c:func:`get_    247     与 :c:func:`put_user()` 和 :c:func:`get_user()` 不同,它们返回未复制的
247     数据量(即0仍然意味着成功)    248     数据量(即0仍然意味着成功)。
248                                                   249 
249 【是的,这个讨厌的接口真心让我 !! 250 【是的,这个愚蠢的接口真心让我尴尬。火爆的口水仗大概每年都会发生。
250 —— Rusty Russell】                           251 —— Rusty Russell】
251                                                   252 
252 这些函数可以隐式睡眠。它不应该    253 这些函数可以隐式睡眠。它不应该在用户上下文之外调用(没有意义)、调用时禁用中断
253 或获得自旋锁。                             254 或获得自旋锁。
254                                                   255 
255 :c:func:`kmalloc()`/:c:func:`kfree()`             256 :c:func:`kmalloc()`/:c:func:`kfree()`
256 -------------------------------------             257 -------------------------------------
257                                                   258 
258 定义于 ``include/linux/slab.h``                259 定义于 ``include/linux/slab.h``
259                                                   260 
260 **[可能睡眠:见下]**                       261 **[可能睡眠:见下]**
261                                                   262 
262 这些函数用于动态请求指针对齐的    263 这些函数用于动态请求指针对齐的内存块,类似用户空间中的malloc和free,但
263 :c:func:`kmalloc()` 需要额外的标志词    264 :c:func:`kmalloc()` 需要额外的标志词。重要的值:
264                                                   265 
265 ``GFP_KERNEL``                                    266 ``GFP_KERNEL``
266     可以睡眠和交换以释放内存。只    267     可以睡眠和交换以释放内存。只允许在用户上下文中使用,但这是分配内存最可靠
267     的方法。                                  268     的方法。
268                                                   269 
269 ``GFP_ATOMIC``                                    270 ``GFP_ATOMIC``
270     不会睡眠。较 ``GFP_KERNEL`` 更不    271     不会睡眠。较 ``GFP_KERNEL`` 更不可靠,但可以从中断上下文调用。你 **应该**
271     有一个很好的内存不足错误处理    272     有一个很好的内存不足错误处理策略。
272                                                   273 
273 ``GFP_DMA``                                       274 ``GFP_DMA``
274     分配低于16MB的ISA DMA。如果你不    275     分配低于16MB的ISA DMA。如果你不知道那是什么,那你就不需要了。非常不可靠。
275                                                   276 
276 如果您看到一个从无效上下文警告    277 如果您看到一个从无效上下文警告消息调用的睡眠的函数,那么您可能在没有
277 ``GFP_ATOMIC`` 的情况下从中断上下文    278 ``GFP_ATOMIC`` 的情况下从中断上下文调用了一个睡眠的分配函数。你必须立即修复,
278 快点!                                         279 快点!
279                                                   280 
280 如果你要分配至少 ``PAGE_SIZE`` ( ``a    281 如果你要分配至少 ``PAGE_SIZE`` ( ``asm/page.h`` 或 ``asm/page_types.h`` )
281 字节,请考虑使用 :c:func:`__get_free_p    282 字节,请考虑使用 :c:func:`__get_free_pages()` ( ``include/linux/gfp.h`` )。
282 它采用顺序参数(0表示页面大小,    283 它采用顺序参数(0表示页面大小,1表示双页,2表示四页……)和与上述相同的内存
283 优先级标志字。                             284 优先级标志字。
284                                                   285 
285 如果分配的字节数超过一页,可以    286 如果分配的字节数超过一页,可以使用 :c:func:`vmalloc()` 。它将在内核映射中分
286 配虚拟内存。此块在物理内存中不    287 配虚拟内存。此块在物理内存中不是连续的,但是MMU(内存管理单元)使它看起来像
287 是为您准备好的连续空间(因此它    288 是为您准备好的连续空间(因此它只是看起来对cpu连续,对外部设备驱动程序则不然)。
288 如果您真的需要为一些奇怪的设备    289 如果您真的需要为一些奇怪的设备提供大量物理上连续的内存,那么您就会遇到问题:
289 Linux对此支持很差,因为正在运行    290 Linux对此支持很差,因为正在运行的内核中的内存碎片化会使它变得很困难。最好的
290 方法是在引导过程的早期通过 :c:fun    291 方法是在引导过程的早期通过 :c:func:`alloc_bootmem()` 函数分配。
291                                                   292 
292 在创建自己的常用对象缓存之前,    293 在创建自己的常用对象缓存之前,请考虑使用 ``include/linux/slab.h`` 中的slab
293 缓存。                                         294 缓存。
294                                                   295 
295 :c:macro:`current`                                296 :c:macro:`current`
296 ------------------                                297 ------------------
297                                                   298 
298 定义于 ``include/asm/current.h``               299 定义于 ``include/asm/current.h``
299                                                   300 
300 此全局变量(其实是宏)包含指向    301 此全局变量(其实是宏)包含指向当前任务结构(task structure)的指针,因此仅在
301 用户上下文中有效。例如,当进程    302 用户上下文中有效。例如,当进程进行系统调用时,这将指向调用进程的任务结构。
302 在中断上下文中不为空(**not NULL**    303 在中断上下文中不为空(**not NULL**)。
303                                                   304 
304 :c:func:`mdelay()`/:c:func:`udelay()`             305 :c:func:`mdelay()`/:c:func:`udelay()`
305 -------------------------------------             306 -------------------------------------
306                                                   307 
307 定义于 ``include/asm/delay.h`` / ``include/    308 定义于 ``include/asm/delay.h`` / ``include/linux/delay.h``
308                                                   309 
309 :c:func:`udelay()` 和 :c:func:`ndelay()` 函    310 :c:func:`udelay()` 和 :c:func:`ndelay()` 函数可被用于小暂停。不要对它们使用
310 大的值,因为这样会导致溢出——    311 大的值,因为这样会导致溢出——帮助函数 :c:func:`mdelay()` 在这里很有用,或者
311 考虑 :c:func:`msleep()`。                      312 考虑 :c:func:`msleep()`。
312                                                   313 
313 :c:func:`cpu_to_be32()`/:c:func:`be32_to_cpu()    314 :c:func:`cpu_to_be32()`/:c:func:`be32_to_cpu()`/:c:func:`cpu_to_le32()`/:c:func:`le32_to_cpu()`
314 ----------------------------------------------    315 -----------------------------------------------------------------------------------------------
315                                                   316 
316 定义于 ``include/asm/byteorder.h``             317 定义于 ``include/asm/byteorder.h``
317                                                   318 
318 :c:func:`cpu_to_be32()` 系列函数(其中    319 :c:func:`cpu_to_be32()` 系列函数(其中“32”可以替换为64或16,“be”可以替换为
319 “le”)是在内核中进行字节序转    320 “le”)是在内核中进行字节序转换的常用方法:它们返回转换后的值。所有的变体也
320 提供反向转换函数:                       321 提供反向转换函数:
321 :c:func:`be32_to_cpu()` 等。                    322 :c:func:`be32_to_cpu()` 等。
322                                                   323 
323 这些函数有两个主要的变体:指针    324 这些函数有两个主要的变体:指针变体,例如 :c:func:`cpu_to_be32p()` ,它获取
324 指向给定类型的指针,并返回转换    325 指向给定类型的指针,并返回转换后的值。另一个变体是“in-situ”系列,例如
325 :c:func:`cpu_to_be32s()` ,它转换指针引    326 :c:func:`cpu_to_be32s()` ,它转换指针引用的值,并返回void。
326                                                   327 
327 :c:func:`local_irq_save()`/:c:func:`local_irq_    328 :c:func:`local_irq_save()`/:c:func:`local_irq_restore()`
328 ----------------------------------------------    329 --------------------------------------------------------
329                                                   330 
330 定义于 ``include/linux/irqflags.h``            331 定义于 ``include/linux/irqflags.h``
331                                                   332 
332                                                   333 
333 这些程序禁用本地CPU上的硬中断,    334 这些程序禁用本地CPU上的硬中断,并还原它们。它们是可重入的;在其一个
334 ``unsigned long flags`` 参数中保存以前    335 ``unsigned long flags`` 参数中保存以前的状态。如果您知道中断已启用,那么可
335 直接使用 :c:func:`local_irq_disable()` 和    336 直接使用 :c:func:`local_irq_disable()` 和 :c:func:`local_irq_enable()`。
336                                                   337 
337 .. _local_bh_disable_zh:                          338 .. _local_bh_disable_zh:
338                                                   339 
339 :c:func:`local_bh_disable()`/:c:func:`local_bh    340 :c:func:`local_bh_disable()`/:c:func:`local_bh_enable()`
340 ----------------------------------------------    341 --------------------------------------------------------
341                                                   342 
342 定义于 ``include/linux/bottom_half.h``         343 定义于 ``include/linux/bottom_half.h``
343                                                   344 
344                                                   345 
345 这些程序禁用本地CPU上的软中断,    346 这些程序禁用本地CPU上的软中断,并还原它们。它们是可重入的;如果之前禁用了
346 软中断,那么在调用这对函数之后    347 软中断,那么在调用这对函数之后仍然会禁用它们。它们阻止软中断和子任务在当前
347 CPU上运行。                                   348 CPU上运行。
348                                                   349 
349 :c:func:`smp_processor_id()`                      350 :c:func:`smp_processor_id()`
350 ----------------------------                      351 ----------------------------
351                                                   352 
352 定义于 ``include/linux/smp.h``                 353 定义于 ``include/linux/smp.h``
353                                                   354 
354 :c:func:`get_cpu()` 禁用抢占(这样您    355 :c:func:`get_cpu()` 禁用抢占(这样您就不会突然移动到另一个cpu)并返回当前
355 处理器号,介于0和 ``NR_CPUS`` 之间    356 处理器号,介于0和 ``NR_CPUS`` 之间。请注意,CPU编号不一定是连续的。完成后,
356 使用 :c:func:`put_cpu()` 再次返回。        357 使用 :c:func:`put_cpu()` 再次返回。
357                                                   358 
358 如果您知道您不能被另一个任务抢    359 如果您知道您不能被另一个任务抢占(即您处于中断上下文中,或已禁用抢占),您
359 可以使用 :c:func:`smp_processor_id()`。      360 可以使用 :c:func:`smp_processor_id()`。
360                                                   361 
361 ``__init``/``__exit``/``__initdata``              362 ``__init``/``__exit``/``__initdata``
362 ------------------------------------              363 ------------------------------------
363                                                   364 
364 定义于  ``include/linux/init.h``               365 定义于  ``include/linux/init.h``
365                                                   366 
366 引导之后,内核释放一个特殊的部    367 引导之后,内核释放一个特殊的部分;用 ``__init`` 标记的函数和用 ``__initdata``
367 标记的数据结构在引导完成后被丢    368 标记的数据结构在引导完成后被丢弃:同样地,模块在初始化后丢弃此内存。
368 ``__exit`` 用于声明只在退出时需要    369 ``__exit`` 用于声明只在退出时需要的函数:如果此文件未编译为模块,则该函数将
369 被删除。请参阅头文件以使用。请    370 被删除。请参阅头文件以使用。请注意,使用 :c:func:`EXPORT_SYMBOL()` 或
370 :c:func:`EXPORT_SYMBOL_GPL()` 将标记为 ``_    371 :c:func:`EXPORT_SYMBOL_GPL()` 将标记为 ``__init`` 的函数导出到模块是没有意义
371 的——这将出问题。                       372 的——这将出问题。
372                                                   373 
373                                                   374 
374 :c:func:`__initcall()`/:c:func:`module_init()`    375 :c:func:`__initcall()`/:c:func:`module_init()`
375 ----------------------------------------------    376 ----------------------------------------------
376                                                   377 
377 定义于  ``include/linux/init.h`` / ``includ    378 定义于  ``include/linux/init.h`` / ``include/linux/module.h``
378                                                   379 
379 内核的许多部分都作为模块(内核    380 内核的许多部分都作为模块(内核的可动态加载部分)良好服务。使用
380 :c:func:`module_init()` 和 :c:func:`module_ex    381 :c:func:`module_init()` 和 :c:func:`module_exit()` 宏可以简化代码编写,无需
381 ``#ifdef`` ,即可以作为模块运行或    382 ``#ifdef`` ,即可以作为模块运行或内置在内核中。
382                                                   383 
383 :c:func:`module_init()` 宏定义在模块插    384 :c:func:`module_init()` 宏定义在模块插入时(如果文件编译为模块)或在引导时
384 调用哪个函数:如果文件未编译为    385 调用哪个函数:如果文件未编译为模块,:c:func:`module_init()` 宏将等效于
385 :c:func:`__initcall()` ,它通过链接器    386 :c:func:`__initcall()` ,它通过链接器的魔力确保在引导时调用该函数。
386                                                   387 
387 该函数可以返回一个错误值,以导    388 该函数可以返回一个错误值,以导致模块加载失败(不幸的是,如果将模块编译到内核
388 中,则此操作无效)。此函数在启    389 中,则此操作无效)。此函数在启用中断的用户上下文中调用,因此可以睡眠。
389                                                   390 
390 :c:func:`module_exit()`                           391 :c:func:`module_exit()`
391 -----------------------                           392 -----------------------
392                                                   393 
393                                                   394 
394 定义于  ``include/linux/module.h``             395 定义于  ``include/linux/module.h``
395                                                   396 
396 这个宏定义了在模块删除时要调用    397 这个宏定义了在模块删除时要调用的函数(如果是编译到内核中的文件,则无用武之地)。
397 只有在模块使用计数到零时才会调    398 只有在模块使用计数到零时才会调用它。这个函数也可以睡眠,但不能失败:当它返回
398 时,所有的东西都必须清理干净。     399 时,所有的东西都必须清理干净。
399                                                   400 
400 注意,这个宏是可选的:如果它不    401 注意,这个宏是可选的:如果它不存在,您的模块将不可移除(除非 ``rmmod -f`` )。
401                                                   402 
402 :c:func:`try_module_get()`/:c:func:`module_put    403 :c:func:`try_module_get()`/:c:func:`module_put()`
403 ----------------------------------------------    404 -------------------------------------------------
404                                                   405 
405 定义于 ``include/linux/module.h``              406 定义于 ``include/linux/module.h``
406                                                   407 
407 这些函数会操作模块使用计数,以    408 这些函数会操作模块使用计数,以防止删除(如果另一个模块使用其导出的符号之一,
408 则无法删除模块,参见下文)。在    409 则无法删除模块,参见下文)。在调用模块代码之前,您应该在该模块上调用
409 :c:func:`try_module_get()` :若失败,那    410 :c:func:`try_module_get()` :若失败,那么该模块将被删除,您应该将其视为不存在。
410 若成功,您就可以安全地进入模块    411 若成功,您就可以安全地进入模块,并在完成后调用模块 :c:func:`module_put()` 。
411                                                   412 
412 大多数可注册结构体都有所有者字    413 大多数可注册结构体都有所有者字段,例如在
413 :c:type:`struct file_operations <file_operatio    414 :c:type:`struct file_operations <file_operations>` 结构体中,此字段应设置为
414 宏 ``THIS_MODULE`` 。                           415 宏 ``THIS_MODULE`` 。
415                                                   416 
416 等待队列 ``include/linux/wait.h``             417 等待队列 ``include/linux/wait.h``
417 ====================================              418 ====================================
418                                                   419 
419 **[睡眠]**                                      420 **[睡眠]**
420                                                   421 
421 等待队列用于等待某程序在条件为    422 等待队列用于等待某程序在条件为真时唤醒另一程序。必须小心使用,以确保没有竞争
422 条件。先声明一个 :c:type:`wait_queue_h    423 条件。先声明一个 :c:type:`wait_queue_head_t` ,然后对希望等待该条件的进程声明
423 一个关于它们自己的 :c:type:`wait_queu    424 一个关于它们自己的 :c:type:`wait_queue_entry_t` ,并将其放入队列中。
424                                                   425 
425 声明                                            426 声明
426 -----                                             427 -----
427                                                   428 
428 使用 :c:func:`DECLARE_WAIT_QUEUE_HEAD()` 宏    429 使用 :c:func:`DECLARE_WAIT_QUEUE_HEAD()` 宏声明一个 ``wait_queue_head_t`` ,
429 或者在初始化代码中使用 :c:func:`ini    430 或者在初始化代码中使用 :c:func:`init_waitqueue_head()` 程序。
430                                                   431 
431 排队                                            432 排队
432 -----                                             433 -----
433                                                   434 
434 将自己放在等待队列中相当复杂,    435 将自己放在等待队列中相当复杂,因为你必须在检查条件之前将自己放入队列中。有一
435 个宏可以来执行此操作: :c:func:`wai    436 个宏可以来执行此操作: :c:func:`wait_event_interruptible()`
436 ( ``include/linux/wait.h`` )第一个参    437 ( ``include/linux/wait.h`` )第一个参数是等待队列头,第二个参数是计算的表达
437 式;当该表达式为true时宏返回0,    438 式;当该表达式为true时宏返回0,或者在接收到信号时返回 ``-ERESTARTSYS`` 。
438 :c:func:`wait_event()` 版本会忽略信号    439 :c:func:`wait_event()` 版本会忽略信号。
439                                                   440 
440 唤醒排队任务                                441 唤醒排队任务
441 -------------                                     442 -------------
442                                                   443 
443 调用 :c:func:`wake_up()` ( ``include/linux    444 调用 :c:func:`wake_up()` ( ``include/linux/wait.h`` ),它将唤醒队列中的所有
444 进程。例外情况:如果有一个进程    445 进程。例外情况:如果有一个进程设置了 ``TASK_EXCLUSIVE`` ,队列的其余部分将不
445 会被唤醒。这个基本函数的其他变    446 会被唤醒。这个基本函数的其他变体也可以在同一个头文件中使用。
446                                                   447 
447 原子操作                                      448 原子操作
448 =========                                         449 =========
449                                                   450 
450 某些操作在所有平台上都有保证。    451 某些操作在所有平台上都有保证。第一类为操作 :c:type:`atomic_t`
451 ( ``include/asm/atomic.h`` )的函数;    452 ( ``include/asm/atomic.h`` )的函数;它包含一个有符号整数(至少32位长),
452 您必须使用这些函数来操作或读取     453 您必须使用这些函数来操作或读取 :c:type:`atomic_t` 变量。
453 :c:func:`atomic_read()` 和 :c:func:`atomic_se    454 :c:func:`atomic_read()` 和 :c:func:`atomic_set()` 获取并设置计数器,还有
454 :c:func:`atomic_add()` ,:c:func:`atomic_sub(    455 :c:func:`atomic_add()` ,:c:func:`atomic_sub()` ,:c:func:`atomic_inc()` ,
455 :c:func:`atomic_dec()` 和 :c:func:`atomic_dec    456 :c:func:`atomic_dec()` 和 :c:func:`atomic_dec_and_test()` (如果递减为零,
456 则返回true)。                               457 则返回true)。
457                                                   458 
458 是的。它在原子变量为零时返回true    459 是的。它在原子变量为零时返回true(即!=0)。
459                                                   460 
460 请注意,这些函数比普通的算术运    461 请注意,这些函数比普通的算术运算速度慢,因此不应过度使用。
461                                                   462 
462 第二类原子操作是在 ``unsigned long``     463 第二类原子操作是在 ``unsigned long`` ( ``include/linux/bitops.h`` )上的
463 原子位操作。这些操作通常采用指    464 原子位操作。这些操作通常采用指向位模式(bit pattern)的指针,第0位是最低有效
464 位。:c:func:`set_bit()`,:c:func:`clear_bit    465 位。:c:func:`set_bit()`,:c:func:`clear_bit()` 和 :c:func:`change_bit()` 设置、
465 清除和更改给定位。:c:func:`test_and_s    466 清除和更改给定位。:c:func:`test_and_set_bit()` ,:c:func:`test_and_clear_bit()`
466 和 :c:func:`test_and_change_bit()` 执行相    467 和 :c:func:`test_and_change_bit()` 执行相同的操作,但如果之前设置了位,则返回
467 true;这些对于原子设置标志特别有    468 true;这些对于原子设置标志特别有用。
468                                                   469 
469 可以使用大于 ``BITS_PER_LONG`` 位的位    470 可以使用大于 ``BITS_PER_LONG`` 位的位索引调用这些操作。但结果在大端序平台上
470 不太正常,所以最好不要这样做。     471 不太正常,所以最好不要这样做。
471                                                   472 
472 符号                                            473 符号
473 =====                                             474 =====
474                                                   475 
475 在内核内部,正常的链接规则仍然    476 在内核内部,正常的链接规则仍然适用(即除非用static关键字将符号声明为文件范围,
476 否则它可以在内核中的任何位置使    477 否则它可以在内核中的任何位置使用)。但是对于模块,会保留一个特殊可导出符号表,
477 该表将入口点限制为内核内部。模    478 该表将入口点限制为内核内部。模块也可以导出符号。
478                                                   479 
479 :c:func:`EXPORT_SYMBOL()`                         480 :c:func:`EXPORT_SYMBOL()`
480 -------------------------                         481 -------------------------
481                                                   482 
482 定义于 ``include/linux/export.h``              483 定义于 ``include/linux/export.h``
483                                                   484 
484 这是导出符号的经典方法:动态加    485 这是导出符号的经典方法:动态加载的模块将能够正常使用符号。
485                                                   486 
486 :c:func:`EXPORT_SYMBOL_GPL()`                     487 :c:func:`EXPORT_SYMBOL_GPL()`
487 -----------------------------                     488 -----------------------------
488                                                   489 
489 定义于 ``include/linux/export.h``              490 定义于 ``include/linux/export.h``
490                                                   491 
491                                                   492 
492 类似于 :c:func:`EXPORT_SYMBOL()`,只是 :    493 类似于 :c:func:`EXPORT_SYMBOL()`,只是 :c:func:`EXPORT_SYMBOL_GPL()` 导出的
493 符号只能由具有由 :c:func:`MODULE_LICEN    494 符号只能由具有由 :c:func:`MODULE_LICENSE()` 指定GPL兼容许可证的模块看到。这
494 意味着此函数被认为是一个内部实    495 意味着此函数被认为是一个内部实现问题,而不是一个真正的接口。一些维护人员和
495 开发人员在添加一些新的API或功能    496 开发人员在添加一些新的API或功能时可能却需要导出 EXPORT_SYMBOL_GPL()。
496                                                   497 
497 :c:func:`EXPORT_SYMBOL_NS()`                      498 :c:func:`EXPORT_SYMBOL_NS()`
498 ----------------------------                      499 ----------------------------
499                                                   500 
500 定义于 ``include/linux/export.h``              501 定义于 ``include/linux/export.h``
501                                                   502 
502 这是 ``EXPORT_SYMBOL()`` 的变体,允许    503 这是 ``EXPORT_SYMBOL()`` 的变体,允许指定符号命名空间。符号名称空间记录于
503 Documentation/core-api/symbol-namespaces.rst     504 Documentation/core-api/symbol-namespaces.rst 。
504                                                   505 
505 :c:func:`EXPORT_SYMBOL_NS_GPL()`                  506 :c:func:`EXPORT_SYMBOL_NS_GPL()`
506 --------------------------------                  507 --------------------------------
507                                                   508 
508 定义于 ``include/linux/export.h``              509 定义于 ``include/linux/export.h``
509                                                   510 
510 这是 ``EXPORT_SYMBOL_GPL()`` 的变体,允    511 这是 ``EXPORT_SYMBOL_GPL()`` 的变体,允许指定符号命名空间。符号名称空间记录于
511 Documentation/core-api/symbol-namespaces.rst     512 Documentation/core-api/symbol-namespaces.rst 。
512                                                   513 
513 程序与惯例                                   514 程序与惯例
514 ===========                                       515 ===========
515                                                   516 
516 双向链表 ``include/linux/list.h``             517 双向链表 ``include/linux/list.h``
517 -----------------------------------               518 -----------------------------------
518                                                   519 
519 内核头文件中曾经有三组链表程序    520 内核头文件中曾经有三组链表程序,但这一组是赢家。如果你对一个单链表没有特别迫切的
520 需求,那么这是一个不错的选择。     521 需求,那么这是一个不错的选择。
521                                                   522 
522 通常 :c:func:`list_for_each_entry()` 很有    523 通常 :c:func:`list_for_each_entry()` 很有用。
523                                                   524 
524 返回值惯例                                   525 返回值惯例
525 ------------                                      526 ------------
526                                                   527 
527 对于在用户上下文中调用的代码,    528 对于在用户上下文中调用的代码,违背C语言惯例是很常见的,即返回0表示成功,返回
528 负错误值(例如 ``-EFAULT`` )表示失    529 负错误值(例如 ``-EFAULT`` )表示失败。这在一开始可能是不直观的,但在内核中
529 相当普遍。                                   530 相当普遍。
530                                                   531 
531 使用 :c:func:`ERR_PTR()` ( ``include/linux    532 使用 :c:func:`ERR_PTR()` ( ``include/linux/err.h`` )将负错误值编码到指针中,
532 然后使用 :c:func:`IS_ERR()` 和 :c:func:`P    533 然后使用 :c:func:`IS_ERR()` 和 :c:func:`PTR_ERR()` 将其再取出:避免为错误值
533 使用单独的指针参数。挺讨厌的,    534 使用单独的指针参数。挺讨厌的,但的确是个好方式。
534                                                   535 
535 破坏编译                                      536 破坏编译
536 ----------                                        537 ----------
537                                                   538 
538 Linus和其他开发人员有时会更改开    539 Linus和其他开发人员有时会更改开发内核中的函数或结构体名称;这样做不仅是为了
539 让每个人都保持警惕,还反映了一    540 让每个人都保持警惕,还反映了一个重大的更改(例如,不能再在打开中断的情况下
540 调用,或者执行额外的检查,或者 !! 541 调用,或者执行额外的检查,或者不执行以前捕获的检查)。通常这会附带一个linux
541 相当全面的注释到相应的内核邮件 !! 542 内核邮件列表中相当全面的注释;请搜索存档以查看。简单地对文件进行全局替换通常
542 替换通常只会让事情变得 **更糟**  !! 543 会让事情变得 **更糟** 。
543                                                   544 
544 初始化结构体成员                          545 初始化结构体成员
545 ------------------                                546 ------------------
546                                                   547 
547 初始化结构体的首选方法是使用指    548 初始化结构体的首选方法是使用指定的初始化器,如ISO C99所述。
548 例如::                                          549 例如::
549                                                   550 
550     static struct block_device_operations opt_    551     static struct block_device_operations opt_fops = {
551             .open               = opt_open,       552             .open               = opt_open,
552             .release            = opt_release,    553             .release            = opt_release,
553             .ioctl              = opt_ioctl,      554             .ioctl              = opt_ioctl,
554             .check_media_change = opt_media_ch    555             .check_media_change = opt_media_change,
555     };                                            556     };
556                                                   557 
557                                                   558 
558 这使得很容易查找(grep),并且可    559 这使得很容易查找(grep),并且可以清楚地看到设置了哪些结构字段。你应该这样做,
559 因为它看起来很酷。                       560 因为它看起来很酷。
560                                                   561 
561 GNU 扩展                                        562 GNU 扩展
562 ----------                                        563 ----------
563                                                   564 
564 Linux内核中明确允许GNU扩展。请注    565 Linux内核中明确允许GNU扩展。请注意,由于缺乏通用性,一些更复杂的版本并没有
565 得到很好的支持,但以下内容被认    566 得到很好的支持,但以下内容被认为是标准的(有关更多详细信息,请参阅GCC info页
566 的“C 扩展”部分——是的,实际    567 的“C 扩展”部分——是的,实际上是info页,手册页只是info中内容的简短摘要)。
567                                                   568 
568 - 内联函数                                    569 - 内联函数
569                                                   570 
570 - 语句表达式(Statement expressions)    571 - 语句表达式(Statement expressions)(即({ 和 })结构)。
571                                                   572 
572                                                   573 
573 - 声明函数/变量/类型的属性(__attr    574 - 声明函数/变量/类型的属性(__attribute__)
574                                                   575 
575 - typeof                                          576 - typeof
576                                                   577 
577 - 零长度数组                                 578 - 零长度数组
578                                                   579 
579 - 宏变量                                       580 - 宏变量
580                                                   581 
581 - 空指针运算                                 582 - 空指针运算
582                                                   583 
583 - 非常量(Non-Constant)初始化程序      584 - 非常量(Non-Constant)初始化程序
584                                                   585 
585 - 汇编程序指令(在 arch/ 和 include/a    586 - 汇编程序指令(在 arch/ 和 include/asm/ 之内)
586                                                   587 
587 - 字符串函数名(__func__)。             588 - 字符串函数名(__func__)。
588                                                   589 
589 - __builtin_constant_p()                          590 - __builtin_constant_p()
590                                                   591 
591 在内核中使用long long时要小心,gcc    592 在内核中使用long long时要小心,gcc为其生成的代码非常糟糕:除法和乘法在i386上
592 不能工作,因为内核环境中缺少用    593 不能工作,因为内核环境中缺少用于它的gcc运行时函数。
593                                                   594 
594 C++                                               595 C++
595 ---                                               596 ---
596                                                   597 
597 在内核中使用C++通常是个坏主意,    598 在内核中使用C++通常是个坏主意,因为内核不提供必要的运行时环境,并且不为其
598 测试包含文件。不过这仍然是可能    599 测试包含文件。不过这仍然是可能的,但不建议。如果你真的想这么做,至少别用
599 异常处理(exceptions)。                   600 异常处理(exceptions)。
600                                                   601 
601 #if                                               602 #if
602 ---                                               603 ---
603                                                   604 
604 通常认为,在头文件(或.c文件顶    605 通常认为,在头文件(或.c文件顶部)中使用宏来抽象函数比在源代码中使用“if”预
605 处理器语句更干净。                       606 处理器语句更干净。
606                                                   607 
607 把你的东西放进内核里                    608 把你的东西放进内核里
608 ======================                            609 ======================
609                                                   610 
610 为了让你的东西更正式、补丁更整    611 为了让你的东西更正式、补丁更整洁,还有一些工作要做:
611                                                   612 
612 -  搞清楚你修改的代码属于谁。查 !! 613 -  搞清楚你在谁的地界儿上干活。查看源文件的顶部、 ``MAINTAINERS`` 文件以及
613    ``CREDITS`` 文件的最后一部分。你    614    ``CREDITS`` 文件的最后一部分。你应该和此人协调,确保你没有重新发明轮子,
614    或者尝试一些已经被拒绝的东西    615    或者尝试一些已经被拒绝的东西。
615                                                   616 
616    确保你把你的名字和电子邮件地    617    确保你把你的名字和电子邮件地址放在你创建或修改的任何文件的顶部。当人们发
617    现一个缺陷,或者想要做出修改    618    现一个缺陷,或者想要做出修改时,这是他们首先会看的地方。
618                                                   619 
619 -  通常你需要一个配置选项来支持    620 -  通常你需要一个配置选项来支持你的内核编程。在适当的目录中编辑 ``Kconfig`` 。
620    配置语言很容易通过剪切和粘贴    621    配置语言很容易通过剪切和粘贴来使用,在
621    Documentation/kbuild/kconfig-language.rst     622    Documentation/kbuild/kconfig-language.rst 中有完整的文档。
622                                                   623 
623    在您对选项的描述中,请确保同    624    在您对选项的描述中,请确保同时照顾到了专家用户和对此功能一无所知的用户。
624    在此说明任何不兼容和问题。结    625    在此说明任何不兼容和问题。结尾一定要写上“如有疑问,就选N”(或者是“Y”);
625    这是针对那些看不懂你在说什么    626    这是针对那些看不懂你在说什么的人的。
626                                                   627 
627 -  编辑 ``Makefile`` :配置变量在这    628 -  编辑 ``Makefile`` :配置变量在这里导出,因此通常你只需添加一行
628    “obj-$(CONFIG_xxx) += xxx.o”。语法    629    “obj-$(CONFIG_xxx) += xxx.o”。语法记录在
629    Documentation/kbuild/makefiles.rst 。         630    Documentation/kbuild/makefiles.rst 。
630                                                   631 
631 -  如果你认为自己做了一些有意义 !! 632 -  如果你做了一些有意义的事情,那可以把自己放进 ``CREDITS`` ,通常不止一个
632    止一个文件(无论如何你的名字 !! 633    文件(无论如何你的名字都应该在源文件的顶部)。维护人员意味着您希望在对
633    意味着您希望在对子系统进行更 !! 634    子系统进行更改时得到询问,并了解缺陷;这意味着对某部分代码做出更多承诺。
634    代码做出更多承诺。                 << 
635                                                   635 
636 -  最后,别忘记去阅读 Documentation/p !! 636 -  最后,别忘记去阅读 Documentation/process/submitting-patches.rst ,
                                                   >> 637    也许还有 Documentation/process/submitting-drivers.rst 。
637                                                   638 
638 Kernel 仙女棒                                  639 Kernel 仙女棒
639 ===============                                   640 ===============
640                                                   641 
641 浏览源代码时的一些收藏。请随意    642 浏览源代码时的一些收藏。请随意添加到此列表。
642                                                   643 
643 ``arch/x86/include/asm/delay.h``::                644 ``arch/x86/include/asm/delay.h``::
644                                                   645 
645     #define ndelay(n) (__builtin_constant_p(n)    646     #define ndelay(n) (__builtin_constant_p(n) ? \
646             ((n) > 20000 ? __bad_ndelay() : __    647             ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \
647             __ndelay(n))                          648             __ndelay(n))
648                                                   649 
649                                                   650 
650 ``include/linux/fs.h``::                          651 ``include/linux/fs.h``::
651                                                   652 
652     /*                                            653     /*
653      * Kernel pointers have redundant informat    654      * Kernel pointers have redundant information, so we can use a
654      * scheme where we can return either an er    655      * scheme where we can return either an error code or a dentry
655      * pointer with the same return value.        656      * pointer with the same return value.
656      *                                            657      *
657      * This should be a per-architecture thing    658      * This should be a per-architecture thing, to allow different
658      * error and pointer decisions.               659      * error and pointer decisions.
659      */                                           660      */
660      #define ERR_PTR(err)    ((void *)((long)(    661      #define ERR_PTR(err)    ((void *)((long)(err)))
661      #define PTR_ERR(ptr)    ((long)(ptr))        662      #define PTR_ERR(ptr)    ((long)(ptr))
662      #define IS_ERR(ptr)     ((unsigned long)(    663      #define IS_ERR(ptr)     ((unsigned long)(ptr) > (unsigned long)(-1000))
663                                                   664 
664 ``arch/x86/include/asm/uaccess_32.h:``::          665 ``arch/x86/include/asm/uaccess_32.h:``::
665                                                   666 
666     #define copy_to_user(to,from,n)               667     #define copy_to_user(to,from,n)                         \
667             (__builtin_constant_p(n) ?            668             (__builtin_constant_p(n) ?                      \
668              __constant_copy_to_user((to),(fro    669              __constant_copy_to_user((to),(from),(n)) :     \
669              __generic_copy_to_user((to),(from    670              __generic_copy_to_user((to),(from),(n)))
670                                                   671 
671                                                   672 
672 ``arch/sparc/kernel/head.S:``::                   673 ``arch/sparc/kernel/head.S:``::
673                                                   674 
674     /*                                            675     /*
675      * Sun people can't spell worth damn. "com    676      * Sun people can't spell worth damn. "compatibility" indeed.
676      * At least we *know* we can't spell, and     677      * At least we *know* we can't spell, and use a spell-checker.
677      */                                           678      */
678                                                   679 
679     /* Uh, actually Linus it is I who cannot s    680     /* Uh, actually Linus it is I who cannot spell. Too much murky
680      * Sparc assembly will do this to ya.         681      * Sparc assembly will do this to ya.
681      */                                           682      */
682     C_LABEL(cputypvar):                           683     C_LABEL(cputypvar):
683             .asciz "compatibility"                684             .asciz "compatibility"
684                                                   685 
685     /* Tested on SS-5, SS-10. Probably someone    686     /* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. */
686             .align 4                              687             .align 4
687     C_LABEL(cputypvar_sun4m):                     688     C_LABEL(cputypvar_sun4m):
688             .asciz "compatible"                   689             .asciz "compatible"
689                                                   690 
690                                                   691 
691 ``arch/sparc/lib/checksum.S:``::                  692 ``arch/sparc/lib/checksum.S:``::
692                                                   693 
693             /* Sun, you just can't beat me, yo    694             /* Sun, you just can't beat me, you just can't.  Stop trying,
694              * give up.  I'm serious, I am goi    695              * give up.  I'm serious, I am going to kick the living shit
695              * out of you, game over, lights o    696              * out of you, game over, lights out.
696              */                                   697              */
697                                                   698 
698                                                   699 
699 致谢                                            700 致谢
700 =====                                             701 =====
701                                                   702 
702 感谢Andi Kleen提出点子,回答我的问    703 感谢Andi Kleen提出点子,回答我的问题,纠正我的错误,充实内容等帮助。
703 感谢Philipp Rumpf做了许多拼写和清晰    704 感谢Philipp Rumpf做了许多拼写和清晰度修复,以及一些优秀的不明显的点。
704 感谢Werner Almesberger对 :c:func:`disable_i    705 感谢Werner Almesberger对 :c:func:`disable_irq()` 做了一个很好的总结,
705 Jes Sorensen和Andrea Arcangeli补充了一些    706 Jes Sorensen和Andrea Arcangeli补充了一些注意事项。
706 感谢Michael Elizabeth Chastain检查并补    707 感谢Michael Elizabeth Chastain检查并补充了配置部分。
707 感谢Telsa Gwynne教我DocBook。                708 感谢Telsa Gwynne教我DocBook。
                                                      

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php