init signal解释

本文详细介绍了sigaction()、fcntl()、socketpair、waitpid等关键函数在信号处理和进程管理中的应用,深入探讨了僵尸进程产生的原因及其解决策略。

相关函数

sigaction()会依参数signum指定的信号编号来设置该信号的处理函数。参数signum可以指定SIGKILL和SIGSTOP以外的所有信号。

fcntl()用来操作文件描述符的一些特性。fcntl 不仅可以施加建议性锁,还可以施加强制锁。同时,fcntl还能对文件的某一记录进行上锁,也就是记录锁。


socketpair就可以创建全双工管道,man socketpair:
socketpair - create a pair of connected sockets, The two sockets are indistinguishable,也就是说,用socketpair创建出来的两个描述符应该是等价的。


waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用 wait()时子进程已经结束,则 wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一快返回。如果不在意结束状态值,则参数 status 可以设成 NULL。参数 pid 为欲等待的子进程识别码,
  其他数值意义如下:
    pid<-1 等待进程组识别码为 pid 绝对值的任何子进程。
    pid=-1 等待任何子进程,相当于 wait()。            
    pid=0     等待进程组识别码与目前进程相同的任何子进程。       
    pid>0     等待任何子进程识别码为 pid 的子进程。
  参数 option 可以为 0 或下面的 OR 组合:
    WNOHANG 如果没有任何已经结束的子进程则马上返回, 不予以等待。
    WUNTRACED 如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会。


僵尸进程产生和危害

在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。 但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)。直到父进程通过wait / waitpid来取时才释放. 但这样就导致了问题,如果进程不调用wait / waitpid的话, 那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。

僵尸进程的避免  

1、父进程通过wait和waitpid等函数等待子进程结束,这会导致父进程挂起。  

2. 如果父进程很忙,那么可以用signal函数为SIGCHLD安装handler,因为子进程结束后, 父进程会收到该信号,可以在handler中调用wait回收。  

3. 如果父进程不关心子进程什么时候结束,那么可以用signal(SIGCHLD, SIG_IGN) 通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收, 并不再给父进程发送信号。  

4. 还有一些技巧,就是fork两次,父进程fork一个子进程,然后继续工作,子进程fork一 个孙进程后退出,那么孙进程被init接管,孙进程结束后,init会回收。不过子进程的回收 还要自己做。

<think>好的,我现在需要帮助用户了解如何在Android中屏蔽init程序对SIGGROUP_EXIT信号的处理。首先,我需要回顾一下之前的对话历史,确保自己理解用户的需求。用户之前询问过如何在Android NDK开发中关闭栈优化,涉及编译器选项、优化级别调整和架构特定设置。现在的问题转向了Android系统的init程序信号处理,尤其是SIGGROUP_EXIT信号。 首先,我需要明确用户提到的SIGGROUP_EXIT是什么。在Linux信号中,并没有一个名为SIGGROUP_EXIT的标准信号。可能是用户指的某个特定信号,或者是进程组相关的信号处理。例如,SIGCHLD是当子进程终止时发送给父进程的信号,而进程组退出可能会涉及到其他信号,如SIGHUP、SIGTERM等。不过,根据用户提供的引用内容,特别是引用[4],他们提到了init进程处理SIGCHLD信号,用于回收僵尸进程,避免资源浪费。因此,用户可能想屏蔽init程序对某些进程组退出信号的处理,可能是SIGCHLD或者相关的信号处理机制。 接下来,我需要考虑Android的init程序的结构。Android的init进程是用户空间的第一个进程,负责启动其他系统服务和管理进程的生命周期。init程序会处理多个信号,比如SIGCHLD,用于监控子进程的状态变化。根据引用[4],init进程通过sigaction设置SIGCHLD的处理函数sigchld_handler,来回收僵尸进程的资源。如果用户希望屏蔽对SIGGROUP_EXIT信号的处理,可能需要修改init程序中的信号处理逻辑。 接下来,我需要分析如何屏蔽特定的信号处理。在Linux系统中,可以通过修改信号处理函数来忽略某个信号,或者替换原有的处理函数。例如,使用signal(SIGCHLD, SIG_IGN)来忽略子进程终止信号,或者使用sigaction来设置新的处理函数。然而,init进程作为系统的关键组件,直接修改其代码可能会有风险,需要重新编译系统镜像,并且可能影响系统的稳定性。 根据用户提供的引用[4],init程序中已经设置了SIGCHLD的处理函数。如果用户想屏蔽对某个信号的处理,可能需要找到init源码中对应的信号处理部分,并注释掉相关的代码,或者修改信号处理函数。例如,在signal_handler.cpp中找到sigchld_handler函数,并阻止其执行资源回收的操作,但这可能导致僵尸进程的积累,因此需要谨慎。 另外,用户提到的“signal_group_exit”可能是指进程组退出的信号处理。在Linux中,当进程组的领导进程退出时,可能会发送SIGHUP信号给该组中的其他进程。但需要确认具体信号的含义。如果是进程组相关的处理,可能需要查看init中如何处理进程组信号,例如是否调用了setpgid或相关的进程管理函数。 在Android源码中,init程序的信号处理逻辑通常位于system/core/init目录下,特别是signal_handler.cpp和service.cpp等文件中。例如,引用[4]中提到的sigaction设置和sigchld_handler函数,可能在这些文件中实现。用户需要定位到相关代码,修改或禁用对应的信号处理。 另外,需要注意权限问题。修改init进程需要系统级权限,通常需要重新编译系统镜像,并在具有root权限的设备上进行测试。普通应用程序无法修改init进程的行为,因此用户的需求可能涉及到系统定制或ROM开发。 总结可能的步骤:1. 定位init程序中处理目标信号的代码部分;2. 修改或注释掉信号处理逻辑;3. 重新编译系统镜像并刷入设备测试。同时需要考虑这样做的潜在风险,比如导致僵尸进程无法回收,影响系统稳定性。 最后,需要提醒用户此类操作的风险,并建议仅在开发或测试环境中进行,确保有备份和恢复方案。</think>在Android系统中屏蔽`init`程序对进程组退出信号(可能涉及`SIGCHLD`或相关信号)的处理需要深入修改系统底层代码,以下是具体实现路径和注意事项: --- ### **核心实现原理** `init`进程通过注册`SIGCHLD`信号处理器来监控子进程状态,并在`signal_handler.cpp`中实现资源回收逻辑[^4]。屏蔽相关信号需修改其信号注册逻辑或处理函数。 --- ### **实现步骤** #### **1. 定位信号处理源码** - **文件路径**:`system/core/init/signal_handler.cpp` - **关键代码段**: ```cpp static void sigchld_handler(int /*signal*/) { ServiceManager::GetInstance().ReapAnyOutstandingChildren(); } void signal_handler_init() { struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_handler = sigchld_handler; act.sa_flags = SA_NOCLDSTOP; sigaction(SIGCHLD, &act, nullptr); // 注册SIGCHLD信号处理器 } ``` #### **2. 修改信号处理逻辑** - **方案一:直接禁用信号注册** 注释或删除`sigaction`调用以停止响应`SIGCHLD`: ```cpp void signal_handler_init() { // 注释此行以禁用SIGCHLD信号处理 // sigaction(SIGCHLD, &act, nullptr); } ``` - **方案二:清空处理函数** 保留信号注册但清空处理逻辑: ```cpp static void sigchld_handler(int /*signal*/) { // 清空原有逻辑,不再回收子进程 // ServiceManager::GetInstance().ReapAnyOutstandingChildren(); } ``` #### **3. 重新编译系统镜像** - 使用Android源码编译环境(如AOSP)重新生成`boot.img`: ```bash source build/envsetup.sh lunch <target_device> make -j$(nproc) bootimage ``` - 通过`fastboot`刷入修改后的镜像: ```bash fastboot flash boot boot.img ``` --- ### **注意事项** 1. **系统稳定性风险** 屏蔽`SIGCHLD`处理可能导致僵尸进程积累,最终耗尽系统PID资源或内存[^4]。建议仅用于调试场景,并在测试后恢复默认逻辑。 2. **进程组管理的关联性** `init`通过`Service`类管理子进程生命周期。若需屏蔽进程组退出信号(如`SIGTERM`对进程组的广播),需进一步分析`kill_process_group()`等函数(位于`system/core/init/service.cpp`)。 3. **兼容性验证** 修改后的`init`需通过CTS/VTS测试,避免因信号处理异常导致系统服务崩溃。 --- ### **替代方案(非源码级)** 若无法修改系统源码,可通过以下方法间接干预: 1. **拦截信号传递** 在子进程中调用`prctl(PR_SET_PDEATHSIG, SIGKILL)`,覆盖从`init`继承的信号处理。 2. **使用`cgroups`隔离进程** 通过`cgroup`机制将关键进程与`init`管理的默认组隔离,避免受全局信号影响。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值