diff --git a/.gitignore b/.gitignore index 62c8935..f32e31a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.idea/ \ No newline at end of file +.idea/ +.DS_Store diff --git a/Intel 手册中文版/卷一:基本架构.md b/Intel 手册中文版/卷一:基本架构.md index 29a4aff..a138fdf 100644 --- a/Intel 手册中文版/卷一:基本架构.md +++ b/Intel 手册中文版/卷一:基本架构.md @@ -532,12 +532,43 @@ CS , DS , SS 和 ES 这四个段寄存器与 Intel 8086 and Intel 286 处理器 @翻译人:符宇舟Alex +## 4.3 POINTER DATA TYPES + +@翻译人:Colinxu2020 + +指针是指向内存中一个位置的地址。 + +在非64位模式下,该架构定义了两种类型的指针:近指针和远指针。一个近指针是一个段内的32位(或16位)偏移(也称为有效地址)。 + +近指针用于平坦的内存模型中的所有内存引用,或者用于分段内存模型中的引用,其中被访问段的基址是隐含的。 + +远指针是一个逻辑地址,由一个16位段选择器和一个32位(或16位)偏移量组成。远指针用于分段内存模型中的内存引用,其中被访问段的身份必须明确指定。 + +带有32位偏移量的近指针和远指针如图4-4所示 + +图4-4 + +### 4.3.1 Pointer Data Types in 64-Bit Mode + +在64位模式(IA-32e 模式的一个子模式)中,一个近指针是64位。这等同于一个有效的地址。 + +64位模式下的远指针可以是三种形式之一。 + +- 16位段选择器,16位偏移,如果操作数是32位的话 +- 16位段选择器,32位偏移,如果操作数是32位的话 +- 如果操作数为64位,16位段选择器,64位偏移量 + +见图4-5 + +图4-5 + ## 4.4 BIT FIELD DATA TYPE [@翻译人:Hola39e](https://github.com/Hola39e) 位域数据类型(见图4-6)是一个连续的比特序列。它可以从内存中任何字节的任何位开始,最多可以包含32位。 - Figure 4-6 here +Figure 4-6 here + ## 4.5 STRING DATA TYPES [@翻译人:Hola39e](https://github.com/Hola39e) @@ -547,20 +578,22 @@ CS , DS , SS 和 ES 这四个段寄存器与 Intel 8086 and Intel 286 处理器 [@翻译人:Hola39e](https://github.com/Hola39e) Intel64和IA-32架构定义与操作一组64位和128位包装(Packed)数据类型,中文又称数据向量,用于单指令多数据流(SIMD)操作。这些打包数据类型的由基本的数据类型(打包对齐的字节、字、双字和四字组成),以及用于进行矢量运算(Packed)指令操作的整数,浮点数基本类型的数值说明。 + ### 4.6.1 64-Bit SIMD Packed Data Types [@翻译人:Hola39e](https://github.com/Hola39e) 64位包装(Packed)SIMD数据结构是在Intel MXX指令集中加入到IA-32中去的。它们在MXX寄存器中被操作。基本的64位包装数据类型是打包对齐起来的字节、字以及双字(见图4-7)。当执行SIMD操作时,这些数据结构会被解释成 进行矢量运算(Packed)指令操作的字节、字、双字长度的整数值。 - Figure 4-7 here +Figure 4-7 here ### 4.6.2 128-Bit Packed SIMD Data Types [@翻译人:Hola39e](https://github.com/Hola39e) 128位包装(Packed)SIMD数据结构是在SSE扩展指令集中被引入到IA-32中去的,在SSE2,SSE3,SSSE3扩展指令集中被使用。它们主要在128位的XMM寄存器和内存中进行操作,基本的128位包装数据类型是打包对齐起来的字节、字、双字、四字组成的(见图4-8)。当对在XMM寄存器中保存的包装(Packed)数据类型执行SIMD操作时,这些数据类型会被解释进行矢量运算(Packed)指令操作或标量运算(Scalar)指令操作的单精度浮点数或双精度浮点数,或者进行矢量运算(Packed)的长度为字节、字、双字、四字的整数值。 - Figure 4-8 here +Figure 4-8 here + # 第五章 Instruction Set Summary # 第六章 Procedure Calls, Interrupts, and Exceptions @@ -580,6 +613,64 @@ Intel64和IA-32架构定义与操作一组64位和128位包装(Packed)数据 ### 6.4.1 Call and Return Operation for Interrupt or Exception Handling Procedures @翻译人:si +6.4 使用CALL和RET指令调用程序 (CALLING PROCEDURES USING CALL AND RET) + +注:procedures译为代码,program译为程序 + +  CALL 指令允许代码控制跳转到当前代码段(近调用 near call)和不同程序代码段(远调用 far call)。近调用通常在当前运行程序或任务中提供代码访问。远调用通常访问操作系统代码或不同任务中的代码。参见第三章的 ”CALL-Call Procedure“ 。在 *Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 2A*的“Instruction Set Reference, A-L” 中有对CALL指令更深层次的描述。 + +  RET 指令也允许近或远的返回以匹配进或远版本的 CALL 指令。另外,RET 指令允许程序在返回时递增栈指针来释放栈上的参数。具体要在栈上释放多少字节决定于 RET 指令上的可选参数(n)。在 *Intel® 64 and* *IA-32 Architectures Software Developer’s Manual, Volume 2B* 的 ”Instruction Set Reference, M-U“ 中有对 RET 指令更详细的介绍。 + +6.4.1 Near CALL and RET Operation + +  当执行近调用时,处理器会做以下这些事情(参见图 6-2 ) + +1. 将 EIP 寄存器的当前值压到栈中。 + 如果影子栈(shadow stack)被启用而且置换值为非零,将 EIP 寄存器的当前值压入影子栈中。 +2. 在 EIP 寄存器中加载被调用代码的偏移量。 +3. 开始执行被调用的代码 + +当执行的近返回(near return)时,处理器会执行这些动作: + +1. 弹出栈顶的值(返回指令指针)到 EIP 寄存器中。 + 如果影子栈被启用,从影子栈弹出栈顶值(返回指令指针)如果与从栈中弹出的指令指针不同,处理器会报一个控制保护异常,错误码为NEAR-RET(#CP(NEAR-RET))。 +2. 如果 RET 指令有一个可选的 n 参数,按 n 操作数指定的字节数递增栈指针以从栈中释放参数 。 +3. 恢复调用代码的运行。 + +6.4.2 Far CALL and RET Operation + +  当执行远调用时,处理器会执行这些动作(见图6-2): + +1. 将 CS 寄存器的当前值压入栈中。 + + 如果影子栈被启用: + + a. 临时内部保存 SPP 寄存器的当前值,将SPP与下一个8字节边界对齐。 + + b. 将 CS 寄存器的当前值压入影子栈。 + + c. 将 LIP(CS.base + EIP)的当前值压入影子栈。 + + d. 将 SSP 寄存器内部保存值压入影子栈。 + +2. 将 EIP 寄存器的当前值压入栈中。 + +3. 加载包含调用代码的段的段选择子到 CS 寄存器中。 + +4. 加载调用代码的偏移值到 EIP 寄存器中。 + +5. 开始执行调用代码的运行。 + +当执行远返回时,处理器会做下面这些事情: + +1. 弹出栈顶值(返回指令指针)到 EIP 寄存器中。 +2. 弹出栈顶值(返回代码段的段选择子)到CS寄存器中。 + 如果启用了影子寄存器 + a. 产生控制保护异常(#CP(FAR-RET/IRET))如果 SSP 没有对齐8字节。 + b. 将影子栈在 SSP+8(LIP)地址的值 和SSP + 16(CS)的值与 从栈中弹出的 CS 和(CS.base + EIP)相比较。如果没有匹配,产生控制保护异常(#CP(FAR-RET/IRET)) + c. 弹出栈顶值(返回代码的SSP)从影子栈到 SSP 寄存器中。 +3. 如果返回指令有可选参数n,按 n 操作数递增栈指针 n 个数量的字节以从栈上释放参数。 +4. 恢复调用代码的运行。 # 第七章 Programming With General-Purpose Instructions diff --git a/Intel 手册中文版/卷三:系统编程指南.md b/Intel 手册中文版/卷三:系统编程指南.md index 3784eab..ffb53d5 100644 --- a/Intel 手册中文版/卷三:系统编程指南.md +++ b/Intel 手册中文版/卷三:系统编程指南.md @@ -1,9 +1,9 @@ 翻译前先阅读整体规则的 [README](https://github.com/sunym1993/flash-linux0.11-talk/blob/main/Intel%20%E6%89%8B%E5%86%8C%E4%B8%AD%E6%96%87%E7%89%88/README.md) 哟~ - +@翻译人: 17cao # 第一章 About This Manual - +@翻译人: 17cao # 第二章 System Architecture Overview - +@翻译人: 17cao # 第三章 Protected-Mode Memory Management # 第四章 Paging diff --git a/README.md b/README.md index 0c995ab..b1bffd3 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,10 @@ **发文时间**:每周一和每周四 +**互动方式**:微信群(关注公众号并回复“os”) + +**创作番外故事**:[知识星球](https://mp.weixin.qq.com/s/NFUgJ4-hIyrs1sQr8AUCvA) + **开篇词**:[闪客新系列!你管这破玩意叫操作系统源码](https://mp.weixin.qq.com/s/tvbkGLfhDq03xxM-FZ4zuA) **一些非必须的资料**:[资料包](https://github.com/sunym1993/flash-linux0.11-talk/tree/main/%E4%B8%80%E4%BA%9B%E9%9D%9E%E5%BF%85%E8%A6%81%E7%9A%84%E8%B5%84%E6%96%99) @@ -23,6 +27,8 @@ **还有个有趣的事情大家可以共同参与进来**:[Intel手册翻译计划](https://github.com/sunym1993/flash-linux0.11-talk/tree/main/Intel%20%E6%89%8B%E5%86%8C%E4%B8%AD%E6%96%87%E7%89%88) +当然,欢迎大家一同维护这个项目,有关操作系统普及的各种信息,都可以发起 PR 提交 + --- **架构图** @@ -37,22 +43,39 @@ * **第一部分:进入内核前的苦力活** - * [第一回 最开始的两行代码](https://mp.weixin.qq.com/s/LIsqRX51W7d_yw-HN-s2DA) - * [第二回 自己给自己挪个地儿](https://mp.weixin.qq.com/s/U-txDYt0YqLh5EeFOcB4NQ) - * [第三回 做好最最基础的准备工作](https://mp.weixin.qq.com/s/90QBJ-lP_-du2qQJxNF-Fw) - * [第四回 把自己在硬盘里的其他部分也放到内存来](https://mp.weixin.qq.com/s/hStc-y-sabP-KwJUDUesTw) - * [第五回 进入保护模式前的最后一次折腾内存](https://mp.weixin.qq.com/s/5s_nmrWRZbA_4mkNKOQ2Cg) - * [第六回 先解决段寄存器的历史包袱问题](https://mp.weixin.qq.com/s/p1a6QxYZyMpJF__uBSE1Kg) - * [第七回 六行代码就进入了保护模式](https://mp.weixin.qq.com/s/S5zarr9BmLhUHAmdmeNypA) - * [第八回 烦死了又要重新设置一遍 idt 和 gdt](https://mp.weixin.qq.com/s/ssQKFMehxZxWT9i6mdRtXg) - * [第九回 Intel 内存管理两板斧:分段与分页](https://mp.weixin.qq.com/s/q2wU9IbX54t_GAuc9V5r7A) - * [第十回 进入 main 函数前的最后一跃!](https://mp.weixin.qq.com/s/ISyaX5zPWRw_d-9zvZUPUg) + * [第1回 最开始的两行代码](https://mp.weixin.qq.com/s/LIsqRX51W7d_yw-HN-s2DA) + * [第2回 自己给自己挪个地儿](https://mp.weixin.qq.com/s/U-txDYt0YqLh5EeFOcB4NQ) + * [第3回 做好最最基础的准备工作](https://mp.weixin.qq.com/s/90QBJ-lP_-du2qQJxNF-Fw) + * [第4回 把自己在硬盘里的其他部分也放到内存来](https://mp.weixin.qq.com/s/hStc-y-sabP-KwJUDUesTw) + * [第5回 进入保护模式前的最后一次折腾内存](https://mp.weixin.qq.com/s/5s_nmrWRZbA_4mkNKOQ2Cg) + * [第6回 先解决段寄存器的历史包袱问题](https://mp.weixin.qq.com/s/p1a6QxYZyMpJF__uBSE1Kg) + * [第7回 六行代码就进入了保护模式](https://mp.weixin.qq.com/s/S5zarr9BmLhUHAmdmeNypA) + * [第8回 烦死了又要重新设置一遍 idt 和 gdt](https://mp.weixin.qq.com/s/ssQKFMehxZxWT9i6mdRtXg) + * [第9回 Intel 内存管理两板斧:分段与分页](https://mp.weixin.qq.com/s/q2wU9IbX54t_GAuc9V5r7A) + * [第10回 进入 main 函数前的最后一跃!](https://mp.weixin.qq.com/s/ISyaX5zPWRw_d-9zvZUPUg) * [第一部分总结与回顾](https://mp.weixin.qq.com/s/8bP3feeF_A13j7ysWur_JQ) * **第二部分:大战前期的初始化工作** + * [第11回 整个操作系统就20几行代码](https://mp.weixin.qq.com/s/kYBrMgHt7C9EmAcwJIPIxg) + * [第12回 管理内存前先划分出三个边界值](https://mp.weixin.qq.com/s/eoBFcgm0QrHOVi_WoS7PwA) + * [第13回 主内存初始化 mem_init](https://mp.weixin.qq.com/s/_rTmjHIDCV9ADiJlfo5B3g) + * [第14回 中断初始化 trap_init](https://mp.weixin.qq.com/s/sFp_388qRncB-jpJeRzCGQ) + * [第15回 块设备请求项初始化 blk_dev_init](https://mp.weixin.qq.com/s/pIbVY1XPCktxGogc4lI1Bw) + * [第16回 控制台初始化 tty_init](https://mp.weixin.qq.com/s/yIrzEWUUuZC9OsiuU_lOaw) + * [第17回 时间初始化 time_init](https://mp.weixin.qq.com/s/y26MMfj8pP5PmbKDZBT5-A) + * [第18回 进程调度初始化 sched_init](https://mp.weixin.qq.com/s/j4FYWUSX_2gpDb_h4vEFqQ) + * [第19回 缓冲区初始化 buffer_init](https://mp.weixin.qq.com/s/X8BSbf1qShS11_fzfyOhTg) + * [第20回 硬盘初始化 hd_init](https://mp.weixin.qq.com/s/803C9jHxIe42i9BrNzEvPA) + * [第二部分总结与回顾](https://mp.weixin.qq.com/s/Hf9B1ww1wFxiUDkWb0obeQ) + * **第三部分:一个新进程的诞生** + * [第21回 新进程诞生全局概述](https://mp.weixin.qq.com/s/H_OCZ2ZtGHWHge_rYKCkJw) + * [第22回 从内核态切换到用户态](https://mp.weixin.qq.com/s/AVl6R2N9d_sldkhfvC6aEw) + * [第23回 如果让你来设计进程调度](https://mp.weixin.qq.com/s/Sf9vV7RCnVDlBKXx5jXs1Q) + * [第24回 从一次定时器滴答来看进程调度](https://mp.weixin.qq.com/s/yFre8Qv_ZCtjRkTS49n6rw) + * **第四部分:shell 程序的到来** * **第五部分:从一个命令的执行看操作系统各模块的运作** diff --git a/file1615.pdf b/file1615.pdf new file mode 100644 index 0000000..47b31b9 Binary files /dev/null and b/file1615.pdf differ diff --git a/一些非必要的资料/x86汇编语言-从实模式到保护模式.pdf b/一些非必要的资料/x86汇编语言-从实模式到保护模式.pdf new file mode 100644 index 0000000..ed1656c Binary files /dev/null and b/一些非必要的资料/x86汇编语言-从实模式到保护模式.pdf differ diff --git a/一些非必要的资料/x86汇编语言_从实模式到保护模式(完整扫描版).pdf b/一些非必要的资料/x86汇编语言_从实模式到保护模式(完整扫描版).pdf deleted file mode 100644 index 93e53b4..0000000 Binary files a/一些非必要的资料/x86汇编语言_从实模式到保护模式(完整扫描版).pdf and /dev/null differ diff --git a/读者分享/Interrupt Table as Implemented by System BIOS b/读者分享/Interrupt Table as Implemented by System BIOS new file mode 100644 index 0000000..20f9a7d --- /dev/null +++ b/读者分享/Interrupt Table as Implemented by System BIOS @@ -0,0 +1,149 @@ + +From hjd(brace) + + +Intel Defined CPU Exception Table (see notes) + + Interrupt Function + + 0 Divide by zero + 1 Single step + 2 Non-maskable (NMI) + 3 Breakpoint + 4 Overflow trap + 5 BOUND range exceeded (186,286,386) + 6 Invalid opcode (186,286,386) + 7 Coprocessor not available (286,386) + 8 Double fault exception (286,386) + 9 Coprocessor segment overrun (286,386) + A Invalid task state segment (286,386) + B Segment not present (286,386) + C Stack exception (286,386) + D General protection exception (286,386) + E Page fault (286,386) + F Reserved + 10 Coprocessor error (286,386) + +IBM PC Hardware Interrupt Table (in order of priority) + + IRQ# Interrupt Function + + IRQ0 8 timer (55ms intervals, 18.2 per second) + IRQ1 9 keyboard service required + IRQ2 A slave 8259 or EGA/VGA vertical retrace + IRQ8 70 real time clock (AT,XT286,PS50+) + IRQ9 71 software redirected to IRQ2 (AT,XT286,PS50+) + IRQ10 72 reserved (AT,XT286,PS50+) + IRQ11 73 reserved (AT,XT286,PS50+) + IRQ12 74 mouse interrupt (PS50+) + IRQ13 75 numeric coprocessor error (AT,XT286,PS50+) + IRQ14 76 fixed disk controller (AT,XT286,PS50+) + IRQ15 77 reserved (AT,XT286,PS50+) + IRQ3 B COM2 or COM4 service required, (COM3-COM8 on MCA PS/2) + IRQ4 C COM1 or COM3 service required + IRQ5 D fixed disk or data request from LPT2 + IRQ6 E floppy disk service required + IRQ7 F data request from LPT1 (unreliable on IBM mono) + + +Interrupt Table as Implemented by System BIOS/DOS + + INT # Locus Function + + 0 CPU divide by zero + 1 CPU single step + 2 CPU non-maskable + 3 CPU breakpoint + 4 CPU overflow trap + 5 BIOS print screen + 6 CPU Invalid opcode (186,286,386) + 7 CPU coprocessor not available (286,386) + 8 IRQ0 timer (55ms intervals, 18.21590 per second) + 9 IRQ1 keyboard service required (see INT 9) + A IRQ2 slave 8259 or EGA/VGA vertical retrace + B IRQ3 COM2 service required (PS/2 MCA COM3-COM8) + C IRQ4 COM1 service required + D IRQ5 fixed disk or data request from LPT2 + E IRQ6 floppy disk service required + F IRQ7 data request from LPT1 (unreliable on IBM mono) + 10 BIOS video (see INT 10) + 11 BIOS Equipment determination (see INT 11) + 12 BIOS memory size (see INT 12) + 13 BIOS disk I/O service (see INT 13) + 14 BIOS serial communications (see INT 14) + 15 BIOS system services, cassette (see INT 15) + 16 BIOS keyboard services (see INT 16) + 17 BIOS parallel printer (see INT 17) + 18 BIOS ROM BASIC loader + 19 BIOS bootstrap loader (unreliable, see INT 19) + 1A BIOS time of day (see INT 1A) + 1B BIOS user defined ctrl-break handler (see INT 1B) + 1C BIOS user defined clock tick handler (see INT 1C) + 1D BIOS 6845 video parameter pointer + 1E BIOS diskette parameter pointer (base table) + 1F BIOS graphics character table + 20 DOS general program termination + 21 DOS function request services (see INT 21) + 22 DOS terminate address (see INT 22) + 23 DOS control break termination address (see INT 23) + 24 DOS critical error handler (see INT 24) + 25 DOS absolute disk read (see INT 25) + 26 DOS absolute disk write (see INT 26) + 27 DOS terminate and stay resident (see INT 27) + 28 DOS idle loop, issued by DOS when idle (see INT 28) + 29 DOS fast TTY console I/O (see INT 29) + 2A DOS critical section and NETBIOS (see INT 2A) + 2B DOS internal, simple IRET in DOS 2.0-5.0 + 2C DOS internal, simple IRET in DOS 2.0-5.0 + 2D DOS internal, simple IRET in DOS 2.0-5.0 + 2E DOS exec command from base level command + interpreter (see INT 2E) + 2F DOS multiplexer (see INT 2F) + 30-31 CPM far jump vector for CPM (not an interrupt) + 31 DPMI DOS Protected Mode Interface (for DOS extenders) + 32 reserved + 33 mouse support (see INT 33) + 34-3E Microsoft/Borland floating point emulation + 3F overlay manager + 40 BIOS hard disk + 41 BIOS fixed disk 0 parameters pointer (see INT 13,9) + 42 BIOS relocated video handler (EGA/VGA/PS) + 43 BIOS user font table (EGA/VGA/PS) + 44 BIOS first 128 graphics characters (also Netware) + 45 BIOS reserved for BIOS + 46 BIOS fixed disk 1 parameters ptr (see INT 13,9/INT 41) + 47 BIOS reserved for BIOS + 48 BIOS PCjr cordless keyboard translation + 49 BIOS PCjr non-keyboard scancode translation table + 4A BIOS user alarm (AT,CONV,PS/2) (see INT 4A) + 4B-4F BIOS reserved + 50 BIOS periodic alarm from timer (PS/2) + 51-58 BIOS reserved + 59 BIOS GSS Computer Graphics Interface + 5A BIOS cluster adapter BIOS entry point + 5B BIOS cluster adapter boot + 5C NETBIOS NETBIOS interface, TOPS interface + 5D-5F BIOS reserved for BIOS + 60-67 reserved for user software interrupts + 67 EMS LIM/EMS specification (see INT 67) + 68 APPC + 69-6B reserved by IBM + 6C DOS DOS 3.2 real time clock update + BIOS system resume vector + 6D-6F reserved + 70 IRQ8 real time clock (AT,XT286,PS50+, see INT 15) + 71 IRQ9 software redirected to IRQ2 (AT,XT286,PS50+) + 72 IRQ10 reserved (AT,XT286,PS50+) + 73 IRQ11 reserved (AT,XT286,PS50+) + 74 IRQ12 mouse interrupt (PS50+) + 75 IRQ13 numeric coprocessor NMI error (AT,XT286,PS50+) + 76 IRQ14 fixed disk controller (AT,XT286,PS50+) + 77 IRQ15 reserved (AT,XT286,PS50+) + 78-79 unused + 80-85 ROM BASIC + 86-F0 DOS reserved for BASIC interpreter use + 86 NETBIOS NETBIOS relocated INT 18 + E0 CPM CP/M 86 function calls + F1-FF reserved by IBM + FE-FF may be destroyed by return from protected + mode using VDISK on 286 machines (Apr 86, DDJ) diff --git a/读者分享/README.md b/读者分享/README.md index 653f781..553965a 100644 --- a/读者分享/README.md +++ b/读者分享/README.md @@ -1 +1 @@ -这里是读者们上传的,请尽情发挥你们的见解吧! +这里的世界,交给大家一起建设! diff --git a/读者分享/file1615.pdf b/读者分享/file1615.pdf new file mode 100644 index 0000000..47b31b9 Binary files /dev/null and b/读者分享/file1615.pdf differ diff --git a/读者分享/linux调度算法解析 23回补充资料.md b/读者分享/linux调度算法解析 23回补充资料.md new file mode 100644 index 0000000..94ca97f --- /dev/null +++ b/读者分享/linux调度算法解析 23回补充资料.md @@ -0,0 +1,69 @@ +23回补充内容 by sn: + +0.11 的调度函数 schedule,在文件 kernel/sched.c 中定义为: + +```c +while (1) { + c = -1; next = 0; i = NR_TASKS; p = &task[NR_TASKS]; + +// 找到 counter 值最大的就绪态进程 + while (--i) { + if (!*--p) continue; + if ((*p)->state == TASK_RUNNING && (*p)->counter > c) + c = (*p)->counter, next = i; + } + +// 如果有 counter 值大于 0 的就绪态进程,则退出 + if (c) break; + +// 如果没有: +// 所有进程的 counter 值除以 2 衰减后再和 priority 值相加, +// 产生新的时间片 + for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if (*p) (*p)->counter = ((*p)->counter >> 1) + (*p)->priority; +} + +// 切换到 next 进程 +switch_to(next); +``` + + +由上面的程序可以看出,0.11 的调度算法是选取 `counter` 值最大的就绪进程进行调度。 +当没有 counter 值大于 0 的就绪进程时,要对所有的进程做 `(*p)->counter = ((*p)->counter >> 1) + (*p)->priority`。 +其效果是对所有的进程(**包括阻塞态进程**)都进行 counter 的衰减,并再累加 priority 值。这样,对正被阻塞的进程来说,其此时的counter不为0,那么计算后得到的counter大于就绪态进程。 +于是可知,**一个进程在阻塞队列中停留的时间越长,其优先级越大,被分配的时间片也就会越大**。 + + +所以总的来说,Linux 0.11 的进程调度是一种**综合考虑进程优先级并能动态反馈调整时间片的轮转调度算法**。 + + + +## 进程 counter 是如何初始化的 + +首先回答第一个问题,显然这个值是在 fork() 中设定的。Linux 0.11 的 `fork()` 会调用 `copy_process()` 来完成从父进程信息拷贝(所以才称其为 fork),看看 `copy_process()` 的实现,会发现其中有下面两条语句: + +```c +// 用来复制父进程的PCB数据信息,包括 priority 和 counter +*p = *current; + +// 初始化 counter +p->counter = p->priority; +// 因为父进程的counter数值已发生变化,而 priority 不会,所以上面的第二句代码将p->counter 设置成 p->priority。 +// 每个进程的 priority 都是继承自父亲进程的,除非它自己改变优先级。 +``` + +①假设没有改变优先级,时间片的初值就是进程 0 的 priority,即宏 INIT_TASK 中定义的: +```c +#define INIT_TASK \ + { 0,15,15, +// 上述三个值分别对应 state、counter 和 priority; +``` + +## 当进程的时间片用完时,被重新赋成何值? + +接下来回答第二个问题,当就绪进程的 counter 为 0 时,不会被调度(schedule 要选取 counter 最大的,大于 0 的进程),而当所有的就绪态进程的 counter 都变成 0 时,会执行下面的语句: + +```c +(*p)->counter = ((*p)->counter >> 1) + (*p)->priority; +``` +算出的新的 counter 值也等于 priority,即初始时间片的大小。