~ [ 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-6.4.16)


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