mirror of
https://github.com/moparisthebest/wget
synced 2024-07-03 16:38:41 -04:00
[svn] New Windows implementation of fork_to_background().
Submitted by David Fritz.
This commit is contained in:
parent
1b6479a39a
commit
03395ca801
@ -1,3 +1,9 @@
|
|||||||
|
2004-03-24 David Fritz <zeroxdf@att.net>
|
||||||
|
|
||||||
|
* mswindows.c (fake_fork): New function.
|
||||||
|
|
||||||
|
* mswindows.c (fork_to_background): Use it.
|
||||||
|
|
||||||
2004-03-19 David Fritz <zeroxdf@att.net>
|
2004-03-19 David Fritz <zeroxdf@att.net>
|
||||||
|
|
||||||
* mswindows.c (ws_hangup): Incorporate old fork_to_background()
|
* mswindows.c (ws_hangup): Incorporate old fork_to_background()
|
||||||
|
234
src/mswindows.c
234
src/mswindows.c
@ -28,8 +28,6 @@ modify this file, you may extend this exception to your version of the
|
|||||||
file, but you are not obligated to do so. If you do not wish to do
|
file, but you are not obligated to do so. If you do not wish to do
|
||||||
so, delete this exception statement from your version. */
|
so, delete this exception statement from your version. */
|
||||||
|
|
||||||
/* #### Someone please document what these functions do! */
|
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -131,10 +129,240 @@ ws_hangup (const char *reason)
|
|||||||
FreeConsole ();
|
FreeConsole ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Construct the name for a named section (a.k.a. `file mapping') object.
|
||||||
|
The returned string is dynamically allocated and needs to be xfree()'d. */
|
||||||
|
static char *
|
||||||
|
make_section_name (DWORD pid)
|
||||||
|
{
|
||||||
|
return aprintf ("gnu_wget_fake_fork_%lu", pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This structure is used to hold all the data that is exchanged between
|
||||||
|
parent and child. */
|
||||||
|
struct fake_fork_info
|
||||||
|
{
|
||||||
|
HANDLE event;
|
||||||
|
int changedp;
|
||||||
|
char lfilename[MAX_PATH + 1];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Determines if we are the child and if so performs the child logic.
|
||||||
|
Return values:
|
||||||
|
< 0 error
|
||||||
|
0 parent
|
||||||
|
> 0 child
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
fake_fork_child (void)
|
||||||
|
{
|
||||||
|
HANDLE section, event;
|
||||||
|
struct fake_fork_info *info;
|
||||||
|
char *name;
|
||||||
|
DWORD le;
|
||||||
|
|
||||||
|
name = make_section_name (GetCurrentProcessId ());
|
||||||
|
section = OpenFileMapping (FILE_MAP_WRITE, FALSE, name);
|
||||||
|
le = GetLastError ();
|
||||||
|
xfree (name);
|
||||||
|
if (!section)
|
||||||
|
{
|
||||||
|
if (le == ERROR_FILE_NOT_FOUND)
|
||||||
|
return 0; /* Section object does not exist; we are the parent. */
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0);
|
||||||
|
if (!info)
|
||||||
|
{
|
||||||
|
CloseHandle (section);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
event = info->event;
|
||||||
|
|
||||||
|
if (!opt.lfilename)
|
||||||
|
{
|
||||||
|
opt.lfilename = unique_name (DEFAULT_LOGFILE, 0);
|
||||||
|
info->changedp = 1;
|
||||||
|
strncpy (info->lfilename, opt.lfilename, sizeof (info->lfilename));
|
||||||
|
info->lfilename[sizeof (info->lfilename) - 1] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
info->changedp = 0;
|
||||||
|
|
||||||
|
UnmapViewOfFile (info);
|
||||||
|
CloseHandle (section);
|
||||||
|
|
||||||
|
/* Inform the parent that we've done our part. */
|
||||||
|
if (!SetEvent (event))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
CloseHandle (event);
|
||||||
|
return 1; /* We are the child. */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
fake_fork (void)
|
||||||
|
{
|
||||||
|
char *cmdline, *args;
|
||||||
|
char exe[MAX_PATH + 1];
|
||||||
|
DWORD exe_len, le;
|
||||||
|
SECURITY_ATTRIBUTES sa;
|
||||||
|
HANDLE section, event, h[2];
|
||||||
|
STARTUPINFO si;
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
struct fake_fork_info *info;
|
||||||
|
char *name;
|
||||||
|
BOOL rv;
|
||||||
|
|
||||||
|
event = section = pi.hProcess = pi.hThread = NULL;
|
||||||
|
|
||||||
|
/* Get command line arguments to pass to the child process.
|
||||||
|
We need to skip the name of the command (what amounts to argv[0]). */
|
||||||
|
cmdline = GetCommandLine ();
|
||||||
|
if (*cmdline == '"')
|
||||||
|
{
|
||||||
|
args = strchr (cmdline + 1, '"');
|
||||||
|
if (args)
|
||||||
|
++args;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
args = strchr (cmdline, ' ');
|
||||||
|
|
||||||
|
/* It's ok if args is NULL, that would mean there were no arguments
|
||||||
|
after the command name. As it is now though, we would never get here
|
||||||
|
if that were true. */
|
||||||
|
|
||||||
|
/* Get the fully qualified name of our executable. This is more reliable
|
||||||
|
than using argv[0]. */
|
||||||
|
exe_len = GetModuleFileName (GetModuleHandle (NULL), exe, sizeof (exe));
|
||||||
|
if (!exe_len || (exe_len >= sizeof (exe)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
sa.nLength = sizeof (sa);
|
||||||
|
sa.lpSecurityDescriptor = NULL;
|
||||||
|
sa.bInheritHandle = TRUE;
|
||||||
|
|
||||||
|
/* Create an anonymous inheritable event object that starts out
|
||||||
|
non-signaled. */
|
||||||
|
event = CreateEvent (&sa, FALSE, FALSE, NULL);
|
||||||
|
if (!event)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Creat the child process detached form the current console and in a
|
||||||
|
suspended state. */
|
||||||
|
memset (&si, 0, sizeof (si));
|
||||||
|
si.cb = sizeof (si);
|
||||||
|
rv = CreateProcess (exe, args, NULL, NULL, TRUE, CREATE_SUSPENDED |
|
||||||
|
DETACHED_PROCESS, NULL, NULL, &si, &pi);
|
||||||
|
if (!rv)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* Create a named section object with a name based on the process id of
|
||||||
|
the child. */
|
||||||
|
name = make_section_name (pi.dwProcessId);
|
||||||
|
section =
|
||||||
|
CreateFileMapping (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
|
||||||
|
sizeof (struct fake_fork_info), name);
|
||||||
|
le = GetLastError();
|
||||||
|
xfree (name);
|
||||||
|
/* Fail if the section object already exists (should not happen). */
|
||||||
|
if (!section || (le == ERROR_ALREADY_EXISTS))
|
||||||
|
{
|
||||||
|
rv = FALSE;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the event handle into the section object. */
|
||||||
|
info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0);
|
||||||
|
if (!info)
|
||||||
|
{
|
||||||
|
rv = FALSE;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->event = event;
|
||||||
|
|
||||||
|
UnmapViewOfFile (info);
|
||||||
|
|
||||||
|
/* Start the child process. */
|
||||||
|
rv = ResumeThread (pi.hThread);
|
||||||
|
if (!rv)
|
||||||
|
{
|
||||||
|
TerminateProcess (pi.hProcess, (DWORD) -1);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for the child to signal to us that it has done its part. If it
|
||||||
|
terminates before signaling us it's an error. */
|
||||||
|
|
||||||
|
h[0] = event;
|
||||||
|
h[1] = pi.hProcess;
|
||||||
|
rv = WAIT_OBJECT_0 == WaitForMultipleObjects (2, h, FALSE, 5 * 60 * 1000);
|
||||||
|
if (!rv)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
info = MapViewOfFile (section, FILE_MAP_READ, 0, 0, 0);
|
||||||
|
if (!info)
|
||||||
|
{
|
||||||
|
rv = FALSE;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure string is properly terminated. */
|
||||||
|
if (info->changedp &&
|
||||||
|
!memchr (info->lfilename, '\0', sizeof (info->lfilename)))
|
||||||
|
{
|
||||||
|
rv = FALSE;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf (_("Continuing in background, pid %lu.\n"), pi.dwProcessId);
|
||||||
|
if (info->changedp)
|
||||||
|
printf (_("Output will be written to `%s'.\n"), info->lfilename);
|
||||||
|
|
||||||
|
UnmapViewOfFile (info);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
if (event)
|
||||||
|
CloseHandle (event);
|
||||||
|
if (section)
|
||||||
|
CloseHandle (section);
|
||||||
|
if (pi.hThread)
|
||||||
|
CloseHandle (pi.hThread);
|
||||||
|
if (pi.hProcess)
|
||||||
|
CloseHandle (pi.hProcess);
|
||||||
|
|
||||||
|
/* We're the parent. If all is well, terminate. */
|
||||||
|
if (rv)
|
||||||
|
exit (0);
|
||||||
|
|
||||||
|
/* We failed, return. */
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fork_to_background (void)
|
fork_to_background (void)
|
||||||
{
|
{
|
||||||
ws_hangup ("fork");
|
int rv;
|
||||||
|
|
||||||
|
rv = fake_fork_child ();
|
||||||
|
if (rv < 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "fake_fork_child() failed\n");
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
else if (rv == 0)
|
||||||
|
{
|
||||||
|
/* We're the parent. */
|
||||||
|
fake_fork ();
|
||||||
|
/* If fake_fork() returns, it failed. */
|
||||||
|
fprintf (stderr, "fake_fork() failed\n");
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
/* If we get here, we're the child. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL WINAPI
|
static BOOL WINAPI
|
||||||
|
Loading…
Reference in New Issue
Block a user