mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-09 13:30:26 +02:00
Improve process handling on MS-Windows
* libguile/posix-w32.c: Include gc.h and threads.h. (proc_record): New structure tag. <procs, proc_size>: New static variables. (find_proc, proc_handle, record_proc, delete_proc): New utility functions. (start_child): Return value is now pid_t, as it is on Posix platforms. Record the new process and returns its PID, instead of returning a handle. Fix the recursive call. (waitpid, kill, getpriority, setpriority, sched_getaffinity) (sched_setaffinity): Look up the PID in the recorded subprocesses before trying to open a process that is not our subprocess. Make sure any open handle is closed before returning, unless it's our subprocess.
This commit is contained in:
parent
aae3561584
commit
62843d5475
1 changed files with 216 additions and 17 deletions
|
@ -29,8 +29,14 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <io.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "posix-w32.h"
|
#include "posix-w32.h"
|
||||||
|
#include "libguile/gc.h" /* for scm_*alloc, scm_strdup */
|
||||||
|
#include "libguile/threads.h" /* for scm_i_scm_pthread_mutex_lock */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get name and information about current kernel.
|
* Get name and information about current kernel.
|
||||||
|
@ -168,6 +174,80 @@ uname (struct utsname *uts)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Utility functions for maintaining the list of subprocesses launched
|
||||||
|
by Guile. */
|
||||||
|
|
||||||
|
struct proc_record {
|
||||||
|
DWORD pid;
|
||||||
|
HANDLE handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct proc_record *procs;
|
||||||
|
static ptrdiff_t proc_size;
|
||||||
|
|
||||||
|
/* Find the process slot that corresponds to PID. Return the index of
|
||||||
|
the slot, or -1 if not found. */
|
||||||
|
static ptrdiff_t
|
||||||
|
find_proc (pid_t pid)
|
||||||
|
{
|
||||||
|
ptrdiff_t found = -1, i;
|
||||||
|
|
||||||
|
for (i = 0; i < proc_size; i++)
|
||||||
|
{
|
||||||
|
if (procs[i].pid == pid && procs[i].handle != INVALID_HANDLE_VALUE)
|
||||||
|
found = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the process handle corresponding to its PID. If not found,
|
||||||
|
return invalid handle value. */
|
||||||
|
static HANDLE
|
||||||
|
proc_handle (pid_t pid)
|
||||||
|
{
|
||||||
|
ptrdiff_t idx = find_proc (pid);
|
||||||
|
|
||||||
|
if (idx < 0)
|
||||||
|
return INVALID_HANDLE_VALUE;
|
||||||
|
return procs[idx].handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store a process record in the procs[] array. */
|
||||||
|
static void
|
||||||
|
record_proc (pid_t proc_pid, HANDLE proc_handle)
|
||||||
|
{
|
||||||
|
ptrdiff_t i;
|
||||||
|
|
||||||
|
/* Find a vacant slot. */
|
||||||
|
for (i = 0; i < proc_size; i++)
|
||||||
|
{
|
||||||
|
if (procs[i].handle == INVALID_HANDLE_VALUE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If no vacant slot, enlarge the array. */
|
||||||
|
if (i == proc_size)
|
||||||
|
{
|
||||||
|
proc_size++;
|
||||||
|
procs = scm_realloc (procs, proc_size * sizeof(procs[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store the process data. */
|
||||||
|
procs[i].pid = proc_pid;
|
||||||
|
procs[i].handle = proc_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delete a process record for process PID. */
|
||||||
|
static void
|
||||||
|
delete_proc (pid_t pid)
|
||||||
|
{
|
||||||
|
ptrdiff_t idx = find_proc (pid);
|
||||||
|
|
||||||
|
if (0 <= idx && idx < proc_size)
|
||||||
|
procs[idx].handle = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Run a child process with redirected standard handles, without
|
/* Run a child process with redirected standard handles, without
|
||||||
redirecting standard handles of the parent. This is required in
|
redirecting standard handles of the parent. This is required in
|
||||||
multithreaded programs, where redirecting a standard handle affects
|
multithreaded programs, where redirecting a standard handle affects
|
||||||
|
@ -522,7 +602,7 @@ prepare_cmdline (const char *cmd, const char * const *argv, int bin_sh_replaced)
|
||||||
|
|
||||||
Return the PID of the child process, or -1 if couldn't start a
|
Return the PID of the child process, or -1 if couldn't start a
|
||||||
process. */
|
process. */
|
||||||
int
|
pid_t
|
||||||
start_child (const char *exec_file, char **argv,
|
start_child (const char *exec_file, char **argv,
|
||||||
int reading, int c2p[2], int writing, int p2c[2],
|
int reading, int c2p[2], int writing, int p2c[2],
|
||||||
int infd, int outfd, int errfd)
|
int infd, int outfd, int errfd)
|
||||||
|
@ -642,7 +722,12 @@ start_child (const char *exec_file, char **argv,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
pid = (intptr_t)pi.hProcess;
|
{
|
||||||
|
scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
|
||||||
|
record_proc (pi.dwProcessId, pi.hProcess);
|
||||||
|
scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
|
||||||
|
pid = pi.dwProcessId;
|
||||||
|
}
|
||||||
|
|
||||||
errno_save = errno;
|
errno_save = errno;
|
||||||
|
|
||||||
|
@ -666,7 +751,8 @@ start_child (const char *exec_file, char **argv,
|
||||||
if (c_strcasecmp (exec_file, shell) != 0)
|
if (c_strcasecmp (exec_file, shell) != 0)
|
||||||
{
|
{
|
||||||
argv[0] = (char *)exec_file;
|
argv[0] = (char *)exec_file;
|
||||||
return start_child (shell, argv, reading, c2p, writing, p2c, errfd);
|
return start_child (shell, argv, reading, c2p, writing, p2c,
|
||||||
|
infd, outfd, errfd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,13 +763,33 @@ start_child (const char *exec_file, char **argv,
|
||||||
|
|
||||||
/* Emulation of waitpid which only supports WNOHANG, since _cwait doesn't. */
|
/* Emulation of waitpid which only supports WNOHANG, since _cwait doesn't. */
|
||||||
int
|
int
|
||||||
waitpid (intptr_t pid, int *status, int options)
|
waitpid (pid_t pid, int *status, int options)
|
||||||
{
|
{
|
||||||
|
HANDLE ph;
|
||||||
|
|
||||||
|
/* Not supported on MS-Windows. */
|
||||||
|
if (pid <= 0)
|
||||||
|
{
|
||||||
|
errno = ENOSYS;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
|
||||||
|
ph = proc_handle (pid);
|
||||||
|
scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
|
||||||
|
/* Since scm_waitpid is documented to work only on child processes,
|
||||||
|
being unable to find a process in our records means failure. */
|
||||||
|
if (ph == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
errno = ECHILD;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if ((options & WNOHANG) != 0)
|
if ((options & WNOHANG) != 0)
|
||||||
{
|
{
|
||||||
DWORD st;
|
DWORD st;
|
||||||
|
|
||||||
if (!GetExitCodeProcess ((HANDLE)pid, &st))
|
if (!GetExitCodeProcess (ph, &st))
|
||||||
{
|
{
|
||||||
errno = ECHILD;
|
errno = ECHILD;
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -692,10 +798,16 @@ waitpid (intptr_t pid, int *status, int options)
|
||||||
return 0;
|
return 0;
|
||||||
if (status)
|
if (status)
|
||||||
*status = st;
|
*status = st;
|
||||||
return (int)pid;
|
CloseHandle (ph);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
_cwait (status, (intptr_t)ph, WAIT_CHILD);
|
||||||
|
|
||||||
return (int)_cwait (status, pid, WAIT_CHILD);
|
scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
|
||||||
|
delete_proc (pid);
|
||||||
|
scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
|
||||||
|
|
||||||
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -757,8 +869,25 @@ w32_status_to_termsig (DWORD status)
|
||||||
int
|
int
|
||||||
kill (int pid, int sig)
|
kill (int pid, int sig)
|
||||||
{
|
{
|
||||||
HANDLE ph = OpenProcess (PROCESS_TERMINATE, 0, pid);
|
HANDLE ph;
|
||||||
|
int child_proc = 0;
|
||||||
|
|
||||||
|
if (pid == getpid ())
|
||||||
|
{
|
||||||
|
if (raise (sig) == 0)
|
||||||
|
errno = ENOSYS;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
|
||||||
|
ph = proc_handle (pid);
|
||||||
|
scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
|
||||||
|
/* If not found among our subprocesses, look elsewhere in the
|
||||||
|
system. */
|
||||||
|
if (ph == INVALID_HANDLE_VALUE)
|
||||||
|
ph = OpenProcess (PROCESS_TERMINATE, 0, pid);
|
||||||
|
else
|
||||||
|
child_proc = 1;
|
||||||
if (!ph)
|
if (!ph)
|
||||||
{
|
{
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
|
@ -766,10 +895,23 @@ kill (int pid, int sig)
|
||||||
}
|
}
|
||||||
if (!TerminateProcess (ph, w32_signal_to_status (sig)))
|
if (!TerminateProcess (ph, w32_signal_to_status (sig)))
|
||||||
{
|
{
|
||||||
errno = EINVAL;
|
/* If it's our subprocess, it could have already exited. In
|
||||||
|
that case, waitpid will handily delete the process from our
|
||||||
|
records, and we should return a more meaningful ESRCH to the
|
||||||
|
caller. */
|
||||||
|
if (child_proc && waitpid (pid, NULL, WNOHANG) == pid)
|
||||||
|
errno = ESRCH;
|
||||||
|
else
|
||||||
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
CloseHandle (ph);
|
CloseHandle (ph);
|
||||||
|
if (child_proc)
|
||||||
|
{
|
||||||
|
scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
|
||||||
|
delete_proc (pid);
|
||||||
|
scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -783,6 +925,7 @@ getpriority (int which, int who)
|
||||||
HANDLE hp;
|
HANDLE hp;
|
||||||
int nice_value = -1;
|
int nice_value = -1;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
int child_proc = 0;
|
||||||
|
|
||||||
/* We don't support process groups and users. */
|
/* We don't support process groups and users. */
|
||||||
if (which != PRIO_PROCESS)
|
if (which != PRIO_PROCESS)
|
||||||
|
@ -794,12 +937,27 @@ getpriority (int which, int who)
|
||||||
if (who == 0)
|
if (who == 0)
|
||||||
hp = GetCurrentProcess ();
|
hp = GetCurrentProcess ();
|
||||||
else
|
else
|
||||||
hp = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, who);
|
{
|
||||||
|
scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
|
||||||
|
hp = proc_handle (who);
|
||||||
|
scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
|
||||||
|
/* If not found among our subprocesses, look elsewhere in the
|
||||||
|
system. */
|
||||||
|
if (hp == INVALID_HANDLE_VALUE)
|
||||||
|
hp = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, who);
|
||||||
|
else
|
||||||
|
child_proc = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (hp)
|
if (hp)
|
||||||
{
|
{
|
||||||
DWORD pri_class = GetPriorityClass (hp);
|
DWORD pri_class = GetPriorityClass (hp);
|
||||||
|
|
||||||
|
/* The pseudo-handle returned by GetCurrentProcess doesn't need
|
||||||
|
to be closed. */
|
||||||
|
if (who > 0 && !child_proc)
|
||||||
|
CloseHandle (hp);
|
||||||
|
|
||||||
if (pri_class > 0)
|
if (pri_class > 0)
|
||||||
{
|
{
|
||||||
switch (pri_class)
|
switch (pri_class)
|
||||||
|
@ -888,6 +1046,7 @@ setpriority (int which, int who, int nice_val)
|
||||||
{
|
{
|
||||||
HANDLE hp;
|
HANDLE hp;
|
||||||
DWORD err;
|
DWORD err;
|
||||||
|
int child_proc = 0, retval = -1;
|
||||||
|
|
||||||
if (which != PRIO_PROCESS)
|
if (which != PRIO_PROCESS)
|
||||||
{
|
{
|
||||||
|
@ -898,7 +1057,17 @@ setpriority (int which, int who, int nice_val)
|
||||||
if (who == 0)
|
if (who == 0)
|
||||||
hp = GetCurrentProcess ();
|
hp = GetCurrentProcess ();
|
||||||
else
|
else
|
||||||
hp = OpenProcess (PROCESS_SET_INFORMATION, FALSE, who);
|
{
|
||||||
|
scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
|
||||||
|
hp = proc_handle (who);
|
||||||
|
scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
|
||||||
|
/* If not found among our subprocesses, look elsewhere in the
|
||||||
|
system. */
|
||||||
|
if (hp == INVALID_HANDLE_VALUE)
|
||||||
|
hp = OpenProcess (PROCESS_SET_INFORMATION, FALSE, who);
|
||||||
|
else
|
||||||
|
child_proc = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (hp)
|
if (hp)
|
||||||
{
|
{
|
||||||
|
@ -920,7 +1089,7 @@ setpriority (int which, int who, int nice_val)
|
||||||
pri_class = REALTIME_PRIORITY_CLASS;
|
pri_class = REALTIME_PRIORITY_CLASS;
|
||||||
|
|
||||||
if (SetPriorityClass (hp, pri_class))
|
if (SetPriorityClass (hp, pri_class))
|
||||||
return 0;
|
retval = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = GetLastError ();
|
err = GetLastError ();
|
||||||
|
@ -934,8 +1103,12 @@ setpriority (int which, int who, int nice_val)
|
||||||
errno = EPERM;
|
errno = EPERM;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* The pseudo-handle returned by GetCurrentProcess doesn't
|
||||||
|
need to be closed. */
|
||||||
|
if (hp && who > 0 && !child_proc)
|
||||||
|
CloseHandle (hp);
|
||||||
|
|
||||||
return -1;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Emulation of sched_getaffinity and sched_setaffinity. */
|
/* Emulation of sched_getaffinity and sched_setaffinity. */
|
||||||
|
@ -944,6 +1117,7 @@ sched_getaffinity (int pid, size_t mask_size, cpu_set_t *mask)
|
||||||
{
|
{
|
||||||
HANDLE hp;
|
HANDLE hp;
|
||||||
DWORD err;
|
DWORD err;
|
||||||
|
int child_proc = 0;
|
||||||
|
|
||||||
if (mask == NULL)
|
if (mask == NULL)
|
||||||
{
|
{
|
||||||
|
@ -954,14 +1128,26 @@ sched_getaffinity (int pid, size_t mask_size, cpu_set_t *mask)
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
hp = GetCurrentProcess ();
|
hp = GetCurrentProcess ();
|
||||||
else
|
else
|
||||||
hp = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, pid);
|
{
|
||||||
|
scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
|
||||||
|
hp = proc_handle (pid);
|
||||||
|
scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
|
||||||
|
/* If not found among our subprocesses, look elsewhere in the
|
||||||
|
system. */
|
||||||
|
if (hp == INVALID_HANDLE_VALUE)
|
||||||
|
hp = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||||
|
else
|
||||||
|
child_proc = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (hp)
|
if (hp)
|
||||||
{
|
{
|
||||||
DWORD_PTR ignored;
|
DWORD_PTR ignored;
|
||||||
BOOL result = GetProcessAffinityMask (hp, (DWORD_PTR *)mask, &ignored);
|
BOOL result = GetProcessAffinityMask (hp, (DWORD_PTR *)mask, &ignored);
|
||||||
|
|
||||||
if (pid != 0)
|
/* The pseudo-handle returned by GetCurrentProcess doesn't
|
||||||
|
need to be closed. */
|
||||||
|
if (pid > 0 && !child_proc)
|
||||||
CloseHandle (hp);
|
CloseHandle (hp);
|
||||||
if (result)
|
if (result)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -988,6 +1174,7 @@ sched_setaffinity (int pid, size_t mask_size, cpu_set_t *mask)
|
||||||
{
|
{
|
||||||
HANDLE hp;
|
HANDLE hp;
|
||||||
DWORD err;
|
DWORD err;
|
||||||
|
int child_proc = 0;
|
||||||
|
|
||||||
if (mask == NULL)
|
if (mask == NULL)
|
||||||
{
|
{
|
||||||
|
@ -998,13 +1185,25 @@ sched_setaffinity (int pid, size_t mask_size, cpu_set_t *mask)
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
hp = GetCurrentProcess ();
|
hp = GetCurrentProcess ();
|
||||||
else
|
else
|
||||||
hp = OpenProcess (PROCESS_SET_INFORMATION, FALSE, pid);
|
{
|
||||||
|
scm_i_scm_pthread_mutex_lock (&scm_i_misc_mutex);
|
||||||
|
hp = proc_handle (pid);
|
||||||
|
scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
|
||||||
|
/* If not found among our subprocesses, look elsewhere in the
|
||||||
|
system. */
|
||||||
|
if (hp == INVALID_HANDLE_VALUE)
|
||||||
|
hp = OpenProcess (PROCESS_SET_INFORMATION, FALSE, pid);
|
||||||
|
else
|
||||||
|
child_proc = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (hp)
|
if (hp)
|
||||||
{
|
{
|
||||||
BOOL result = SetProcessAffinityMask (hp, *(DWORD_PTR *)mask);
|
BOOL result = SetProcessAffinityMask (hp, *(DWORD_PTR *)mask);
|
||||||
|
|
||||||
if (pid != 0)
|
/* The pseudo-handle returned by GetCurrentProcess doesn't
|
||||||
|
need to be closed. */
|
||||||
|
if (pid > 0 && !child_proc)
|
||||||
CloseHandle (hp);
|
CloseHandle (hp);
|
||||||
if (result)
|
if (result)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue