关于POPEN的问题! (dup2 )
写了个POPEN的函数,是在库函数的基础上修改的,但里面我有几个问题不明白:
FILE* my_popen( const VB *inCommand, const VB *inMode, pid_t *outPid )
{
INT aPipedes[2];
FILE* apStream = NULL;
FILE* outRet = NULL;
INT aSubRet = 0;
INT aErrNo = 0;
pid_t aPid = 0;
if( ( inCommand == NULL ) ||
( inMode == NULL ) ||
( *inMode != 'r' && *inMode != 'w' ) )
{
outRet = NULL;
goto ERR_END;
}
/* Create the pipe. */
aSubRet = pipe( aPipedes );
if( aSubRet < 0 ){
outRet = NULL;
goto ERR_END;
}
/* Fork off the child. */
aPid = fork();
if( aPid == (pid_t)-1 ){
/* The fork failed. */
(void)close( aPipedes[0] );
(void)close( aPipedes[1] );
outRet = NULL;
goto ERR_END;
} else if( aPid == (pid_t)0 )
{
/* We are the child side. Make the write side of
the pipe be stdin or the read side be stdout. */
const VB *new_argv[4];
if( ( *inMode == 'w' ? dup2( aPipedes[STDIN_FILENO], STDIN_FILENO ) :
dup2( aPipedes[STDOUT_FILENO], STDOUT_FILENO ) ) < 0 ){
_exit (127);
}
/* Close the pipe descriptors. */
(void) close (aPipedes[STDIN_FILENO]);
(void) close (aPipedes[STDOUT_FILENO]);
/* Exec the shell. */
new_argv[0] = SH_NAME;
new_argv[1] = "-c";
new_argv[2] = inCommand;
new_argv[3] = NULL;
(void) execve (SH_PATH, (VB *const *) new_argv, __environ);
/* Die if it failed. */
_exit (127);
}
/* We are the parent side. */
*outPid = aPid;
/* Close the irrelevant side of the pipe and open the relevant side as a
new stream. Mark our side of the pipe to close on exec, so new children
won't see it. */
if (*inMode == 'r')
{
(void) close (aPipedes[STDOUT_FILENO]);
(void) fcntl (aPipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
apStream = fdopen (aPipedes[STDIN_FILENO], inMode);
}
else
{
(void) close (aPipedes[STDIN_FILENO]);
(void) fcntl (aPipedes[STDOUT_FILENO], F_SETFD, FD_CLOEXEC);
apStream = fdopen (aPipedes[STDOUT_FILENO], inMode);
}
if( apStream == NULL )
{
/* The stream couldn't be opened or the child structure couldn't be
allocated. Kill the child and close the other side of the pipe. */
( void )kill( *outPid, SIGKILL );
( void )close( aPipedes[ *inMode == 'r' ? STDOUT_FILENO : STDIN_FILENO ] );
( void )waitpid( *outPid, (INT *) NULL, 0 );
outRet = NULL;
goto ERR_END;
}
outRet = apStream;
ERR_END:
return outRet;
}
函数代码已经贴出,编译无任何问题,可正常使用.
(1):
if( ( *inMode == 'w' ? dup2( aPipedes[STDIN_FILENO], STDIN_FILENO ) :
dup2( aPipedes[STDOUT_FILENO], STDOUT_FILENO ) ) < 0 ){
_exit (127);
}
此段代码中,dup2使用时候,怎么可以用宏做为参数啊?不是2个参数都要INT型吗?
(2): 当apStream == NULL时,KILL掉子进程后,为何还要执行WAITPID,而且,CLOSE不也执行多了吗?后面的不就多余执行了吗?
问题点数:20、回复次数:4Top
1 楼LunTanZeng(筱淼)回复于 2006-08-03 17:08:50 得分 0
sfTop
2 楼kofiory(幽灵)回复于 2006-08-04 11:18:17 得分 0
问题1,我自己已经想明白了
关于问题2我还不明白啊@!Top
3 楼Ropyn(剑心)回复于 2006-08-04 14:44:06 得分 0
kill( *outPid, SIGKILL );
这行并不能真正杀死子进程,它只是让进程进入zombie状态,PCB也没有回收,并让子进程发送SIGCHLD给父,期待父来回收PCB.
所以后面还要用waitpid来回收zombie进程的PCB(进程控制块)
Top
4 楼gettext(冰雪之崖)回复于 2006-08-05 00:48:42 得分 0
pipe()打开的是两个file descriptors,父子进程各用一个。 kill()之前close()的是自己不用的,kill()之后close()的是自己用的。
kill()之后的waitpid()是为了释放子进程的资源。
man waitpid
The waitpid function suspends execution of the current process until
a child as specified by the pid argument has exited, or until a sig-
nal is delivered whose action is to terminate the current process or
to call a signal handling function. If a child as requested by pid
has already exited by the time of the call (a so-called "zombie" pro-
cess), the function returns immediately. Any system resources used
by the child are freed.
Top




