当前位置:首页>Linux>《Linux-0.12 基础篇》- 03 计算机基础知识

《Linux-0.12 基础篇》- 03 计算机基础知识

  • 2026-03-09 14:51:22
《Linux-0.12 基础篇》- 03 计算机基础知识

字数 8828,阅读大约需 45 分钟

第三章:计算机基础知识

3.1 概述

在我们开始深入探索 Linux 0.12 内核的奥秘之前,需要先打好坚实的基础。如果你要攀登一座技术高峰,对基本的装备和路线没有充分了解,贸然出发只会迷失方向。本章将为你的内核学习之旅准备必要的知识装备,让你能够理解那些看似神秘的代码背后的原理。

计算机科学的发展如同建造一座宏伟的宫殿。早期的程序员们从最基础的电路和逻辑门开始,一层层向上构建:机器语言 -> 汇编语言 -> 高级语言 -> 操作系统 -> 应用程序。每一层都建立在下层的基础上,同时又为上层提供了更便捷的抽象。Linux内核正是这座宫殿中承上启下的关键楼层——它既要理解下层硬件的“语言”,又要为上层的应用程序提供稳定可靠的运行环境。

学习 Linux 内核需要一种特殊的思维方式,我称之为“分层理解与穿透思考”。你需要同时掌握多个抽象层次的知识:从晶体管开关状态的物理层,到指令执行的架构层,再到进程调度、内存管理的系统层。这就像一位建筑师,既要懂得材料科学(硬件特性),又要精通结构力学(系统设计),还要考虑使用体验(用户界面)。

本章的内容安排遵循从具体到抽象、从底层到高层的逻辑顺序。我们将首先回顾x86汇编语言的基础,这是与硬件直接对话的语言;然后深入学习C语言的关键特性,特别是指针和内存管理,这是内核编程的核心工具;接着重温计算机组成原理,理解硬件如何执行软件指令;最后系统学习操作系统的核心概念,为后续的内核分析建立理论框架。

图 3.1 计算机系统层次结构

每一个知识点都不是孤立的,我们会将它们与Linux 0.12的实际代码联系起来。比如,在学习x86分段机制时,我们会查看内核如何设置全局描述符表;在学习进程概念时,我们会分析 task_struct 结构体的定 义。这种理论与实践的结合,让你在学习到解剖学理论知识的同时观察手术过程,能够获得最深刻的理解。

3.2 必要的计算机基础

3.2.1 x86汇编语言基础

汇编语言是计算机能理解的母语,是机器指令的人类可读形式。在Linux 0.12内核中,大约有5%的代码是用汇编语言编写的,主要集中在引导扇区、模式切换和关键性能路径上。理解汇编代码,让你获得直接观察CPU工作的“显微镜”。

x86架构的发展历程本身就是一部微缩的计算机发展史。从1978年的8086处理器开始,到我们关注的80386,再到今天的64位处理器,每一代都在兼容前代的基础上增加新特性。80386引入了保护模式、虚拟内存和32位寄存器,这些特性正是现代操作系统的基础。

让我们从最基础的寄存器开始。想象寄存器就像是CPU的工作台,数据在这里被处理和暂存。80386有8个32位通用寄存器:EAX、EBX、ECX、EDX、ESI、EDI、EBP、ESP。每个寄存器都有其习惯用法:EAX常用于存放函数返回值,ECX用于循环计数,ESP指向栈顶,EBP作为栈帧指针。

; 一个简单的汇编函数示例; 这个函数将两个数相加并返回结果add_numbers:    push ebp           ; 保存旧的栈帧指针    mov ebp, esp       ; 建立新的栈帧    mov eax, [ebp+8]   ; 获取第一个参数    add eax, [ebp+12]  ; 加上第二个参数    pop ebp            ; 恢复旧的栈帧指针    ret                ; 返回,结果在EAX中

在Linux 0.12的引导代码中,汇编语言发挥着关键作用。让我们查看boot/bootsect.s中的一段实际代码:

! bootsect.s中的关键代码! 将引导扇区从0x07C0移到0x9000BOOTSEG  = 0x07c0   ! 原始加载地址INITSEG  = 0x9000   ! 目标地址entry startstart:    mov ax,#BOOTSEG    mov ds,ax        ! 设置数据段寄存器    mov ax,#INITSEG    mov es,ax        ! 设置附加段寄存器    mov cx,#256      ! 512字节 = 256字    sub si,si        ! 源偏移清零    sub di,di        ! 目标偏移清零    rep              ! 重复执行    movw             ! 移动字(16位)! 这里使用了段寄存器和重复前缀指令! 展示了x86汇编的典型模式

理解这段代码需要知道几个关键点:在实模式下,内存地址由段寄存器和偏移地址共同构成;rep movw是一次高效的块移动操作;引导扇区移动自己是为了给后续代码腾出空间。

保护模式是80386的重要特性,也是现代操作系统的基础。在保护模式下,CPU提供了内存保护、特权级控制和虚拟内存支持。切换到保护模式的过程就像从平房搬进多层楼房——空间更大了,但管理也更复杂了。Linux 0.12在boot/setup.s中完成了这个切换:

! setup.s中切换到保护模式的代码! 设置全局描述符表(GDT)gdt:    .word 0,0,0,0        ! 空描述符    ! 代码段描述符    .word 0xFFFF         ! 段限长 0-15位    .word 0x0000         ! 段基址 0-15位      .word 0x9A00         ! 属性:存在,特权级0,代码段,可读    .word 0x00C0         ! 粒度4K,32位,限长16-19位    ! 数据段描述符    .word 0xFFFF    .word 0x0000    .word 0x9200         ! 属性:存在,特权级0,数据段,可写    .word 0x00C0lgdt gdt_48              ! 加载GDTR寄存器mov ax,#0x0001lmsw ax                  ! 设置CR0的PE位,进入保护模式jmpi 0,8                 ! 跳转到保护模式代码段

这段代码创建了一个简单的全局描述符表,定义了代码段和数据段,然后通过设置CR0寄存器进入保护模式。理解这个过程对于理解操作系统的内存保护机制至关重要。

3.2.2 C语言编程(重点:指针、内存管理)

如果说汇编语言是与硬件对话的直接方式,那么C语言就是系统编程的“高级母语”。Dennis Ritchie在开发UNIX操作系统时创造了C语言,这种语言的设计哲学深刻影响了操作系统开发:提供接近硬件的控制能力,同时保持足够的高级抽象。

在Linux内核中,C语言的指针和内存管理特性被发挥到了极致。理解这些特性,就像是手持一把锋利的手术刀——它精准而危险,用得好可以创造奇迹,用不好会导致灾难。

1. 指针的本质

指针是内存地址的抽象。在32位系统中,指针是4字节的值,表示一个内存位置。但指针的真正力量在于它提供的间接访问能力。让我们通过Linux 0.12中的实际代码来理解:

// include/linux/kernel.h 中的典型指针使用// 计算数组元素个数#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))// mm/memory.c 中的内存操作// 复制内存页#define copy_page(from,to) \__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024))// 指针的层级访问struct task_struct {    // ...struct task_struct *next_task, *prev_task;struct m_inode *pwd, *root;    // ...};

struct task_struct定义中,我们看到指针被用来构建链表(next_taskprev_task)和引用其他数据结构(pwdroot)。这种通过指针连接的数据结构是内核的骨架。

2. 指针运算与数组

在C语言中,数组名本质上是指向数组第一个元素的指针。这种设计带来了灵活性和一致性,但也需要格外小心。看看内核中如何遍历任务列表:

// kernel/sched.c 中遍历任务队列struct task_struct *p;// 这是Linux 0.12中经典的遍历方式for(p = &init_task ; (p = p->next_task) != &init_task ; ) {    // 处理每个进程    if (p->state == TASK_RUNNING) {        // ...    }}

这段代码展示了一个循环链表遍历。init_task是初始任务,所有任务通过next_task指针连接成环形链表。指针运算p = p->next_task使p指向下一个任务。

3. 结构体与内存对齐

结构体是C语言组织相关数据的核心机制。在内核中,结构体不仅用于数据封装,还通过精细的字段排列来优化内存访问。让我们查看进程控制块的定义:

// include/linux/sched.h 中task_struct的简化版本struct task_struct {    long state;                    /* 进程状态 */    long counter;                  /* 时间片计数器 */    long priority;                 /* 优先级 */    long signal;                   /* 信号位图 */struct sigaction sigaction[32]; /* 信号处理 */    long blocked;                  /* 阻塞信号位图 */    int exit_code;                 /* 退出代码 */    unsigned long start_code;      /* 代码段起始地址 */    unsigned long end_code;        /* 代码段结束地址 */    unsigned long end_data;        /* 数据段结束地址 */    unsigned long brk;             /* 堆当前位置 */    unsigned long start_stack;     /* 栈起始地址 */    long pid;                      /* 进程ID */    long father;                   /* 父进程ID */    // ... 更多字段};

这个结构体的大小是84字节(在当时的编译环境下)。注意字段的排列顺序:频繁访问的字段(如state、counter)放在前面,这样能够提高缓存命中率。这是内核编程中的一项重要优化技巧。

5. 内存管理的内核视角

用户程序看到的内存是连续的虚拟地址空间,但内核需要管理物理内存的分配。在Linux 0.12中,内存管理相对简单,但也包含了现代内存管理器的雏形。

// mm/memory.c 中的物理内存分配unsigned long get_free_page(void){    register unsigned long __res asm("ax");    __asm__("std ; repne ; scasb\n\t"        "jne 1f\n\t"        "movb $1,1(%%edi)\n\t"        "sall $12,%%ecx\n\t"        "addl %2,%%ecx\n\t"        "movl %%ecx,%%edx\n\t"        "movl $1024,%%ecx\n\t"        "leal 4092(%%edx),%%edi\n\t"        "rep ; stosl\n\t"        "movl %%edx,%%eax\n"        "1:"        :"=a" (__res)        :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),        "D" (mem_map+PAGING_PAGES-1)        :"di","cx","dx");    return __res;}

这段汇编与C混合的代码展示了Linux 0.12如何分配一个4KB的物理页。它搜索mem_map位图,找到空闲页后标记为已使用,然后返回物理地址。虽然现代内核的内存管理要复杂得多,但基本原理是一致的:使用位图跟踪页的使用状态。

图 3.2 内存分配过程

3.2.3 计算机组成原理回顾

要真正理解操作系统如何工作,我们需要知道硬件如何执行软件指令。计算机组成原理提供了这种理解的基础框架。让我们从CPU的工作循环开始,这是所有计算的基础。

1. 冯·诺依曼架构

在1945年的一个阳光明媚的日子里,冯.诺依曼等人在《关于电子计算装置逻辑结构设计》的研究报告中提出了一种计算机的硬件结构,它就是大名鼎鼎的冯.诺依曼结构,这个结构被沿用至今。其核心思想是“存储程序”——指令和数据存储在同一个存储器中。冯.诺依曼结构指出计算机由控制器、运算器、存储器、输入设备和输出设备5个部分组成,CPU的工作就是不断重复**“取指-译码-执行”**循环。在Linux内核的上下文中,理解这个循环有助于理解上下文切换、中断处理等核心机制。

图 3.3 冯·诺依曼架构

2. CPU的工作模式

x86处理器有多种工作模式,Linux 0.12主要涉及两种:实模式和保护模式。实模式是8086兼容模式,地址空间只有1MB,没有内存保护。保护模式提供了4GB地址空间、内存保护和多任务支持。内核启动过程中最戏剧性的时刻之一就是从实模式切换到保护模式。

3. 内存层次结构

从CPU寄存器到硬盘,存储设备的速度和容量呈反比关系。理解这个层次结构对于理解内核的缓存策略至关重要。Linux 0.12已经有了缓冲区缓存(buffer cache)的概念,这是磁盘数据在内存中的副本,用于加速文件访问。

// fs/buffer.c 中的缓冲区头结构struct buffer_head {    char * b_data;                    /* 指向数据缓冲区的指针 */    unsigned long b_blocknr;          /* 块号 */    unsigned short b_dev;             /* 设备号 */    unsigned char b_uptodate;         /* 数据是否最新 */    unsigned char b_dirt;             /* 是否脏(需要写回磁盘) */    unsigned char b_count;            /* 使用计数 */    unsigned char b_lock;             /* 是否被锁定 */struct task_struct * b_wait;      /* 等待该缓冲区的任务 */struct buffer_head * b_prev;      /* 哈希表前驱 */struct buffer_head * b_next;      /* 哈希表后继 */struct buffer_head * b_prev_free; /* 空闲链表前驱 */struct buffer_head * b_next_free; /* 空闲链表后继 */};

这个数据结构管理着磁盘块在内存中的缓存。b_dirt标志位表示缓冲区内容是否被修改过,需要写回磁盘。b_count记录有多少个进程正在使用这个缓冲区。这些机制共同实现了高效的磁盘缓存。

4. I/O系统

输入输出设备是计算机与外界交互的窗口。内核通过设备驱动程序管理这些设备。在Linux 0.12中,设备管理相对简单,但已经具备了现代设备驱动框架的雏形。

理解计算机组成原理的关键是看到硬件与软件之间的相互作用。当内核执行outb指令向端口写入数据时,它直接与硬件对话;当设置页表项时,它在配置MMU(内存管理单元)的行为;当处理中断时,它在响应硬件信号。这些操作都建立在硬件特性的基础之上。

3.3 操作系统核心概念

3.3.1 进程与线程

进程是操作系统中最核心的抽象之一。它代表了一个正在执行的程序实例,拥有独立的内存空间和系统资源。理解进程就像理解一个独立的“宇宙”——它有自己的代码、数据、堆栈,与其他进程隔离,只能通过操作系统提供的机制进行交互。

1. 进程控制块(PCB)

在Linux 0.12中,进程管理相对简单但完整。让我们深入分析进程控制块(PCB),在内核中称为task_struct

// include/linux/sched.h 中进程状态的定义#define TASK_RUNNING            0   // 正在运行或准备运行#define TASK_INTERRUPTIBLE      1   // 可中断睡眠#define TASK_UNINTERRUPTIBLE    2   // 不可中断睡眠#define TASK_ZOMBIE             3   // 僵尸状态#define TASK_STOPPED            4   // 停止状态// 进程调度相关的关键字段struct task_struct {    // ...    long state;                    /* 进程状态 */    long counter;                  /* 时间片计数器 */    long priority;                 /* 静态优先级 */    long signal;                   /* 接收到的信号 */    // ...};

进程状态机是理解进程行为的关键。一个进程在生命周期中会在不同状态间转换:从创建(fork)开始,可能进入就绪状态(TASK_RUNNING),然后被调度执行,执行中可能因为等待I/O进入睡眠状态(TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE),最后通过退出(exit)结束生命。

2. 进程创建与复制

Linux使用fork系统调用创建新进程。这是一个巧妙的设计——通过复制当前进程来创建新进程。让我们看看内核中如何实现:

// kernel/fork.c 中fork系统调用的核心int sys_fork(struct pt_regs *regs){    // 调用copy_process函数创建新进程    return copy_process(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,                        regs->esp, regs);}static int copy_process(unsigned long clone_flags, unsigned long usp,                       struct pt_regs *regs){struct task_struct *p;    // 1. 为新的task_struct分配内存    p = (struct task_struct *) get_free_page();    if (!p)        return -EAGAIN;    // 2. 复制父进程的task_struct    *p = *current;  // 注意:这是结构体复制    // 3. 重置子进程特有字段    p->pid = last_pid++;    p->father = current->pid;    p->counter = p->priority;    // 4. 复制进程地址空间    copy_mem(nr,p);    // 5. 设置子进程内核栈    p->tss.esp = usp;    // 6. 将新进程加入进程链表    p->next_task = task[0];    task[nr] = p;    return last_pid;}

这个实现展示了几个重要概念:写时复制(Copy-On-Write)的思想雏形、进程控制块的复制、地址空间的复制。*p = *current;这一行是结构体整体复制,复制了父进程的所有状态。

图 3.4 进程创建

3. 进程调度

调度器决定哪个进程获得CPU时间。Linux 0.12使用一个简单的轮转调度算法,但已经包含了优先级的概念:

// kernel/sched.c 中的调度函数void schedule(void){    int i, next, c;struct task_struct **p;    // 检查每个任务的报警信号    for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)        if (*p && (*p)->timeout && (*p)->timeout < jiffies) {            (*p)->timeout = 0;            if ((*p)->state == TASK_INTERRUPTIBLE)                (*p)->state = TASK_RUNNING;        }    // 主调度循环    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;        }        if (c) break;  // 找到可运行任务        // 所有任务的counter都为0,重新分配时间片        for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)            if (*p)                (*p)->counter = ((*p)->counter >> 1) + (*p)->priority;    }    // 切换到选中的任务    switch_to(next);}

调度算法的核心逻辑是:优先运行counter值最大的就绪进程。每个时钟中断会减少当前进程的counter,当所有进程的counter都减到0时,重新计算counter值(counter = counter/2 + priority)。这种设计既保证了公平性(轮转),又考虑了优先级。

图 3.5 进程调度

4. 进程间通信

虽然Linux 0.12的IPC机制相对简单,但已经有了信号和管道的支持。信号是进程间异步通知的机制,管道提供了进程间数据流动的通道。

3.3.2 内存管理

内存管理是操作系统的核心功能之一,负责将有限的物理内存分配给多个进程使用。Linux 0.12的内存管理虽然简单,但包含了现代内存管理器的所有基本要素:分段、分页、虚拟内存、物理内存分配。

1. 分段与分页

x86架构同时支持分段和分页机制。分段将内存划分为不同的段(代码段、数据段等),每个段有基地址和限长。分页将内存划分为固定大小的页(4KB),通过页表进行映射。Linux主要使用分页机制,分段被最小化使用以简化设计。

让我们查看内核如何设置页目录和页表:

// mm/memory.c 中的页表设置unsigned long * pg_dir = 0;  // 页目录指针void mem_init(long start_mem, long end_mem){    int i;    HIGH_MEMORY = end_mem;    // 清除mem_map(物理内存位图)    for (i=0 ; i<PAGING_PAGES ; i++)        mem_map[i] = USED;    // 标记可用页面为空闲    i = MAP_NR(start_mem);    end_mem -= start_mem;    end_mem >>= 12;  // 转换为页数    while (end_mem-->0)        mem_map[i++]=0;}// 设置页表项的函数#define set_bit(nr,addr) ({ \register int res __asm__("ax"); \__asm__ __volatile__("btsl %2,%1\n\tsetb %%al": \"=a" (res):"m" (*(addr)),"Ir" (nr)); \res;})

2. 虚拟地址到物理地址的转换

这是内存管理的核心魔法。当进程访问一个虚拟地址时,MMU自动将其转换为物理地址。这个过程对进程透明,但内核需要设置好转换表(页表)。

图 3.6 x86地址转换

3. 内存分配策略

内核需要管理物理内存的分配。Linux 0.12使用伙伴系统(buddy system)的简化版本和slab分配器的前身。让我们看看如何分配一页内存:

// 获取一页空闲内存unsigned long get_free_page(void){    register unsigned long __res asm("ax");    __asm__("std ; repne ; scasb\n\t"  // 反向扫描字符串        "jne 1f\n\t"                   // 未找到跳转        "movb $1,1(%%edi)\n\t"         // 标记页面为已使用        "sall $12,%%ecx\n\t"           // 计算物理地址        "addl %2,%%ecx\n\t"        "movl %%ecx,%%edx\n\t"        "movl $1024,%%ecx\n\t"         // 1024个双字 = 4096字节        "leal 4092(%%edx),%%edi\n\t"   // 指向页末尾        "rep ; stosl\n\t"              // 清空页面(填充0)        "movl %%edx,%%eax\n"           // 返回物理地址        "1:"        :"=a" (__res)        :"0" (0),"i" (LOW_MEM),"c" (PAGING_PAGES),        "D" (mem_map+PAGING_PAGES-1)        :"di","cx","dx");    return __res;}

这个函数展示了几个重要技术:内联汇编的使用、位图搜索算法、页面清零操作。mem_map是一个数组,每个元素对应一个物理页,0表示空闲,1表示已用。

4. 内存保护

内存保护通过页表项中的标志位实现。每个页表项包含存在位(P)、读写位(R/W)、用户/超级用户位(U/S)等。这些标志位使得内核可以保护自己的代码和数据不被用户程序访问,同时保护不同用户程序彼此隔离。

3.3.3 文件系统

文件系统是操作系统管理持久化数据的机制。它将磁盘上的原始数据块组织成用户友好的文件和目录。Linux 0.12使用Minix文件系统,这是一个简单但完整的文件系统设计。

1. 文件系统层次

理解文件系统需要从多个层次思考。最底层是磁盘块设备,以固定大小的块(如1KB)为单位读写。上层是文件系统,将磁盘块组织成inode、目录项和数据块。最上层是用户看到的文件和目录树。

// fs.h 中Minix文件系统的超级块结构struct super_block {    unsigned short s_ninodes;      // inode数量    unsigned short s_nzones;       // 块数量(V1版本)    unsigned short s_imap_blocks;  // inode位图块数    unsigned short s_zmap_blocks;  // 块位图块数    unsigned short s_firstdatazone;// 第一个数据块    unsigned short s_log_zone_size;// 块大小对数    unsigned long s_max_size;      // 最大文件大小    unsigned short s_magic;        // 魔数    // ...};

2. 文件的元数据(inode)

inode(索引节点)存储文件的元数据:大小、权限、时间戳,以及指向数据块的指针。在Minix文件系统中,每个inode有9个块指针:7个直接指针、1个一级间接指针、1个二级间接指针。

// fs.h 中Minix inode结构struct m_inode {    unsigned short i_mode;     // 文件类型和权限    unsigned short i_uid;      // 用户ID    unsigned long i_size;      // 文件大小(字节)    unsigned long i_mtime;     // 修改时间    unsigned char i_gid;       // 组ID    unsigned char i_nlinks;    // 链接数    unsigned short i_zone[9];  // 块指针数组    // ...};

3. 目录结构

目录是一种特殊文件,内容为目录项列表。每2025个目录项包含inode号和文件名。

// fs.h 中目录项结构#define NAME_LEN 14struct dir_entry {    unsigned short inode;      // inode号    char name[NAME_LEN];       // 文件名};

4. 文件操作流程:

让我们跟踪一个简单的文件读取操作,看看内核如何处理:

  1. 1. 用户程序调用read(fd, buf, count)
  2. 2. 触发sys_read系统调用
  3. 3. 内核通过文件描述符找到file结构
  4. 4. file结构指向inode
  5. 5. 根据文件偏移量计算逻辑块号
  6. 6. 通过inode的块指针找到物理块号
  7. 7. 从缓冲区缓存或磁盘读取数据
  8. 8. 复制数据到用户空间
  9. 9. 更新文件偏移量
// fs/read_write.c 中read系统调用实现int sys_read(unsigned int fd, char *buf, int count){struct file *file;struct m_inode *inode;    // 参数检查    if (fd >= NR_OPEN || count < 0 || !(file = current->filp[fd]))        return -EINVAL;    if (!count)        return 0;    // 验证访问权限    inode = file->f_inode;    if (inode->i_pipe)        return read_pipe(inode, buf, count);    if (S_ISCHR(inode->i_mode))        return rw_char(READ, inode->i_zone[0], buf, count);    if (S_ISBLK(inode->i_mode))        return block_read(inode->i_zone[0], &file->f_pos, buf, count);    // 普通文件读取    if (S_ISREG(inode->i_mode))        return file_read(inode, file, buf, count);    // 目录文件读取    if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode))        return file_read(inode, file, buf, count);    return -EINVAL;}

5. 缓冲区缓存

为了减少磁盘访问,内核维护一个缓冲区缓存,存储最近使用的磁盘块。当需要读取块时,首先检查缓存;当修改块时,先在缓存中修改,稍后写回磁盘。

// fs/buffer.c 中从缓存读取块struct buffer_head * bread(int dev, int block){struct buffer_head *bh;    // 在缓存中查找    bh = getblk(dev, block);    if (bh->b_uptodate)        return bh;    // 缓存未命中,从磁盘读取    ll_rw_block(READ, bh);    wait_on_buffer(bh);    if (bh->b_uptodate)        return bh;    brelse(bh);    return NULL;}

3.3.4 设备驱动

设备驱动程序是内核与硬件设备之间的桥梁。在Linux 0.12中,设备驱动相对简单,但已经展示了现代设备驱动框架的基本结构。

图 3.7 设备驱动结构

1. 设备分类

Linux将设备分为三类:字符设备(如终端)、块设备(如硬盘)、网络设备(在0.12中尚未完全支持)。每种设备类型有不同的接口和处理方式。

2. 设备文件

UNIX哲学中,"一切都是文件"的概念也适用于设备。设备在文件系统中表现为特殊文件,通过主设备号和次设备号标识。主设备号指定设备类型,次设备号指定具体设备。

// fs.h 中设备号处理#define MAJOR(a) (((unsigned)(a))>>8)  // 获取主设备号#define MINOR(a) ((a)&0xff)            // 获取次设备号// 字符设备开关表struct file_operations chr_dev_fops[] = {    NULL,        /* 0 - 无设备 */    rw_ttyx,     /* 1 - /dev/ttyx 串行终端 */    rw_tty,      /* 2 - /dev/tty  控制终端 */    rw_ram,      /* 3 - /dev/ram  内存磁盘 */    rw_mem,      /* 4 - /dev/mem  物理内存 */    rw_kmem,     /* 5 - /dev/kmem 内核虚拟内存 */    NULL,        /* 6 - 未使用 */    rw_port,     /* 7 - /dev/port I/O端口 */    rw_mouse,    /* 8 - /dev/mouse 鼠标 */    rw_tape,     /* 9 - /dev/tape 磁带 */    rw_fd,       /* 10 - /dev/fd  软盘 */    rw_wave,     /* 11 - /dev/wave 声卡 */    rw_sb,       /* 12 - /dev/sb  声霸卡 */    rw_dsp,      /* 13 - /dev/dsp 数字信号处理器 */    rw_audio,    /* 14 - /dev/audio 音频设备 */    rw_sequencer,/* 15 - /dev/sequencer 音序器 */    NULL,        /* 16 - 未使用 */    rw_scsi      /* 17 - /dev/scsi SCSI设备 */};

3. 设备驱动结构

一个完整的设备驱动通常包含以下部分:初始化函数、打开/关闭函数、读写函数、控制函数(ioctl)。让我们看一个简单的字符设备驱动示例:

// kernel/chr_drv/tty_io.c 中tty设备写函数int tty_write(unsigned channel, char *buf, int nr){struct tty_struct *tty;    char c, *b = buf;    // 参数检查    if (channel > 2 || !(tty = TTY_TABLE(channel)))        return -EIO;    // 逐个字符处理    while (nr > 0) {        // 如果输出缓冲区满,睡眠等待        if (FULL(tty->write_q)) {            // 唤醒可能等待读取的进程            if (FULL(tty->read_q))                wake_up(&tty->read_wait);            // 当前进程睡眠            sleep_if_full(&tty->write_q);            continue;        }        // 从用户空间获取字符        c = get_fs_byte(b);        // 特殊字符处理(如换行、退格等)        if (O_POST(tty)) {            if (c == '\n' && !O_ONLCR(tty))                PUTCH(13, tty->write_q);            if (O_LCUC(tty))                c = toupper(c);        }        // 放入输出队列        PUTCH(c, tty->write_q);        b++; nr--;    }    // 启动传输    tty->write(tty);    return (b - buf);}

4. 中断处理

设备通常通过中断与CPU通信。当设备完成一个操作或需要CPU注意时,会触发中断。内核的中断处理程序需要快速响应,通常分为上半部(快速处理)和下半部(延迟处理)。

// kernel/system_call.s 中的中断处理入口timer_interrupt:    push %ds    push %es    push %fs    pushl %edx    pushl %ecx    pushl %ebx    pushl %eax    movl $0x10,%eax    mov %ax,%ds    mov %ax,%es    movl $0x17,%eax    mov %ax,%fs    incl jiffies        // 更新系统时钟    movb $0x20,%al    outb %al,$0x20      // 发送EOI到8259A    call do_timer       // 调用C函数处理定时器    popl %eax    popl %ebx    popl %ecx    popl %edx    pop %fs    pop %es    pop %ds    iret

5. DMA(直接内存访问)

对于大量数据传输,DMA允许设备直接访问内存,无需CPU干预。这提高了数据传输效率,减少了CPU负载。

3.4 系统调用机制

系统调用是用户程序与内核之间的接口。当用户程序需要内核服务时(如读写文件、创建进程),通过系统调用进入内核态。理解系统调用机制是理解操作系统如何保护自己、如何提供服务的关键。

1. 系统调用流程

当用户程序执行int 0x80指令时,CPU从用户态切换到内核态,跳转到内核预设的中断处理程序。这个过程涉及特权级切换、栈切换、寄存器保存等复杂操作。

// include/unistd.h 中系统调用号定义#define __NR_setup       0#define __NR_exit        1#define __NR_fork        2#define __NR_read        3#define __NR_write       4#define __NR_open        5#define __NR_close       6// ... 更多系统调用// kernel/system_call.s 中系统调用入口system_call:    cmpl $NR_syscalls,%eax    jae bad_sys_call    push %ds    push %es    push %fs    pushl %edx    pushl %ecx    pushl %ebx    movl $0x10,%edx    mov %dx,%ds    mov %dx,%es    movl $0x17,%edx    mov %dx,%fs    call *sys_call_table(,%eax,4)  // 调用系统调用处理函数    pushl %eax    // ... 后续处理

2. 参数传递

系统调用参数通过寄存器传递。在Linux 0.12中,EAX存放系统调用号,EBX、ECX、EDX、ESI、EDI存放最多6个参数。

3. 从内核返回用户空间

系统调用完成后,需要恢复用户程序的执行环境。这包括恢复寄存器、切换栈、修改特权级等。

3.5 中断与异常处理

中断和异常是CPU响应外部事件或内部错误的机制。中断来自外部设备(如定时器、键盘),异常来自CPU内部(如除零错误、页错误)。内核必须妥善处理这些事件,确保系统稳定运行。

1. 中断描述符表(IDT)

x86使用IDT定义中断和异常的处理程序。Linux在启动时初始化IDT,为每个中断向量设置处理函数。

// kernel/traps.c 中设置中断门#define set_intr_gate(n,addr) \    _set_gate(&idt[n],14,0,addr)void trap_init(void){    int i;    // 设置陷阱门(异常)    set_trap_gate(0,÷_error);    set_trap_gate(1,&debug);    set_trap_gate(2,&nmi);    // ...    // 设置系统调用门    set_system_gate(0x80,&system_call);    // 设置中断门(硬件中断)    for (i = 0; i < 16; i++)        set_intr_gate(0x20+i, interrupt[i]);    // 加载IDTR    __asm__("lidt idt_descr");}

2. 中断处理流程

当中断发生时,CPU自动保存部分寄存器,跳转到IDT指定的处理函数。处理函数需要保存剩余寄存器,处理中断,然后恢复寄存器并返回。

3. 中断优先级与屏蔽

多个中断可能同时发生,需要优先级管理。某些关键代码段需要临时屏蔽中断,避免被干扰。

3.6 同步与互斥

在多任务环境中,多个进程可能同时访问共享资源,需要同步机制避免冲突。Linux 0.12提供了基本的同步原语。

1. 临界区

访问共享资源的代码段称为临界区。内核需要确保同一时间只有一个进程进入临界区。

2. 原子操作

某些操作必须不可分割地完成。x86提供了一些原子指令,如xchg(交换)、lock前缀。

3. 信号量

Dijkstra提出的经典同步机制。Linux 0.12虽然未实现完整的信号量,但有类似的机制。

// 简单的忙等待锁volatile int lock = 0;void acquire_lock(void){    while (__sync_lock_test_and_set(&lock, 1)) {        // 忙等待    }}void release_lock(void){    __sync_lock_release(&lock);}

4. 死锁

多个进程互相等待对方释放资源,导致所有进程都无法继续执行。内核设计需要避免死锁。

3.7 性能与优化

虽然Linux 0.12设计简洁,但已经包含了一些性能优化考虑。理解这些优化有助于我们编写高效的系统代码。

缓存友好性:合理安排数据结构布局,提高CPU缓存命中率。比如将频繁访问的字段放在结构体开头。

减少拷贝:内核与用户空间之间的数据拷贝是性能瓶颈。优化拷贝操作可以提高性能。

延迟操作:将不紧急的操作推迟执行,如磁盘写回、内存回收。

批处理:将多个小操作合并为大操作,减少开销。如磁盘请求合并。

3.8 安全与保护

操作系统必须保护自己不被恶意或错误的用户程序破坏。Linux 0.12提供了基本的安全机制。

特权级:x86有4个特权级(0-3)。Linux使用0级(内核态)和3级(用户态)。用户程序运行在3级,只能执行非特权指令。

内存保护:通过页表项的标志位,内核可以保护自己的代码和数据不被用户程序访问。

系统调用验证:内核必须验证系统调用的参数,防止用户程序传递恶意参数。

资源限制:限制用户程序可以使用的资源,如打开文件数、内存大小。

3.9 本章总结

在本章中,我们系统地回顾了学习Linux内核所需的计算机基础知识。从最底层的汇编语言和硬件架构,到中间的C语言编程和内存管理,再到高层的操作系统概念,我们建立了一个完整的知识框架。

这些知识不是孤立的,它们相互关联、相互支撑。汇编语言让我们理解CPU如何执行指令;C语言让我们理解如何高效地操作内存;计算机组成原理让我们理解硬件如何支持软件;操作系统概念让我们理解系统如何管理资源。

最重要的是,我们看到了这些抽象概念在Linux 0.12中的具体实现。我们看到task_struct如何表示进程,mem_map如何管理物理内存,inode如何描述文件,buffer_head如何缓存磁盘数据。这种从理论到实践的连接,是深入理解操作系统的关键。

在后续章节中,我们将基于这些基础知识,深入分析Linux 0.12的各个子系统。你会看到进程调度器如何选择下一个运行进程,内存管理器如何分配和回收页面,文件系统如何组织磁盘数据,设备驱动如何控制硬件设备。

记住,学习内核是一个渐进的过程。开始时可能觉得复杂难懂,但随着你逐步深入,各个知识点会逐渐连接起来,形成完整的理解。就像拼图游戏,开始时只是一堆碎片,但随着拼凑的进行,整体的图案会越来越清晰。

技术之路,始于基础;深入理解,成于系统。 现在,你的知识基础已经奠定,让我们在下一章开始真正的内核探索之旅。


扩展思考

  1. 1. 从8086的实模式到80386的保护模式,x86架构的演进反映了计算机系统设计的哪些核心思想?这些思想对现代操作系统设计有什么影响?
  2. 2. C语言作为系统编程语言,其设计哲学(如"信任程序员"、"保持简洁")如何体现在Linux内核的代码风格和架构设计中?这种哲学在今天的系统编程中仍然适用吗?
  3. 3. 操作系统通过抽象隐藏硬件复杂性,为用户程序提供简洁接口。这种抽象带来的便利性和性能损失之间应该如何权衡?Linux内核的设计中体现了哪些权衡决策?
  4. 4. 从Linux 0.12到现代Linux内核,操作系统的基本原理没有改变,但具体实现变得复杂得多。这种复杂性主要来自哪些需求?在什么情况下,简单设计比复杂设计更可取?

“学问无遗力,少壮工夫老始成。”——陆游《冬夜读书示子聿》

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-03-27 20:04:48 HTTP/2.0 GET : https://f.mffb.com.cn/a/478942.html
  2. 运行时间 : 0.083116s [ 吞吐率:12.03req/s ] 内存消耗:4,980.41kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=e026f9560ddb71ff39dd82b537bdfcbb
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000723s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000562s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000238s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000333s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000490s ]
  6. SELECT * FROM `set` [ RunTime:0.000206s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000513s ]
  8. SELECT * FROM `article` WHERE `id` = 478942 LIMIT 1 [ RunTime:0.002610s ]
  9. UPDATE `article` SET `lasttime` = 1774613088 WHERE `id` = 478942 [ RunTime:0.003605s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000275s ]
  11. SELECT * FROM `article` WHERE `id` < 478942 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000642s ]
  12. SELECT * FROM `article` WHERE `id` > 478942 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000536s ]
  13. SELECT * FROM `article` WHERE `id` < 478942 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001073s ]
  14. SELECT * FROM `article` WHERE `id` < 478942 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.001241s ]
  15. SELECT * FROM `article` WHERE `id` < 478942 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.003168s ]
0.084813s