首先,我要说,这里有很多问题。
我的论文的任务之一要求我写一个程序来执行一个子程序,如果它的运行时间(不是墙壁时间,而是user+sys )大于一个特定的值,或者它的内存消耗大于另一个指定的值,它就会终止它。
虽然我还没有弄清楚内存的部分。我用setitmer和ITIMER_PROF信号杀人的时间。(因为ITIMER_PROF收集实际的CPU使用情况,而不是在时间上设置一个起点,然后计算x个时间量)
我之所以使用setitimer,是因为我所需的精度低于第二精度。(例如,在1.75秒后终止进程( 1750000微秒)。setrlimit方法只有一秒钟。
问题1,,为什么在父进程中设置了ITIME_PROF时,不与ITIME_PROF一起工作?它没有收集对子程序的CPU /系统调用?
childPID = fork();
if (childPID == -1){
printf( "Puff paff ... fork() did not work !\n" );
exit(1);
}
// Child
if(childPID == 0) {
execvp(args[0], args);
exit(1);
}
// Parent
else{
// Using a ITIMER_PROF inside the parent program will not work!
// The child may take 1 hour to execute and the parent will wait it out!
// To fix this we need to use a ITIMER_REAL ( wall-time ) but that's not an accurate measurement
struct itimerval timer;
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 500000;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 500000;
setitimer ( ITIMER_PROF, &timer, NULL);
int status;
waitpid(childPID,&status,0);
if (WIFEXITED(status)) {
fprintf(stderr, "Nice nice, the child exited ... with cPID = %d with status = %d \n", cPID, WEXITSTATUS(status) );
}
}问题2为什么这样做!?execvp不覆盖所有函数( timeout_sigprof、main和任何其他函数)吗?难道没有人能捕捉到子程序中的信号并取代原来的功能吗?
void timeout_sigprof( int signum ){
fprintf(stderr, "The alarm SIGPROF is here !\nThe actual pid: %d\n", getpid());
//TODO: Write output and say the child terminated with
// ram or time limit exceeded
exit(105); // Note the 105 !
}
childPID = fork();
if (childPID == -1){
printf( "Puff paff ... fork() did not work !\n" );
exit(1);
}
// Child
if(childPID == 0) {
//
struct sigaction sa;
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &timeout_sigprof;
sigaction (SIGPROF, &sa, NULL);
struct itimerval timer;
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 250000;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 250000;
setitimer ( ITIMER_PROF, &timer, NULL);
execvp(args[0], args);
exit(1);
}
// Parent process
else {
// Waiting for the child
int status;
waitpid(childPID,&status,0);
if (WIFEXITED(status)) {
fprintf(stderr, "Nice nice, the child exited ... with cPID = %d with status = %d \n", cPID, WEXITSTATUS(status) );
}
exit(0);
}问题3为什么放置在这里的dup2实际工作,让我们重定向孩子的输入/输出?
childPID = fork();
if (childPID == -1){
printf( "Puff paff ... fork() did not work !\n" );
exit(1);
}
// Child
if(childPID == 0) {
// Redirect all I/O to/from a file
int outFileId = open("output", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
// Redirect the output for the CHILD program. Still don't know why it works.
dup2(outFileId, 1)
// No idea why these dup2's work ! As i close the file descriptors here ?!
close(outFileId);
execvp(args[0], args);
exit(1);
}
// Parent process
else {
// Waiting for the child
int status;
waitpid(childPID,&status,0);
if (WIFEXITED(status)) {
fprintf(stderr, "Nice nice, the child exited ... with cPID = %d with status = %d \n", cPID, WEXITSTATUS(status) );
}
exit(0);
}下面是我编写的代码,它只在一个程序运行了X段时间(x=500 is )之后才会杀死它。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/time.h>
volatile pid_t childPID;
// This function should exist only in the parent! The child show not have it after a exec* acording to :
// The exec() family of functions replaces the current process image with a new process image.
void timeout_sigprof( int signum ){
fprintf(stderr, "The alarm SIGPROF is here !\nThe actual pid: %d\n", getpid());
//TODO: Write output and say the child terminated with a ram or time limit exceeded
exit(105); // Note the 105 !
}
int main(int argc, char *argv[]) {
int cstatus;
pid_t cPID;
char *args[2];
args[0] = "/home/ddanailov/Projects/thesis/programs/prime/prime";
args[1] = NULL; // Indicates the end of arguments.
// Handle the SIGPROF signal in the function time_handler in both the child and
struct sigaction sa;
memset (&sa, 0, sizeof (sa));
sa.sa_handler = &timeout_sigprof;
sigaction (SIGPROF, &sa, NULL);
childPID = fork();
if (childPID == -1){
printf( "Puff paff ... fork() did not work !\n" );
exit(1);
}
// Child
if(childPID == 0) {
struct itimerval timer;
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 250000;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 250000;
setitimer ( ITIMER_PROF, &timer, NULL);
// Redirect all I/O to/from a file
int outFileId = open("output", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IRGRP | S_IWGRP | S_IWUSR);
// int inFileId = open("input");
// Redirect the output for the CHILD program. Still don't know why it works.
//dup2(inFileId, 0);
dup2(outFileId, 1);
//dup2(outFileId, 2);
// No idea why these dup2's work ! As i close the file descriptors here ?!
close(outFileId);
close(inFileId);
execvp(args[0], args);
exit(1);
}
// Parent process
else {
// Waiting for the child
int status;
waitpid(childPID,&status,0);
if (WIFEXITED(status)) {
fprintf(stderr, "Nice nice, the child exited ... with cPID = %d with status = %d \n", cPID, WEXITSTATUS(status) );
}
exit(0);
}
return 0;
}任何帮助/解释都将不胜感激!
提前谢谢大家,
例如
发布于 2014-07-22 12:33:50
问题1
为什么在父进程中设置ITIME_PROF的setitimer不能工作?它没有收集对子程序的CPU /系统调用?
不,他们不是。与ITIME_PROF相关的计时器只在具有计时器集的进程正在执行时减少,或者当系统调用是代表它执行时,而不是当子进程正在执行时。
这些信号通常通过分析工具来使用,它包含在链接到您要分析的程序的库中。
但是:无论如何,您可能不需要将信号发送到父进程。如果您的目标是在程序超出允许的使用范围后终止它,那么让它接收SIGPROF并退出(如我下面对Q2的答复所示)。然后,在waitpid返回并检测到程序由于SIGPROF而退出后,您可以通过调用times或getrusage来找出子程序使用的实际时间。
唯一的缺点是子程序可以通过在SIGPROF上设置自己的信号处理程序来破坏这个进程。
问题2
为什么这样做!?execvp不覆盖所有函数( timeout_sigprof、main和任何其他函数)吗?难道没有人能捕捉到子程序中的信号并取代原来的功能吗?
它不是,或者至少不是你的思维方式。如前所述,在父进程中安装的信号处理程序将被execvp加载的新映像替换。
它看起来起作用的原因是,如果新程序没有为SIGPROF设置信号处理程序,那么当该信号被发送到进程时,它将终止。回想一下,发送到进程的任何信号,如果该进程尚未为其设置处理程序,或专门决定忽略,将导致进程终止。
如果由execvp执行的程序确实为SIGPROF设置了信号处理程序,那么它将不会被终止。
更新
看到你的评论后,我想我最好试试你的节目。我在waitpid之后向if语句添加了一个分支,如下所示:
waitpid(childPID,&status,0);
if (WIFEXITED(status)) {
fprintf(stderr, "Nice nice, the child exited ... with cPID = %d with status = %d \n", childPID, WEXITSTATUS(status) );
} else if (WIFSIGNALED(status)) {
fprintf(stderr, "Process pid=%d received signal %d\n",childPID,WTERMSIG(status));
}当我运行这个程序时,我看到以下内容:
$ ./watcher
Process pid=1045 received signal 27这证实了我上面所说的话。我没有看到“警报SIGPROF在这里!”打印出来的,我在父母身上看到了一个迹象,表明孩子是被信号27杀死的,那就是SIGPROF。
我只能想到一种场景,在这种情况下,您将看到信号处理程序执行,如果定时器设置得太低,在execv实际加载新映像之前触发。不过,这看上去并不完全可能。
另一种可能是您无意中在目标程序中安装了相同的信号处理程序(复制粘贴错误?)。
问题3
为什么放置在这里的dup2实际工作,让我们重定向子的输入/输出?
我从代码中的注释中假设,您的意思是“即使我在dup2之后立即关闭了原始的文件描述符,为什么它仍然工作呢?”
dup2将旧FD复制到新FD中,因此在执行之后:
dup2(outFileId, 1);您有两个引用相同文件描述的文件描述符:变量outFileId中包含的文件描述符和FD 1(即stdout)。还请注意,原始的stdout将被此操作关闭。
文件描述符类似于对基础文件描述数据结构的引用,该数据结构表示打开的文件。调用dup2后,有两个文件描述符指向相同的文件描述。
close的手册页说:
如果fd是引用基础打开文件描述的最后一个文件描述符(请参阅open(2)),则释放与打开的文件描述相关的资源。
因此,它可以正常工作:仍然有一个FD打开,FD 1 (stdout),新的子进程可以写入它。
https://stackoverflow.com/questions/24885081
复制相似问题