Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 标准输出影响SIGKILL?_Php_Linux_Bash_Fork_Sigkill - Fatal编程技术网

Php 标准输出影响SIGKILL?

Php 标准输出影响SIGKILL?,php,linux,bash,fork,sigkill,Php,Linux,Bash,Fork,Sigkill,我有一个脚本来限制命令的执行时间长度 limit.php <?php declare(ticks = 1); if ($argc<2) die("Wrong parameter\n"); $cmd = $argv[1]; $tl = isset($argv[2]) ? intval($argv[2]) : 3; $pid = pcntl_fork(); if (-1 == $pid) { die('FORK_FAILED'); } elseif ($pid == 0) {

我有一个脚本来限制命令的执行时间长度

limit.php

<?php
declare(ticks = 1);

if ($argc<2) die("Wrong parameter\n");
$cmd = $argv[1];
$tl = isset($argv[2]) ? intval($argv[2]) : 3;

$pid = pcntl_fork();
if (-1 == $pid) {
    die('FORK_FAILED');
} elseif ($pid == 0) {
    exec($cmd);
    posix_kill(posix_getppid(), SIGALRM);
} else {
    pcntl_signal(SIGALRM, create_function('$signo',"die('EXECUTE_ENDED');"));
    sleep($tl);
    posix_kill($pid, SIGKILL);
    die("TIMEOUT_KILLED : $pid");
}
3s后,我们可以发现进程如我们预期的那样被终止

测试B

删除输出代码并再次运行

php limit.php "php -r 'while(1){sleep(1);}'" 3
结果看起来不太好,函数“exec”创建的进程没有像测试A那样被终止

[alix@s4 tmp]$ ps aux | grep whil[e]
alix      4433  0.0  0.1 139644  6860 pts/0    S    10:32   0:00 php -r while(1){sleep(1);}
系统信息

[alix@s4 tmp]$ uname -a
Linux s4 2.6.18-308.1.1.el5 #1 SMP Wed Mar 7 04:16:51 EST 2012 x86_64 x86_64 x86_64 GNU/Linux
[alix@s4 tmp]$ php -v
PHP 5.3.9 (cli) (built: Feb 15 2012 11:54:46) 
Copyright (c) 1997-2012 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies
为什么进程在测试A中被杀死而在测试B中没有被杀死?输出是否会影响SIGKILL


有什么建议吗?

您将kill信号发送给您的分叉进程,但这不会传播给它的子进程或子进程。因此,他们是孤立的,并继续运行,直到有什么东西阻止他们这样做。(在这种情况下,任何写入标准输出的尝试都会导致一个错误,然后迫使它们退出。重定向输出也可能导致无限期运行孤立。)

您希望向进程及其所有子进程发送终止信号。不幸的是,我缺乏知识来告诉你一个好的方法。我不太熟悉PHP的进程控制功能。无法解析ps的输出

不过,我发现一种简单的方法是使用kill命令向整个进程组发送kill信号。它很凌乱,并且在我的机器上的输出中添加了一个额外的“Killed”消息,但它似乎可以工作

<?php
declare(ticks = 1);

if ($argc<2) die("Wrong parameter\n");
$cmd = $argv[1];
$tl = isset($argv[2]) ? intval($argv[2]) : 3;

$pid = pcntl_fork();
if (-1 == $pid) {
    die('FORK_FAILED');
} elseif ($pid == 0) {
    exec($cmd);
    posix_kill(posix_getppid(), SIGALRM);
} else {
    pcntl_signal(SIGALRM, create_function('$signo',"die('EXECUTE_ENDED');"));
    sleep($tl);
    $gpid = posix_getpgid($pid);

    echo("TIMEOUT_KILLED : $pid");
    exec("kill -KILL -{$gpid}"); //This will also cause the script to kill itself.
}

您将kill信号发送到分叉进程,但不会传播到它的子进程或子进程。因此,他们是孤立的,并继续运行,直到有什么东西阻止他们这样做。(在这种情况下,任何写入标准输出的尝试都会导致一个错误,然后迫使它们退出。重定向输出也可能导致无限期运行孤立。)

您希望向进程及其所有子进程发送终止信号。不幸的是,我缺乏知识来告诉你一个好的方法。我不太熟悉PHP的进程控制功能。无法解析ps的输出

不过,我发现一种简单的方法是使用kill命令向整个进程组发送kill信号。它很凌乱,并且在我的机器上的输出中添加了一个额外的“Killed”消息,但它似乎可以工作

<?php
declare(ticks = 1);

if ($argc<2) die("Wrong parameter\n");
$cmd = $argv[1];
$tl = isset($argv[2]) ? intval($argv[2]) : 3;

$pid = pcntl_fork();
if (-1 == $pid) {
    die('FORK_FAILED');
} elseif ($pid == 0) {
    exec($cmd);
    posix_kill(posix_getppid(), SIGALRM);
} else {
    pcntl_signal(SIGALRM, create_function('$signo',"die('EXECUTE_ENDED');"));
    sleep($tl);
    $gpid = posix_getpgid($pid);

    echo("TIMEOUT_KILLED : $pid");
    exec("kill -KILL -{$gpid}"); //This will also cause the script to kill itself.
}

当(1){sleep(1);echo php_OS;}
进程C
)和它的父进程(
进程B
)之间有一个
管道
posix_kill($pid,SIGKILL)
进程B
发送
kill
信号,然后
进程B
终止,但是
进程C
对信号一无所知,当
进程C
接收到
信号,但不知道如何处理信号,因此退出时,进程C
将继续运行并向
断管
输出一些信息

您可以使用strace验证它(运行
php limit.php“strace php-r”而(1){sleep(1);echo php_OS;};”“1
),您将看到如下内容:

14:43:49.254809 write(1, "Linux", 5)    = -1 EPIPE (Broken pipe)
14:43:49.254952 --- SIGPIPE (Broken pipe) @ 0 (0) ---
14:43:49.255110 close(2)                = 0
14:43:49.255212 close(1)                = 0
14:43:49.255307 close(0)                = 0
14:43:49.255402 munmap(0x7fb0762f2000, 4096) = 0
14:43:49.257781 munmap(0x7fb076342000, 1052672) = 0
14:43:49.258100 munmap(0x7fb076443000, 266240) = 0
14:43:49.258268 munmap(0x7fb0762f3000, 323584) = 0
14:43:49.258555 exit_group(0)           = ?
至于
php-r'while(1){sleep(1);}
,因为没有
断管发生在它的父级死后,所以它继续按预期运行

一般来说,如果你想杀死它的子进程,你应该杀死整个进程组,而不仅仅是进程本身,通过
PHP
你可以将
process B
添加到它自己的进程组中,然后杀死整个组,下面是你的代码的区别:

--- limit.php   2012-08-11 20:50:22.000000000 +0800
+++ limit-new.php   2012-08-11 20:50:39.000000000 +0800
@@ -9,11 +9,13 @@
 if (-1 == $pid) {
     die('FORK_FAILED');
 } elseif ($pid == 0) {
+    $_pid = posix_getpid();
+    posix_setpgid($_pid, $_pid);
     exec($cmd);
     posix_kill(posix_getppid(), SIGALRM);
 } else {
     pcntl_signal(SIGALRM, create_function('$signo',"die('EXECUTE_ENDED');"));
     sleep($tl);
-    posix_kill($pid, SIGKILL);
+    posix_kill(-$pid, SIGKILL);
     die("TIMEOUT_KILLED : $pid");
 }

当(1){sleep(1);echo php_OS;}
process C
)和它的父进程(
process B
)之间有一个
PIPE
)时,
posix_kill($pid,SIGKILL)
process B
发送
kill
信号,然后
process B
终止,但是
进程C
对信号一无所知,当
进程C
接收到
信号,但不知道如何处理信号,因此退出时,进程C
将继续运行并向
断管
输出一些信息

您可以使用strace验证它(运行
php limit.php“strace php-r”而(1){sleep(1);echo php_OS;};”“1
),您将看到如下内容:

14:43:49.254809 write(1, "Linux", 5)    = -1 EPIPE (Broken pipe)
14:43:49.254952 --- SIGPIPE (Broken pipe) @ 0 (0) ---
14:43:49.255110 close(2)                = 0
14:43:49.255212 close(1)                = 0
14:43:49.255307 close(0)                = 0
14:43:49.255402 munmap(0x7fb0762f2000, 4096) = 0
14:43:49.257781 munmap(0x7fb076342000, 1052672) = 0
14:43:49.258100 munmap(0x7fb076443000, 266240) = 0
14:43:49.258268 munmap(0x7fb0762f3000, 323584) = 0
14:43:49.258555 exit_group(0)           = ?
至于
php-r'while(1){sleep(1);}
,因为没有
断管发生在它的父级死后,所以它继续按预期运行

一般来说,如果你想杀死它的子进程,你应该杀死整个进程组,而不仅仅是进程本身,通过
PHP
你可以将
process B
添加到它自己的进程组中,然后杀死整个组,下面是你的代码的区别:

--- limit.php   2012-08-11 20:50:22.000000000 +0800
+++ limit-new.php   2012-08-11 20:50:39.000000000 +0800
@@ -9,11 +9,13 @@
 if (-1 == $pid) {
     die('FORK_FAILED');
 } elseif ($pid == 0) {
+    $_pid = posix_getpid();
+    posix_setpgid($_pid, $_pid);
     exec($cmd);
     posix_kill(posix_getppid(), SIGALRM);
 } else {
     pcntl_signal(SIGALRM, create_function('$signo',"die('EXECUTE_ENDED');"));
     sleep($tl);
-    posix_kill($pid, SIGKILL);
+    posix_kill(-$pid, SIGKILL);
     die("TIMEOUT_KILLED : $pid");
 }

最好先发送一个术语信号(15),在发送KILL(9)信号之前给进程一个正常关闭的机会。最好先发送一个术语信号(15),在发送KILL(9)信号之前给进程一个正常关闭的机会。啊,我想知道他们在尝试写入terminal时是否得到了SIGPIPE。PS:适用于内核的新版本,如2.6.34,但不适用于我的2.6。18@Alix上一个补丁有一个bug,应该在子进程中创建新的进程组,我已经更新了答案。啊,我想知道他们在尝试写入terminal时是否得到了SIGPIPE。PS:适用于内核的新版本,如2.6.34,但不适用于我的2.6。18@Alix上一个补丁中有一个bug,新的进程组应该在子进程中创建,我已经更新了答案。谢谢@EPB,是的,根本原因是SIGPIPE。谢谢@EPB,是的,根本原因是SIGPIPE。