news 2026/3/26 0:12:45

do_exit()

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
do_exit()

do_exit()是 Linux 内核中进程终止的 “最终收尾函数”,它的核心作用是处理进程的正常 / 异常终止逻辑,完成进程的资源释放、状态清理、父子进程关联更新,最终将进程转为 “僵尸状态” 等待父进程回收,是用户态进程调用exit()_exit()或因信号(如SIGKILL)终止的底层核心实现。

首先明确核心定位:进程的终止流程是 “触发终止 → 执行清理 → 释放资源 → 进入僵尸态”,do_exit()负责完成后三步的核心工作,且进程一旦进入do_exit(),就无法被中断或恢复,必然走向终止(这是一个单向不可逆的流程)。

进程终止的前置知识与触发场景

在深入do_exit()前,先理清进程终止的关键背景,这是理解do_exit()工作的基础:

进程终止的两类场景

  • 正常终止:进程主动调用exit()(用户态)、_exit()(用户态)或do_exit()(内核态),如程序执行完毕调用return 0最终会触发exit()
  • 异常终止:进程收到无法捕获 / 忽略的致命信号(如SIGKILLSIGSEGV),内核信号处理函数最终回调do_exit(),如程序段错误、被kill -9杀死。

僵尸进程(Zombie Process)的由来

进程终止时,do_exit()会释放大部分资源,但会保留task_struct结构体的核心信息(进程 ID、退出码、资源使用统计),并将进程状态设为TASK_DEAD(僵尸态,用户态显示Z+),目的是等待父进程通过wait()/waitpid()系统调用回收这些剩余信息。若父进程未及时回收,该进程就会成为 “僵尸进程”。

进程终止的核心约束

  • do_exit()是进程终止的最终入口,无论何种终止场景,最终都会进入该函数。
  • do_exit()运行完毕后,进程不会直接消失,而是进入僵尸态,等待父进程回收。
  • 内核线程与用户态进程的终止流程一致,均通过do_exit(),但内核线程无用户态资源(如地址空间),释放步骤更简洁。

函数原型(Linux 5.10)

void do_exit(long code)
  • 参数code:进程的退出码,对应用户态exit(n)中的n,最终会被保存到task_struct中,供父进程通过wait()获取。
  • 返回值:无(进程进入do_exit()后不会返回,最终会触发调度,让其他进程执行)。
  • 关键特性
    • 运行在进程上下文,仅能处理当前进程(current)。
    • 单向不可逆:一旦进入该函数,进程必然终止,无法被唤醒或恢复。
    • 不直接释放task_struct:仅释放大部分资源,保留核心信息进入僵尸态。

do_exit()的核心工作流程(简化版)

do_exit()的工作流程非常繁杂,核心是 “清理资源、更新状态、通知父进程”,简化后的关键步骤如下(按执行顺序排列):

void do_exit(long code) { struct task_struct *tsk = current; // 步骤1:标记进程为终止中,禁止被调度和信号干扰 tsk->flags |= PF_EXITING; smp_wmb(); // 内存屏障,保证标记对其他 CPU 可见 // 步骤2:执行进程的退出回调函数(如用户态的 atexit()、内核态的 task_exit_callback()) exit_callbacks(tsk); // 步骤3:释放进程的用户态资源(核心,减少内存占用) // 3.1 释放地址空间(mm_struct,用户态虚拟内存、页表等) if (tsk->mm) { mm_release(tsk, tsk->mm); tsk->mm = NULL; } // 3.2 释放文件描述符表、打开的文件、工作目录等 exit_files(tsk); // 3.3 释放信号处理结构体、信号掩码等 exit_signals(tsk); // 3.4 释放进程的终端关联、会话信息等 exit_sighand(tsk); // 3.5 释放其他用户态资源(如进程凭据、命名空间等) exit_creds(tsk); // 步骤4:更新进程状态,保存退出信息,进入僵尸态 tsk->exit_code = code; // 保存退出码 tsk->exit_signal = determine_exit_signal(tsk); // 确定要发送给父进程的信号(通常 SIGCHLD) tsk->state = TASK_DEAD; // 标记为僵尸态(TASK_DEAD 对应用户态的 Z+) // 步骤5:处理子进程的“收养”问题(关键:防止子进程成为孤儿进程) // 若父进程已提前终止,将当前进程的所有子进程收养给 init 进程(PID=1) reparent_children(tsk, true); // 步骤6:通知父进程进程已终止,让父进程回收僵尸进程 notify_parent(tsk, tsk->exit_signal); // 通常发送 SIGCHLD 信号 // 步骤7:释放进程的内核态资源(部分,保留 task_struct 供父进程回收) // 释放内核栈、调度相关资源、信号量等 exit_task_struct(tsk); // 步骤8:最终触发调度,放弃 CPU 执行权,进程不再被唤醒 // 这是进程执行的最后一段代码,切换后再也不会回到当前进程 schedule(); // 步骤9:理论上不会执行到这里(防御性代码,防止异常) BUG(); }

关键步骤拆解(核心重点)

(1)标记进程为终止中(PF_EXITING

设置tsk->flags |= PF_EXITING,告诉内核其他模块 “该进程正在终止”,禁止调度器将其重新挑选、禁止新的信号投递到该进程,避免终止流程被干扰。

(2)释放用户态核心资源

这是do_exit()的核心工作之一,目的是释放进程占用的大部分系统资源,减少内存开销,关键释放项包括:

  • 地址空间(mm_struct:释放用户态虚拟内存区域、页表、TLB 缓存等,内核线程无mm_struct,此步骤跳过。
  • 文件描述符表:关闭所有未关闭的文件描述符(对应open()打开的文件、管道、套接字等),释放文件描述符表资源。
  • 信号处理资源:释放信号处理结构体sighand_struct,清除未处理的信号(致命信号除外,已触发终止)。
  • 这些资源的释放是 “立即生效” 的,释放后其他进程可以复用这些资源(如文件描述符、内存地址)。

(3)处理子进程收养(reparent_children()

这是内核的关键保护机制,防止当前进程终止后,其子进程成为 “孤儿进程” 且无人回收(最终会被 init 进程收养):

  • 核心逻辑:遍历当前进程的所有子进程,将它们的父进程 ID(ppid)更新为init进程(PID=1)。
  • init进程会循环调用wait()回收所有收养的子进程,避免这些子进程成为僵尸进程堆积。

(4)进入僵尸态并通知父进程

  • 进程状态设为TASK_DEAD(僵尸态),保留task_struct结构体的核心信息(PID、退出码、资源统计)。
  • 向父进程发送SIGCHLD信号(默认),通知父进程 “当前进程已终止,请尽快调用wait()回收我”。
  • 此时用户态通过ps命令可以看到该进程状态为Z+(僵尸进程),直到父进程调用wait()回收。

(5)最终触发schedule()放弃 CPU

这是进程执行的最后一步,调用schedule()后,进程会被从运行队列中移除,调度器挑选其他进程执行,该进程再也不会被唤醒,也不会再返回do_exit()函数。

do_exit()与相关函数的关联

1. 与exit()/_exit()(用户态)的关联
  • 用户态调用exit(n):会先执行用户态的清理回调(如atexit()注册的函数),然后调用_exit(n)进入内核态。
  • 用户态调用_exit(n):直接触发系统调用sys_exit(n),内核态sys_exit()最终调用do_exit(n),完成进程终止。
  • 核心关联:exit()_exit()sys_exit()do_exit()do_exit()是用户态进程终止的最终内核入口。
2. 与wait()/waitpid()(用户态)的关联
  • 父进程调用wait()/waitpid():触发系统调用sys_wait4(),内核会查找父进程的僵尸子进程,回收其task_struct剩余信息,释放最终的内核资源。
  • do_exit()wait()的关系:do_exit()负责 “创建僵尸进程”,wait()负责 “回收僵尸进程”,二者是 “产生” 与 “清理” 的对应关系。
  • 若父进程未调用wait():僵尸进程会一直存在,直到父进程终止(子进程被 init 进程收养并回收)。
3. 与do_stop()(之前学习的停止状态)的关联
  • 二者都是进程状态的单向转换,但目标状态不同:
    • do_stop():进程进入TASK_STOPPED(停止态),可被SIGCONT唤醒恢复。
    • do_exit():进程进入TASK_DEAD(僵尸态),不可逆,无法被任何信号唤醒。
  • 终止信号可打断停止状态:若停止状态的进程收到SIGKILL,会直接从TASK_STOPPED进入do_exit(),终止进程。

常见问题与避坑指南

僵尸进程的产生与解决

  • 产生原因:进程终止后,do_exit()进入僵尸态,父进程未及时调用wait()/waitpid()回收。
  • 解决方法:父进程主动调用wait()回收子进程;若父进程无需关注子进程退出状态,可通过signal(SIGCHLD, SIG_IGN)忽略SIGCHLD信号,内核会自动回收僵尸子进程。

kill -9无法杀死僵尸进程

  • 僵尸进程已经终止,不再占用 CPU 资源,仅保留task_struct信息,SIGKILL对僵尸进程无效。
  • 解决方法:杀死僵尸进程的父进程,让僵尸进程被init进程收养并回收。

do_exit()无法被中断

  • 进程进入do_exit()后,标记为PF_EXITING,禁止新信号投递,即使发送SIGCONT也无法恢复,终止流程单向不可逆。

内核线程的终止

  • 内核线程调用do_exit()时,由于无用户态资源(mm=NULL),会跳过用户态资源释放步骤,直接进入状态更新和子进程收养,流程更简洁。

退出码的传递

  • 用户态exit(n)n会被保存到tsk->exit_code,父进程通过wait()获取的退出码包含该值(需通过WEXITSTATUS(status)解析)。
  • 异常终止(如SIGSEGV)的退出码会包含致命信号编号,可通过WTERMSIG(status)解析。

总结

  1. do_exit()是进程终止的最终内核函数,负责清理进程大部分资源、更新状态为僵尸态、通知父进程,流程单向不可逆。
  2. 核心工作流程:标记终止中 → 执行清理回调 → 释放用户态资源 → 处理子进程收养 → 进入僵尸态 → 通知父进程 → 触发调度放弃 CPU。
  3. 僵尸进程是do_exit()的产物,需父进程wait()或 init 进程收养回收,否则会长期存在。
  4. 与用户态的关联:exit()/_exit()最终触发do_exit()wait()/waitpid()最终回收do_exit()创建的僵尸进程。
  5. 核心特性:进程进入do_exit()后必然终止,无法恢复,仅保留少量核心信息等待父进程回收。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/25 15:32:26

Topical Collection Essay

EE308FZ_Fifth Assignment_Alpha Sprint_Topical Collection Essay Assignment 5Alpha SprintCourseEE308FZ — Software EngineeringClass Link2501_MU_SE_FZURequirementsFifth Assignment——Alpha SprintTeam NameFZU Meteorological BureauObjectiveRecord all the blog …

作者头像 李华
网站建设 2026/3/17 10:04:24

python基于微信小程序的旅游服务助手 景点 酒店 旅游规划 可视化

文章目录 功能概述核心模块设计技术实现要点数据存储方案扩展优化方向 系统设计与实现的思路主要技术与实现手段源码lw获取/同行可拿货,招校园代理 :文章底部获取博主联系方式! 功能概述 Python开发的微信小程序旅游服务助手整合景点查询、酒店预订、旅…

作者头像 李华
网站建设 2026/3/18 8:02:46

主流AI视频生成商用方案选型评测:五大核心维度对比分析

引言:从技术热潮到商业落地的挑战2024年,AI视频生成技术正从令人惊叹的“技术演示”阶段,快速迈向规模化“商业应用”阶段。无论是电商卖家、内容创作者,还是企业市场部门,都看到了利用AI高效生产视频内容的巨大潜力。…

作者头像 李华
网站建设 2026/3/25 20:34:05

30.9MB全球国界与中国国界私藏版

为了便于全球或全国私有化地图的数据提取,我们基于公开的全球数据处理了一份方便我们自用的全球与全国国界数据。 我们暂且称该数据为“全球与全国国界私藏版”,如果该数据对你也有用,请从GIS资源库自助领取。 30.9MB全球与全国国界私藏版 …

作者头像 李华
网站建设 2026/3/18 4:03:21

计算机SSM毕设实战-基于SSM框架的中小学生阅读能力培养系统的设计与实现基于ssm的中小学生阅读能力培养系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华