[ruby-dev:13510] Re: mswin32/ming32 system patch (experimental)
From:
"U.Nakamura" <usa@...>
Date:
2001-06-08 12:12:55 UTC
List:
ruby-dev #13510
こんにちは、なかむら(う)です。
ちょっと日があいちゃいましたが...
At Mon, 4 Jun 2001 11:36:12 +0900, nobu.nakada@nifty.ne.jp wrote in
'[ruby-dev:13450] Re: mswin32/ming32 system patch (experimental)'
> psa が NULL でないときに sa を初期化していないので、`` がエラー
これはミスってました。すみません。
> になります。psa って引数にする必要ってあるんでしょうか。win32.c
> の外に SECURITY_ATTRIBUTES が見えている必要があるというのも気
> になります。あとエラーのときに無条件に CloseHandle() してるのも。
いろいろ悩んでたんですが(mypopen・mypcloseとの絡み)、今回の
パッチで適当に変更してみました。
> # どっちかというと stderr とか cwd を指定できた方が嬉しいような
> # 気も。
んー、[ruby-dev:12136]のような話が進行してからでいいかなぁ、
と思ってます(←手抜きです)。
というわけで、またまたパッチです(CVS HEADからの差分)。
RUBY_CRITICALで囲まないといけないところがいまいちわかってま
せんが、こんなもんでどないでしょう?>みなさま
前回([ruby-dev:13446])からの主な変更点は、
1. プロセスのハンドルを持ち回るのが嫌だったので配列に入れて
pidから引くようにした(かわりに256個しかchildを持てない)
2. mypclose()でパイプの終了を待つようにした。結果、rb_waitpid()
を外から見えるようにする必要は無くなった(そもそも前回のが
勘違い)
3. waitpid()で_cwait()を呼ぶのをやめた
4. その他
です。
問題点は、waitpid()でchildの死因を取れないことですが...
BC++のcwait()は死因を取れるみたいですけど、どうやってるんで
しょうね?
あと、fork+execするメソッドがないとあんまり嬉しくないので、
てきとうにでっちあげたパッチも別途つけときます。
# これを採用して欲しい、という意図はありません
Index: process.c
===================================================================
RCS file: /src/ruby/process.c,v
retrieving revision 1.36
diff -u -2 -p -r1.36 process.c
--- process.c 2001/05/21 04:22:54 1.36
+++ process.c 2001/06/08 12:09:55
@@ -834,6 +834,35 @@ rb_f_system(argc, argv)
VALUE *argv;
{
-#if defined(NT) || defined(__EMX__)
+#if defined(NT)
VALUE cmd;
+ int pid;
+
+ fflush(stdout);
+ fflush(stderr);
+ if (argc == 0) {
+ rb_last_status = Qnil;
+ rb_raise(rb_eArgError, "wrong # of arguments");
+ }
+
+ if (TYPE(argv[0]) == T_ARRAY) {
+ if (RARRAY(argv[0])->len != 2) {
+ rb_raise(rb_eArgError, "wrong first argument");
+ }
+ argv[0] = RARRAY(argv[0])->ptr[0];
+ }
+ cmd = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
+
+ SafeStringValue(cmd);
+
+ /* if error, fork_and_exec() exec rb_sys_fail() */
+ pid = fork_and_exec(RSTRING(cmd)->ptr);
+ rb_syswait(pid);
+
+ if (NUM2INT(rb_last_status) == 0) {
+ return Qtrue;
+ }
+ return Qfalse;
+#elif defined(__EMX__)
+ VALUE cmd;
int status;
@@ -1327,6 +1356,6 @@ Init_process()
rb_define_singleton_method(rb_mProcess, "fork", rb_f_fork, 0);
rb_define_singleton_method(rb_mProcess, "exit!", rb_f_exit_bang, -1);
+
rb_define_module_function(rb_mProcess, "kill", rb_f_kill, -1);
-#ifndef NT
rb_define_module_function(rb_mProcess, "wait", proc_wait, 0);
rb_define_module_function(rb_mProcess, "wait2", proc_wait2, 0);
@@ -1356,5 +1385,4 @@ Init_process()
rb_define_module_function(rb_mProcess, "pid", get_pid, 0);
rb_define_module_function(rb_mProcess, "ppid", get_ppid, 0);
-#endif /* ifndef NT */
rb_define_module_function(rb_mProcess, "getpgrp", proc_getpgrp, -1);
Index: win32/win32.c
===================================================================
RCS file: /src/ruby/win32/win32.c,v
retrieving revision 1.45
diff -u -2 -p -r1.45 win32.c
--- win32/win32.c 2001/05/12 06:47:24 1.45
+++ win32/win32.c 2001/06/08 12:09:58
@@ -73,4 +73,5 @@ extern char **environ;
#endif
+static pid_t win32_exec_and_nowait(char *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE, HANDLE);
static bool NtHasRedirection (char *);
static int valid_filename(char *s);
@@ -295,4 +296,56 @@ char *getlogin()
#if 1
+#define MAXCHILDNUM 256 /* max num of child processes */
+
+struct {
+ int inuse; /* use or unuse */
+ HANDLE hProcess; /* process handle */
+ pid_t pid; /* process id */
+} ChildRecord[MAXCHILDNUM];
+
+static int FindChildSlot(pid_t pid)
+{
+ int slot;
+
+ for (slot = 0; slot < MAXCHILDNUM; slot++) {
+ if (ChildRecord[slot].inuse == TRUE && ChildRecord[slot].pid == pid) {
+ return slot;
+ }
+ }
+
+ return -1;
+}
+
+static BOOL CloseChildHandle(pid_t pid)
+{
+ int slot;
+
+ slot = FindChildSlot(pid);
+ if (slot < 0) {
+ return FALSE;
+ }
+ ChildRecord[slot].inuse = FALSE;
+
+ return CloseHandle(ChildRecord[slot].hProcess);
+}
+
+static int FindFreeChildSlot(void)
+{
+ int slot;
+
+ for (slot = 0; slot < MAXCHILDNUM && ChildRecord[slot].inuse; slot++)
+ ;
+ if (slot >= MAXCHILDNUM) {
+ return -1;
+ }
+
+ ChildRecord[slot].inuse = TRUE;
+ ChildRecord[slot].pid = -1;
+ ChildRecord[slot].hProcess = NULL;
+
+ return slot;
+}
+
+
// popen stuff
@@ -397,9 +450,12 @@ mypopen (char *cmd, char *mode)
{
FILE *fp;
- int saved, reading;
+ int reading;
int pipemode;
- int pipes[2];
int pid;
int slot;
+ BOOL fRet;
+ HANDLE hInFile, hOutFile;
+ SECURITY_ATTRIBUTES sa;
+ int fd;
static initialized = 0;
@@ -436,238 +492,57 @@ mypopen (char *cmd, char *mode)
// Now get a pipe
//
-
-#if 0
- if (_pipe(pipes, NtPipeSize, pipemode) == -1) {
- return NULL;
+ sa.nLength = sizeof (SECURITY_ATTRIBUTES);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ fRet = CreatePipe(&hInFile, &hOutFile, &sa, 2048L);
+ if (!fRet) {
+ errno = GetLastError();
+ rb_sys_fail("mypopen: CreatePipe");
}
if (reading) {
-
- //
- // we\'re reading from the pipe, so we must hook up the
- // write end of the pipe to the new processes stdout.
- // To do this we must save our file handle from stdout
- // by _dup\'ing it, then setting our stdout to be the pipe\'s
- // write descriptor. We must also make the write handle
- // inheritable so the new process can use it.
-
- if ((saved = _dup(fileno(stdout))) == -1) {
- _close(pipes[NtPipeRead]);
- _close(pipes[NtPipeWrite]);
- return NULL;
- }
- if (_dup2 (pipes[NtPipeWrite], fileno(stdout)) == -1) {
- _close(pipes[NtPipeRead]);
- _close(pipes[NtPipeWrite]);
- return NULL;
- }
+ pid = win32_exec_and_nowait(cmd, &sa, NULL, hOutFile, NULL);
}
else {
- //
- // must be writing to the new process. Do the opposite of
- // the above, i.e. hook up the processes stdin to the read
- // end of the pipe.
- //
-
- if ((saved = _dup(fileno(stdin))) == -1) {
- _close(pipes[NtPipeRead]);
- _close(pipes[NtPipeWrite]);
- return NULL;
- }
- if (_dup2(pipes[NtPipeRead], fileno(stdin)) == -1) {
- _close(pipes[NtPipeRead]);
- _close(pipes[NtPipeWrite]);
- return NULL;
- }
+ pid = win32_exec_and_nowait(cmd, &sa, hInFile, NULL, NULL);
}
- //
- // Start the new process. Must set _fileinfo to non-zero value
- // for file descriptors to be inherited. Reset after the process
- // is started.
- //
-
- if (NtHasRedirection(cmd)) {
- docmd:
- pid = spawnlpe(_P_NOWAIT, "cmd.exe", "/c", cmd, 0, environ);
- if (pid == -1) {
- _close(pipes[NtPipeRead]);
- _close(pipes[NtPipeWrite]);
- return NULL;
- }
+ if (reading) {
+ fd = _open_osfhandle((long)hInFile, (_O_RDONLY | pipemode));
+ CloseHandle(hOutFile);
}
else {
- char **vec;
- int vecc = NtMakeCmdVector(cmd, &vec, FALSE);
-
- //pid = spawnvpe (_P_NOWAIT, vec[0], vec, environ);
- pid = spawnvpe (_P_WAIT, vec[0], vec, environ);
- if (pid == -1) {
- goto docmd;
- }
- Safefree (vec, vecc);
+ fd = _open_osfhandle((long)hOutFile, (_O_WRONLY | pipemode));
+ CloseHandle(hInFile);
}
- if (reading) {
-
- //
- // We need to close our instance of the inherited pipe write
- // handle now that it's been inherited so that it will actually close
- // when the child process ends.
- //
-
- if (_close(pipes[NtPipeWrite]) == -1) {
- _close(pipes[NtPipeRead]);
- return NULL;
- }
- if (_dup2 (saved, fileno(stdout)) == -1) {
- _close(pipes[NtPipeRead]);
- return NULL;
- }
- _close(saved);
-
- //
- // Now get a stream pointer to return to the calling program.
- //
-
- if ((fp = (FILE *) fdopen(pipes[NtPipeRead], mode)) == NULL) {
- return NULL;
- }
+ if (fd == -1) {
+ CloseHandle(reading ? hInFile : hOutFile);
+ CloseChildHandle(pid);
+ rb_sys_fail("mypopen: _open_osfhandle");
}
- else {
-
- //
- // need to close our read end of the pipe so that it will go
- // away when the write end is closed.
- //
-
- if (_close(pipes[NtPipeRead]) == -1) {
- _close(pipes[NtPipeWrite]);
- return NULL;
- }
- if (_dup2 (saved, fileno(stdin)) == -1) {
- _close(pipes[NtPipeWrite]);
- return NULL;
- }
- _close(saved);
- //
- // Now get a stream pointer to return to the calling program.
- //
-
- if ((fp = (FILE *) fdopen(pipes[NtPipeWrite], mode)) == NULL) {
- _close(pipes[NtPipeWrite]);
- return NULL;
- }
+ if ((fp = (FILE *) fdopen(fd, mode)) == NULL) {
+ _close(fd);
+ CloseChildHandle(pid);
+ rb_sys_fail("mypopen: fdopen");
}
- //
- // do the book keeping
- //
-
MyPopenRecord[slot].inuse = TRUE;
- MyPopenRecord[slot].pipe = fp;
- MyPopenRecord[slot].pid = pid;
+ MyPopenRecord[slot].pipe = fp;
+ MyPopenRecord[slot].pid = pid;
return fp;
-#else
- {
- int p[2];
-
- BOOL fRet;
- HANDLE hInFile, hOutFile;
- LPCSTR lpApplicationName = NULL;
- LPTSTR lpCommandLine;
- LPTSTR lpCmd2 = NULL;
- DWORD dwCreationFlags;
- STARTUPINFO aStartupInfo;
- PROCESS_INFORMATION aProcessInformation;
- SECURITY_ATTRIBUTES sa;
- int fd;
-
- sa.nLength = sizeof (SECURITY_ATTRIBUTES);
- sa.lpSecurityDescriptor = NULL;
- sa.bInheritHandle = TRUE;
-
- fRet = CreatePipe(&hInFile, &hOutFile, &sa, 2048L);
- if (!fRet) {
- errno = GetLastError();
- rb_sys_fail("mypopen: CreatePipe");
- }
-
- memset(&aStartupInfo, 0, sizeof (STARTUPINFO));
- memset(&aProcessInformation, 0, sizeof (PROCESS_INFORMATION));
- aStartupInfo.cb = sizeof (STARTUPINFO);
- aStartupInfo.dwFlags = STARTF_USESTDHANDLES;
-
- if (reading) {
- aStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
- aStartupInfo.hStdOutput = hOutFile;
- }
- else {
- aStartupInfo.hStdInput = hInFile;
- aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
- }
- aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
-
- dwCreationFlags = (NORMAL_PRIORITY_CLASS);
-
- lpCommandLine = cmd;
- if (NtHasRedirection(cmd) || isInternalCmd(cmd)) {
- lpApplicationName = getenv("COMSPEC");
- lpCmd2 = xmalloc(strlen(lpApplicationName) + 1 + strlen(cmd) + sizeof (" /c "));
- sprintf(lpCmd2, "%s %s%s", lpApplicationName, " /c ", cmd);
- lpCommandLine = lpCmd2;
- }
-
- fRet = CreateProcess(lpApplicationName, lpCommandLine, &sa, &sa,
- sa.bInheritHandle, dwCreationFlags, NULL, NULL, &aStartupInfo, &aProcessInformation);
- errno = GetLastError();
-
- if (lpCmd2)
- free(lpCmd2);
-
- if (!fRet) {
- CloseHandle(hInFile);
- CloseHandle(hOutFile);
- return NULL;
- }
-
- CloseHandle(aProcessInformation.hThread);
-
- if (reading) {
- fd = _open_osfhandle((long)hInFile, (_O_RDONLY | pipemode));
- CloseHandle(hOutFile);
- }
- else {
- fd = _open_osfhandle((long)hOutFile, (_O_WRONLY | pipemode));
- CloseHandle(hInFile);
- }
-
- if (fd == -1) {
- CloseHandle(reading ? hInFile : hOutFile);
- CloseHandle(aProcessInformation.hProcess);
- rb_sys_fail("mypopen: _open_osfhandle");
- }
-
- if ((fp = (FILE *) fdopen(fd, mode)) == NULL) {
- _close(fd);
- CloseHandle(aProcessInformation.hProcess);
- rb_sys_fail("mypopen: fdopen");
- }
-
- MyPopenRecord[slot].inuse = TRUE;
- MyPopenRecord[slot].pipe = fp;
- MyPopenRecord[slot].pid = (int)aProcessInformation.hProcess;
- return fp;
- }
-#endif
}
+extern VALUE rb_last_status;
+
int
mypclose(FILE *fp)
{
int i;
- DWORD exitcode;
+ int status = -1;
+ int ret;
Sleep(100);
@@ -683,34 +558,7 @@ mypclose(FILE *fp)
// get the return status of the process
//
+ rb_syswait(MyPopenRecord[i].pid);
+ status = NUM2INT(rb_last_status);
-#if 0
- if (_cwait(&exitcode, MyPopenRecord[i].pid, WAIT_CHILD) == -1) {
- if (errno == ECHILD) {
- fprintf(stderr, "mypclose: nosuch child as pid %x\n",
- MyPopenRecord[i].pid);
- }
- }
-#else
- for (;;) {
- if (GetExitCodeProcess((HANDLE)MyPopenRecord[i].pid, &exitcode)) {
- if (exitcode == STILL_ACTIVE) {
- //printf("Process is Active.\n");
- Sleep(100);
- TerminateProcess((HANDLE)MyPopenRecord[i].pid, 0); // ugly...
- continue;
- }
- else if (exitcode == 0) {
- //printf("done.\n");
- break;
- }
- else {
- //printf("never.\n");
- break;
- }
- }
- }
- CloseHandle((HANDLE)MyPopenRecord[i].pid);
-#endif
-
//
// close the pipe
@@ -728,5 +576,5 @@ mypclose(FILE *fp)
MyPopenRecord[i].pid = 0;
- return (int)((exitcode & 0xff) << 8);
+ return status;
}
#endif
@@ -735,109 +583,105 @@ mypclose(FILE *fp)
-typedef char* CHARP;
-/*
- * The following code is based on the do_exec and do_aexec functions
- * in file doio.c
- */
-
-int
-do_spawn(cmd)
-char *cmd;
+pid_t fork_and_exec(char *cmd)
{
- register char **a;
- register char *s;
- char **argv;
- int status = -1;
- char *shell, *cmd2;
- int mode = NtSyncProcess ? P_WAIT : P_NOWAIT;
- char quote;
- char *exec;
+ return win32_exec_and_nowait(cmd, NULL, NULL, NULL, NULL);
+}
- /* save an extra exec if possible */
- if ((shell = getenv("RUBYSHELL")) != 0) {
- if (NtHasRedirection(cmd)) {
- int i;
- char *p;
- char *argv[4];
- char *cmdline = ALLOC_N(char, (strlen(cmd) * 2 + 1));
+static pid_t win32_exec_and_nowait(char *cmd, SECURITY_ATTRIBUTES *psa, HANDLE hInput, HANDLE hOutput, HANDLE hError)
+{
+ BOOL fRet;
+ LPCSTR lpApplicationName = NULL;
+ LPTSTR lpCommandLine;
+ LPTSTR lpCmd2 = NULL;
+ DWORD dwCreationFlags;
+ STARTUPINFO aStartupInfo;
+ PROCESS_INFORMATION aProcessInformation;
+ SECURITY_ATTRIBUTES sa;
+ char *shell;
+ int slot;
+ static int initialized = 0;
- p=cmdline;
- *p++ = '"';
- for (s=cmd; *s;) {
- if (*s == '"')
- *p++ = '\\'; /* Escape d-quote */
- *p++ = *s++;
- }
- *p++ = '"';
- *p = '\0';
- /* fprintf(stderr, "do_spawn: %s %s\n", shell, cmdline); */
- argv[0] = shell;
- argv[1] = "-c";
- argv[2] = cmdline;
- argv[4] = NULL;
- status = spawnvpe(mode, argv[0], argv, environ);
- /* return spawnle(mode, shell, shell, "-c", cmd, (char*)0, environ); */
- free(cmdline);
- return (int)((status & 0xff) << 8);
- }
- }
- else if ((shell = getenv("COMSPEC")) != 0) {
- if (NtHasRedirection(cmd) /* || isInternalCmd(cmd) */) {
- status = spawnle(mode, shell, shell, "/c", cmd, (char*)0, environ);
- return (int)((status & 0xff) << 8);
+ if (!initialized++) {
+ for (slot = 0; slot < MAXCHILDNUM; slot++) {
+ ChildRecord[slot].inuse = FALSE;
}
}
- argv = ALLOC_N(CHARP, (strlen(cmd) / 2 + 2));
- cmd2 = ALLOC_N(char, (strlen(cmd) + 1));
- strcpy(cmd2, cmd);
- a = argv;
- for (s = cmd2; *s;) {
- while (*s && ISSPACE(*s)) s++;
- if (*s == '"') {
- quote = *s;
- *(a++) = s++;
- while (*s) {
- if (*s == '\\' && *(s + 1) == quote) {
- memmove(s, s + 1, strlen(s) + 1);
- s++;
- }
- else if (*s == quote) {
- s++;
- break;
- }
- s++;
- }
- }
- else if (*s) {
- *(a++) = s;
- while (*s && !ISSPACE(*s)) s++;
- }
- if (*s)
- *s++ = '\0';
- }
- *a = NULL;
- exec = NULL;
- if (argv[0]) {
- exec = ALLOC_N(char, (strlen(argv[0]) + 1));
- if (argv[0][0] == '"' && argv[0][strlen(argv[0]) - 1] == '"') {
- strcpy(exec, &argv[0][1]);
- exec[strlen(exec) - 1] = '\0';
- }
- else {
- strcpy(exec, argv[0]);
- }
- if ((status = spawnvpe(mode, exec, argv, environ)) == -1) {
- free(exec);
- free(argv);
- free(cmd2);
- return -1;
- }
+ slot = FindFreeChildSlot();
+ if (slot < 0) {
+ errno = ENOMEM; /* or EAGAIN? */
+ return -1;
+ }
+
+ if (!psa) {
+ sa.nLength = sizeof (SECURITY_ATTRIBUTES);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+ psa = &sa;
+ }
+
+ memset(&aStartupInfo, 0, sizeof (STARTUPINFO));
+ memset(&aProcessInformation, 0, sizeof (PROCESS_INFORMATION));
+ aStartupInfo.cb = sizeof (STARTUPINFO);
+ aStartupInfo.dwFlags = STARTF_USESTDHANDLES;
+ if (hInput) {
+ aStartupInfo.hStdInput = hInput;
+ }
+ else {
+ aStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ }
+ if (hOutput) {
+ aStartupInfo.hStdOutput = hOutput;
+ }
+ else {
+ aStartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ }
+ if (hError) {
+ aStartupInfo.hStdError = hError;
+ }
+ else {
+ aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+ }
+
+ dwCreationFlags = (NORMAL_PRIORITY_CLASS);
+
+ lpCommandLine = cmd;
+
+ if ((shell = getenv("RUBY_SHELL")) && NtHasRedirection(cmd)) {
+ lpApplicationName = shell;
+ lpCmd2 = ALLOC_N(char, strlen(lpApplicationName) + 1 + strlen(cmd) + sizeof (" -c "));
+ sprintf(lpCmd2, "%s %s%s", lpApplicationName, " -c ", cmd);
+ lpCommandLine = lpCmd2;
+ }
+ else if ((shell = getenv("COMSPEC")) &&
+ (NtHasRedirection(cmd) || isInternalCmd(cmd))) {
+ lpApplicationName = shell;
+ lpCmd2 = ALLOC_N(char, strlen(lpApplicationName) + 1 + strlen(cmd) + sizeof (" /c "));
+ sprintf(lpCmd2, "%s %s%s", lpApplicationName, " /c ", cmd);
+ lpCommandLine = lpCmd2;
+ }
+
+ RUBY_CRITICAL({
+ fRet = CreateProcess(lpApplicationName, lpCommandLine, psa, psa,
+ psa->bInheritHandle, dwCreationFlags, NULL, NULL,
+ &aStartupInfo, &aProcessInformation);
+ errno = GetLastError();
+ });
+ if (lpCmd2)
+ free(lpCmd2);
+
+ if (!fRet) {
+ ChildRecord[slot].inuse = FALSE;
+ rb_sys_fail("win32_exec_and_wait: CreateProcess");
}
- free(exec);
- free(cmd2);
- free(argv);
- return (int)((status & 0xff) << 8);
+
+ CloseHandle(aProcessInformation.hThread);
+
+ ChildRecord[slot].hProcess = aProcessInformation.hProcess;
+ ChildRecord[slot].pid = (pid_t)aProcessInformation.dwProcessId;
+
+
+ return ChildRecord[slot].pid;
}
@@ -1061,4 +905,5 @@ NtHasRedirection (char *cmd)
case '>':
case '<':
+ case '|':
if (!inquote)
@@ -2467,4 +2312,23 @@ waitpid (pid_t pid, int *stat_loc, int o
{
DWORD timeout;
+ DWORD exitcode;
+ int ret;
+ int slot;
+
+ if (pid == -1) {
+ for (slot = 0; slot < MAXCHILDNUM && !ChildRecord[slot].inuse; slot++)
+ ;
+ if (slot >= MAXCHILDNUM) {
+ errno = ECHILD;
+ return -1;
+ }
+ }
+ else {
+ slot = FindChildSlot(pid);
+ if (slot < 0) {
+ errno = ECHILD;
+ return -1;
+ }
+ }
if (options == WNOHANG) {
@@ -2473,15 +2337,34 @@ waitpid (pid_t pid, int *stat_loc, int o
timeout = INFINITE;
}
- RUBY_CRITICAL({
- if (wait_events((HANDLE)pid, timeout) == WAIT_OBJECT_0) {
- pid = _cwait(stat_loc, pid, 0);
+
+ for (;;) {
+ if (!GetExitCodeProcess(ChildRecord[slot].hProcess, &exitcode)) {
+ /* If an error occured, return immediatly. */
+ errno = GetLastError();
+ if (errno == ERROR_INVALID_PARAMETER) {
+ errno = ECHILD;
+ }
+ CloseHandle(ChildRecord[slot].hProcess);
+ ChildRecord[slot].inuse = FALSE;
+ pid = -1;
+ break;
}
- else {
+ else if (exitcode != STILL_ACTIVE) {
+ /* If already died, return immediatly. */
+ pid = ChildRecord[slot].pid;
+ CloseHandle(ChildRecord[slot].hProcess);
+ ChildRecord[slot].inuse = FALSE;
+ *stat_loc = exitcode << 8;
+ break;
+ }
+
+ /* wait... */
+ if (wait_events(ChildRecord[slot].hProcess, timeout) != WAIT_OBJECT_0) {
+ /* still active */
pid = 0;
+ break;
}
- });
-#if !defined __BORLANDC__
- if (pid) *stat_loc <<= 8;
-#endif
+ }
+
return pid;
}
@@ -2491,5 +2374,5 @@ waitpid (pid_t pid, int *stat_loc, int o
int _cdecl
gettimeofday(struct timeval *tv, struct timezone *tz)
-{
+{
SYSTEMTIME st;
time_t t;
@@ -2557,30 +2440,47 @@ chown(const char *path, int owner, int g
#include <signal.h>
+#ifndef SIGINT
+#define SIGINT 2
+#endif
+#ifndef SIGKILL
+#define SIGKILL 9
+#endif
int
kill(int pid, int sig)
{
- if ((unsigned int)pid == GetCurrentProcessId())
+ if ((unsigned int)pid == GetCurrentProcessId() && sig != SIGKILL)
return raise(sig);
- if (sig == 2 && pid > 0) {
- if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, (DWORD)pid)) {
- errno = GetLastError();
- return -1;
- }
+ if (sig == SIGINT && pid > 0) {
+ RUBY_CRITICAL({
+ if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, (DWORD)pid)) {
+ errno = GetLastError();
+ return -1;
+ }
+ });
}
- else if (sig == 9 && pid > 0) {
+ else if (sig == SIGKILL && pid > 0) {
HANDLE hProc;
+ int ret = 0;
- hProc = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
- if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
- errno = GetLastError();
- return -1;
- }
- if (!TerminateProcess(hProc, 0)) {
- errno = GetLastError();
+ RUBY_CRITICAL({
+ hProc = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
+ if (hProc == NULL || hProc == INVALID_HANDLE_VALUE) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ errno = ESRCH;
+ }
+ else {
+ errno = EPERM;
+ }
+ return -1;
+ }
+
+ if (!TerminateProcess(hProc, 0)) {
+ errno = EPERM;
+ ret = -1;
+ }
CloseHandle(hProc);
- return -1;
- }
- CloseHandle(hProc);
+ });
+ return ret;
}
else {
Index: win32/win32.h
===================================================================
RCS file: /src/ruby/win32/win32.h,v
retrieving revision 1.18
diff -u -2 -p -r1.18 win32.h
--- win32/win32.h 2001/03/20 23:10:05 1.18
+++ win32/win32.h 2001/06/08 12:09:58
@@ -234,5 +234,5 @@ extern int link(char *, char *);
extern int gettimeofday(struct timeval *, struct timezone *);
extern pid_t waitpid (pid_t, int *, int);
-extern int do_spawn(char *);
+extern pid_t fork_and_exec(char *);
extern int kill(int, int);
extern int isinf(double);
こっちがおまけ(上からの差分)
diff -u2pr aaa/process.c mytree/process.c
--- aaa/process.c Fri Jun 8 21:09:34 2001
+++ mytree/process.c Fri Jun 8 17:12:38 2001
@@ -745,4 +745,43 @@ rb_f_exec(argc, argv)
}
+#ifdef NT
+static VALUE
+rb_f_fork_and_exec(argc, argv)
+ int argc;
+ VALUE *argv;
+{
+ VALUE cmd;
+ VALUE prog = 0;
+ int pid;
+
+ if (argc == 0) {
+ rb_raise(rb_eArgError, "wrong # of arguments");
+ }
+
+ if (TYPE(argv[0]) == T_ARRAY) {
+ if (RARRAY(argv[0])->len != 2) {
+ rb_raise(rb_eArgError, "wrong first argument");
+ }
+ prog = RARRAY(argv[0])->ptr[0];
+ argv[0] = RARRAY(argv[0])->ptr[1];
+ }
+ if (prog) {
+ SafeStringValue(prog);
+ }
+ if (argc == 1 && prog == 0) {
+ cmd = argv[0];
+ SafeStringValue(cmd);
+ pid = fork_and_exec(RSTRING(cmd)->ptr);
+ }
+ else {
+ cmd = rb_ary_join(rb_ary_new4(argc, argv), rb_str_new2(" "));
+ SafeStringValue(cmd);
+ pid = fork_and_exec(RSTRING(cmd)->ptr);
+ }
+
+ return INT2NUM(pid);
+}
+#endif
+
static VALUE
rb_f_fork(obj)
@@ -1335,4 +1374,7 @@ Init_process()
rb_define_global_function("exec", rb_f_exec, -1);
rb_define_global_function("fork", rb_f_fork, 0);
+#ifdef NT
+ rb_define_global_function("fork_and_exec", rb_f_fork_and_exec, -1);
+#endif
rb_define_global_function("exit!", rb_f_exit_bang, -1);
rb_define_global_function("system", rb_f_system, -1);
それでは。
--
U.Nakamura <usa@osb.att.ne.jp>