Ken Thomases : kernel32: Use double-fork to avoid leaving zombie processes.
Alexandre Julliard
julliard at winehq.org
Thu Dec 1 14:05:32 CST 2011
Module: wine
Branch: master
Commit: 5bac5ee26ef4abc56155f9458e303927c93a185e
URL: http://source.winehq.org/git/wine.git/?a=commit;h=5bac5ee26ef4abc56155f9458e303927c93a185e
Author: Ken Thomases <ken at codeweavers.com>
Date: Wed Nov 30 18:20:24 2011 -0600
kernel32: Use double-fork to avoid leaving zombie processes.
---
dlls/kernel32/process.c | 153 +++++++++++++++++++++++++++-------------------
1 files changed, 90 insertions(+), 63 deletions(-)
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c
index ae3bbb2..0fc2c2b 100644
--- a/dlls/kernel32/process.c
+++ b/dlls/kernel32/process.c
@@ -41,6 +41,9 @@
# include <sys/prctl.h>
#endif
#include <sys/types.h>
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
@@ -1505,11 +1508,11 @@ static int fork_and_exec( const char *filename, const WCHAR *cmdline, const WCHA
if (!(pid = fork())) /* child */
{
- close( fd[0] );
-
- if (flags & (CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | DETACHED_PROCESS))
+ if (!(pid = fork())) /* grandchild */
{
- if (!(pid = fork()))
+ close( fd[0] );
+
+ if (flags & (CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | DETACHED_PROCESS))
{
int nullfd = open( "/dev/null", O_RDWR );
setsid();
@@ -1521,36 +1524,41 @@ static int fork_and_exec( const char *filename, const WCHAR *cmdline, const WCHA
close( nullfd );
}
}
- else if (pid != -1) _exit(0); /* parent */
- }
- else
- {
- if (stdin_fd != -1)
- {
- dup2( stdin_fd, 0 );
- close( stdin_fd );
- }
- if (stdout_fd != -1)
- {
- dup2( stdout_fd, 1 );
- close( stdout_fd );
- }
- if (stderr_fd != -1)
+ else
{
- dup2( stderr_fd, 2 );
- close( stderr_fd );
+ if (stdin_fd != -1)
+ {
+ dup2( stdin_fd, 0 );
+ close( stdin_fd );
+ }
+ if (stdout_fd != -1)
+ {
+ dup2( stdout_fd, 1 );
+ close( stdout_fd );
+ }
+ if (stderr_fd != -1)
+ {
+ dup2( stderr_fd, 2 );
+ close( stderr_fd );
+ }
}
- }
- /* Reset signals that we previously set to SIG_IGN */
- signal( SIGPIPE, SIG_DFL );
+ /* Reset signals that we previously set to SIG_IGN */
+ signal( SIGPIPE, SIG_DFL );
- if (newdir) chdir(newdir);
+ if (newdir) chdir(newdir);
+
+ if (argv && envp) execve( filename, argv, envp );
+ }
+
+ if (pid <= 0) /* grandchild if exec failed or child if fork failed */
+ {
+ err = errno;
+ write( fd[1], &err, sizeof(err) );
+ _exit(1);
+ }
- if (argv && envp) execve( filename, argv, envp );
- err = errno;
- write( fd[1], &err, sizeof(err) );
- _exit(1);
+ _exit(0); /* child if fork succeeded */
}
HeapFree( GetProcessHeap(), 0, argv );
HeapFree( GetProcessHeap(), 0, envp );
@@ -1558,10 +1566,18 @@ static int fork_and_exec( const char *filename, const WCHAR *cmdline, const WCHA
if (stdout_fd != -1) close( stdout_fd );
if (stderr_fd != -1) close( stderr_fd );
close( fd[1] );
- if ((pid != -1) && (read( fd[0], &err, sizeof(err) ) > 0)) /* exec failed */
+ if (pid != -1)
{
- errno = err;
- pid = -1;
+ /* reap child */
+ do {
+ err = waitpid(pid, NULL, 0);
+ } while (err < 0 && errno == EINTR);
+
+ if (read( fd[0], &err, sizeof(err) ) > 0) /* exec or second fork failed */
+ {
+ errno = err;
+ pid = -1;
+ }
}
if (pid == -1) FILE_SetDosError();
close( fd[0] );
@@ -1805,11 +1821,11 @@ static pid_t exec_loader( LPCWSTR cmd_line, unsigned int flags, int socketfd,
if (exec_only || !(pid = fork())) /* child */
{
- char preloader_reserve[64], socket_env[64];
-
- if (flags & (CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | DETACHED_PROCESS))
+ if (exec_only || !(pid = fork())) /* grandchild */
{
- if (!(pid = fork()))
+ char preloader_reserve[64], socket_env[64];
+
+ if (flags & (CREATE_NEW_PROCESS_GROUP | CREATE_NEW_CONSOLE | DETACHED_PROCESS))
{
int fd = open( "/dev/null", O_RDWR );
setsid();
@@ -1821,44 +1837,55 @@ static pid_t exec_loader( LPCWSTR cmd_line, unsigned int flags, int socketfd,
close( fd );
}
}
- else if (pid != -1) _exit(0); /* parent */
- }
- else
- {
- if (stdin_fd != -1) dup2( stdin_fd, 0 );
- if (stdout_fd != -1) dup2( stdout_fd, 1 );
- }
+ else
+ {
+ if (stdin_fd != -1) dup2( stdin_fd, 0 );
+ if (stdout_fd != -1) dup2( stdout_fd, 1 );
+ }
- if (stdin_fd != -1) close( stdin_fd );
- if (stdout_fd != -1) close( stdout_fd );
+ if (stdin_fd != -1) close( stdin_fd );
+ if (stdout_fd != -1) close( stdout_fd );
- /* Reset signals that we previously set to SIG_IGN */
- signal( SIGPIPE, SIG_DFL );
+ /* Reset signals that we previously set to SIG_IGN */
+ signal( SIGPIPE, SIG_DFL );
- sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd );
- sprintf( preloader_reserve, "WINEPRELOADRESERVE=%lx-%lx",
- (unsigned long)binary_info->res_start, (unsigned long)binary_info->res_end );
+ sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd );
+ sprintf( preloader_reserve, "WINEPRELOADRESERVE=%lx-%lx",
+ (unsigned long)binary_info->res_start, (unsigned long)binary_info->res_end );
- putenv( preloader_reserve );
- putenv( socket_env );
- if (winedebug) putenv( winedebug );
- if (wineloader) putenv( wineloader );
- if (unixdir) chdir(unixdir);
+ putenv( preloader_reserve );
+ putenv( socket_env );
+ if (winedebug) putenv( winedebug );
+ if (wineloader) putenv( wineloader );
+ if (unixdir) chdir(unixdir);
- if (argv)
- {
- do
+ if (argv)
{
- wine_exec_wine_binary( loader, argv, getenv("WINELOADER") );
- }
+ do
+ {
+ wine_exec_wine_binary( loader, argv, getenv("WINELOADER") );
+ }
#ifdef __APPLE__
- while (errno == ENOTSUP && exec_only && terminate_main_thread());
+ while (errno == ENOTSUP && exec_only && terminate_main_thread());
#else
- while (0);
+ while (0);
#endif
+ }
+ _exit(1);
}
- _exit(1);
+
+ _exit(pid == -1);
}
+
+ if (pid != -1)
+ {
+ /* reap child */
+ pid_t wret;
+ do {
+ wret = waitpid(pid, NULL, 0);
+ } while (wret < 0 && errno == EINTR);
+ }
+
HeapFree( GetProcessHeap(), 0, wineloader );
HeapFree( GetProcessHeap(), 0, argv );
return pid;
More information about the wine-cvs
mailing list