在 linux 上调用 "clone()" 但它似乎出现故障
Calling "clone()" on linux but it seems to malfunction
一个简单的测试程序,我希望它会"clone" fork一个子进程,每个进程都能执行到结束
#include<stdio.h>
#include<sched.h>
#include<unistd.h>
#include<sys/types.h>
#include<errno.h>
int f(void*arg)
{
pid_t pid=getpid();
printf("child pid=%d\n",pid);
}
char buf[1024];
int main()
{
printf("before clone\n");
int pid=clone(f,buf,CLONE_VM|CLONE_VFORK,NULL);
if(pid==-1){
printf("%d\n",errno);
return 1;
}
waitpid(pid,NULL,0);
printf("after clone\n");
printf("father pid=%d\n",getpid());
return 0;
}
如它:
$g++ testClone.cpp && ./a.out
before clone
它没有打印出我预期的结果。似乎在 "clone" 之后程序处于未知状态然后退出。我试过 gdb 并打印:
Breakpoint 1, main () at testClone.cpp:15
(gdb) n-
before clone
(gdb) n-
waiting for new child: No child processes.
(gdb) n-
Single stepping until exit from function clone@plt,-
which has no line number information.
如果我删除 "waitpid" 行,那么 gdb 会打印出另一种奇怪的信息。
(gdb) n-
before clone
(gdb) n-
Detaching after fork from child process 26709.
warning: Unexpected waitpid result 000000 when waiting for vfork-done
Cannot remove breakpoints because program is no longer writable.
It might be running in another process.
Further execution is probably impossible.
0x00007fb18a446bf1 in clone () from /lib64/libc.so.6
ptrace: No such process.
我的程序哪里出错了?
您永远不应该在用户级程序中调用 clone
-- 在 clone
d 进程中允许您执行的操作有太多限制。
特别是,调用任何 libc
函数(例如 printf
)是完全禁止的(因为 libc
不知道您的 clone
存在,并且还没有为它执行任何设置)。
正如 K. A. Buhr 指出的那样,您传递的筹码也太少,而且传错了方向。您的堆栈也没有正确对齐。
简而言之,即使 K. A. Buhr 的修改 看起来 有效,但实际上并没有。
TL;DR:clone
,只是不要使用它。
clone
的第二个参数是指向子堆栈的指针。根据 clone(2)
的手册页:
Stacks grow downward on all processors that run Linux (except the HP PA processors), so child_stack usually points to the topmost address of the memory space set up for the child stack.
此外,1024 字节对于堆栈来说是微不足道的。您的程序的以下修改版本显示 运行 正确:
// #define _GNU_SOURCE // may be needed if compiled as C instead of C++
#include <stdio.h>
#include <sched.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
int f(void*arg)
{
pid_t pid=getpid();
printf("child pid=%d\n",pid);
return 0;
}
char buf[1024*1024]; // *** allocate more stack ***
int main()
{
printf("before clone\n");
int pid=clone(f,buf+sizeof(buf),CLONE_VM|CLONE_VFORK,NULL);
// *** in previous line: pointer is to *end* of stack ***
if(pid==-1){
printf("%d\n",errno);
return 1;
}
waitpid(pid,NULL,0);
printf("after clone\n");
printf("father pid=%d\n",getpid());
return 0;
}
另外,@Employed Russian 是对的——您可能不应该使用 clone
,除非您想要找点乐子。 fork
或 vfork
是 clone
更明智的接口,只要它们满足您的需要。
一个简单的测试程序,我希望它会"clone" fork一个子进程,每个进程都能执行到结束
#include<stdio.h>
#include<sched.h>
#include<unistd.h>
#include<sys/types.h>
#include<errno.h>
int f(void*arg)
{
pid_t pid=getpid();
printf("child pid=%d\n",pid);
}
char buf[1024];
int main()
{
printf("before clone\n");
int pid=clone(f,buf,CLONE_VM|CLONE_VFORK,NULL);
if(pid==-1){
printf("%d\n",errno);
return 1;
}
waitpid(pid,NULL,0);
printf("after clone\n");
printf("father pid=%d\n",getpid());
return 0;
}
如它:
$g++ testClone.cpp && ./a.out
before clone
它没有打印出我预期的结果。似乎在 "clone" 之后程序处于未知状态然后退出。我试过 gdb 并打印:
Breakpoint 1, main () at testClone.cpp:15
(gdb) n-
before clone
(gdb) n-
waiting for new child: No child processes.
(gdb) n-
Single stepping until exit from function clone@plt,-
which has no line number information.
如果我删除 "waitpid" 行,那么 gdb 会打印出另一种奇怪的信息。
(gdb) n-
before clone
(gdb) n-
Detaching after fork from child process 26709.
warning: Unexpected waitpid result 000000 when waiting for vfork-done
Cannot remove breakpoints because program is no longer writable.
It might be running in another process.
Further execution is probably impossible.
0x00007fb18a446bf1 in clone () from /lib64/libc.so.6
ptrace: No such process.
我的程序哪里出错了?
您永远不应该在用户级程序中调用 clone
-- 在 clone
d 进程中允许您执行的操作有太多限制。
特别是,调用任何 libc
函数(例如 printf
)是完全禁止的(因为 libc
不知道您的 clone
存在,并且还没有为它执行任何设置)。
正如 K. A. Buhr 指出的那样,您传递的筹码也太少,而且传错了方向。您的堆栈也没有正确对齐。
简而言之,即使 K. A. Buhr 的修改 看起来 有效,但实际上并没有。
TL;DR:clone
,只是不要使用它。
clone
的第二个参数是指向子堆栈的指针。根据 clone(2)
的手册页:
Stacks grow downward on all processors that run Linux (except the HP PA processors), so child_stack usually points to the topmost address of the memory space set up for the child stack.
此外,1024 字节对于堆栈来说是微不足道的。您的程序的以下修改版本显示 运行 正确:
// #define _GNU_SOURCE // may be needed if compiled as C instead of C++
#include <stdio.h>
#include <sched.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
int f(void*arg)
{
pid_t pid=getpid();
printf("child pid=%d\n",pid);
return 0;
}
char buf[1024*1024]; // *** allocate more stack ***
int main()
{
printf("before clone\n");
int pid=clone(f,buf+sizeof(buf),CLONE_VM|CLONE_VFORK,NULL);
// *** in previous line: pointer is to *end* of stack ***
if(pid==-1){
printf("%d\n",errno);
return 1;
}
waitpid(pid,NULL,0);
printf("after clone\n");
printf("father pid=%d\n",getpid());
return 0;
}
另外,@Employed Russian 是对的——您可能不应该使用 clone
,除非您想要找点乐子。 fork
或 vfork
是 clone
更明智的接口,只要它们满足您的需要。