mingw: use real pid

The Windows port have so far been using process handles in place
of PID. However, this is not work consistent with what getpid
returns.

PIDs are system-global identifiers, but process handles are local
to a process. Using PIDs instead of process handles allows, for
instance, a user to kill a hung process with the Task Manager,
something that would have been impossible with process handles.

Change the code to use the real PID, and use OpenProcess to get a
process-handle. Store the PID and the process handle in a linked
list protected by a critical section, so we can safely close the
process handle later.

Linked list code written by Pat Thoyts.

Signed-off-by: Erik Faye-Lund <kusmabite@gmail.com>
Signed-off-by: Pat Thoyts <patthoyts@users.sourceforge.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Erik Faye-Lund 2010-11-04 02:35:13 +01:00 committed by Junio C Hamano
parent bb34c5aabe
commit 52de4db579
2 changed files with 75 additions and 8 deletions

View File

@ -702,6 +702,14 @@ static int env_compare(const void *a, const void *b)
return strcasecmp(*ea, *eb);
}
struct pinfo_t {
struct pinfo_t *next;
pid_t pid;
HANDLE proc;
} pinfo_t;
struct pinfo_t *pinfo = NULL;
CRITICAL_SECTION pinfo_cs;
static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
const char *dir,
int prepend_cmd, int fhin, int fhout, int fherr)
@ -794,7 +802,26 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env,
return -1;
}
CloseHandle(pi.hThread);
return (pid_t)pi.hProcess;
/*
* The process ID is the human-readable identifier of the process
* that we want to present in log and error messages. The handle
* is not useful for this purpose. But we cannot close it, either,
* because it is not possible to turn a process ID into a process
* handle after the process terminated.
* Keep the handle in a list for waitpid.
*/
EnterCriticalSection(&pinfo_cs);
{
struct pinfo_t *info = xmalloc(sizeof(struct pinfo_t));
info->pid = pi.dwProcessId;
info->proc = pi.hProcess;
info->next = pinfo;
pinfo = info;
}
LeaveCriticalSection(&pinfo_cs);
return (pid_t)pi.dwProcessId;
}
static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env,
@ -1518,6 +1545,50 @@ char *getpass(const char *prompt)
return strbuf_detach(&buf, NULL);
}
pid_t waitpid(pid_t pid, int *status, unsigned options)
{
HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
FALSE, pid);
if (!h) {
errno = ECHILD;
return -1;
}
if (options == 0) {
struct pinfo_t **ppinfo;
if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
CloseHandle(h);
return 0;
}
if (status)
GetExitCodeProcess(h, (LPDWORD)status);
EnterCriticalSection(&pinfo_cs);
ppinfo = &pinfo;
while (*ppinfo) {
struct pinfo_t *info = *ppinfo;
if (info->pid == pid) {
CloseHandle(info->proc);
*ppinfo = info->next;
free(info);
break;
}
ppinfo = &info->next;
}
LeaveCriticalSection(&pinfo_cs);
CloseHandle(h);
return pid;
}
CloseHandle(h);
errno = EINVAL;
return -1;
}
#ifndef NO_MINGW_REPLACE_READDIR
/* MinGW readdir implementation to avoid extra lstats for Git */
struct mingw_DIR

View File

@ -140,13 +140,7 @@ static inline int mingw_unlink(const char *pathname)
}
#define unlink mingw_unlink
static inline pid_t waitpid(pid_t pid, int *status, unsigned options)
{
if (options == 0)
return _cwait(status, pid, 0);
errno = EINVAL;
return -1;
}
pid_t waitpid(pid_t pid, int *status, unsigned options);
#ifndef NO_OPENSSL
#include <openssl/ssl.h>
@ -321,11 +315,13 @@ void free_environ(char **env);
static int mingw_main(); \
int main(int argc, const char **argv) \
{ \
extern CRITICAL_SECTION pinfo_cs; \
_fmode = _O_BINARY; \
_setmode(_fileno(stdin), _O_BINARY); \
_setmode(_fileno(stdout), _O_BINARY); \
_setmode(_fileno(stderr), _O_BINARY); \
argv[0] = xstrdup(_pgmptr); \
InitializeCriticalSection(&pinfo_cs); \
return mingw_main(argc, argv); \
} \
static int mingw_main(c,v)