kill 函数详解

kill 是 Unix/Linux 系统中用于向进程或进程组发送信号的重要系统调用。

基本功能

  • 作用:向一个或多个进程发送信号
  • 函数原型:int kill(pid_t pid, int sig);
  • 参数:
    – pid:指定目标进程或进程组
    – sig:要发送的信号编号(来自<signal.h>),0表示空信号

pid 参数详解

根据 pid 值的不同,信号发送范围也不同:

  • pid > 0:发送给指定进程ID的单个进程
  • pid = 0:发送给与调用者同进程组的所有进程
  • pid = -1:发送给调用者有权限发送信号的所有进程
  • pid < -1:发送给进程组ID等于pid绝对值的所有进程

特殊用法

  • sig = 0:不实际发送信号,只检查目标进程是否存在(进程有效性验证)
  • SIGCONT信号:当向同会话的进程发送SIGCONT时,会跳过用户ID权限检查

权限要求

发送信号需要满足以下条件之一:调用进程有root权限,或者调用进程的真实/有效用户ID与目标进程的真实/set-user-ID匹配

返回值与错误

成功:返回0
失败:返回-1,并设置errno:

  • EINVAL:无效的信号编号
  • EPERM:无权限向目标进程发送信号
  • ESRCH:找不到指定的进程或进程组

注意事项

系统可能实施额外的安全限制。某些系统进程可能无法被信号中断。当向自身发送信号时,信号可能在kill()返回前就被处理

常见用途

终止进程:kill(pid, SIGTERM)
强制终止:kill(pid, SIGKILL)
暂停进程:kill(pid, SIGSTOP)
恢复进程:kill(pid, SIGCONT)
检查进程是否存在:kill(pid, 0)
这个系统调用是Unix系统进程管理和进程间通信的基础功能之一。

kill 函数设计原理与历史背景解析

权限检查语义的选择

历史分歧:System V与其他系统(如BSD)在权限检查上存在差异。
POSIX采用System V的语义,允许启动应用程序的用户向其发送信号,即使该程序改变了有效用户ID,这意味着set-user-ID程序除非改变真实用户ID,否则无法完全保护自己免受信号干扰(特别是SIGKILL)。

特殊pid值的处理

某些实现会对超出范围的pid值做特殊处理。POSIX明确要求在这种情况下返回[ESRCH]错误,但标准允许实现提供扩展行为。

信号传递时机保证

初始提案要求非阻塞信号在kill()返回前必须被传递,实际标准采用较弱保证(因历史兼容性)。
传统signal()实现只能保证每次进入内核时传递一个信号,使用sigaction()的实现通常能满足更强保证,标准鼓励但不强制要求实现提供强保证。

会话与信号安全

SIGCONT特殊处理允许向同一会话内的任何进程发送,绕过用户ID检查。比BSD更宽松,允许向祖先进程发送;比BSD更严格,新会话中的后代进程需接受检查。
其他作业控制信号由终端驱动直接发送,本身就不受安全检查限制。

安全实现考虑

安全标签不同的进程间可能禁止发送信号,为防止隐蔽通道,应返回[ESRCH]而非[EPERM]。

僵尸进程的处理

历史上实现不一致,有的成功、有的报错。POSIX明确要求必须视为存活进程,不能返回[ESRCH]。检查子进程终止应使用waitpid()而非kill()。

函数命名历史

kill()名称可能引起误解(并非总是终止进程),为保持历史兼容性而保留原名。
这些设计决策反映了POSIX标准在功能、安全性和历史兼容性之间的权衡,特别是考虑了不同Unix变体之间的实现差异。标准既保持了足够的灵活性允许实现扩展,又通过明确定义消除了历史上的歧义行为。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值