From: "U.Nakamura" Date: 2001-06-03T00:10:40+09:00 Subject: [ruby-dev:13446] Re: mswin32/ming32 system patch (experimental) こんにちは、なかむら(う)です。 At Sat, 2 Jun 2001 04:54:08 +0900, "U.Nakamura" wrote in '[ruby-dev:13442] Re: mswin32/ming32 system patch (experimental)' > > CreateProcess() 使う方向でいいんじゃないでしょうか。ただ、子 > > プロセスの終了待ちは rb_f_system() の方でやった方がいいような > > 気がしなくもありません。それと、このパッチだと RUBYSHELL や > > COMSPEC を使うときには、やはりスレッドが止まってしまうように思 > > えるのですが。 > > 前者の方は、まだ考慮中です。process.cの中をそれなりの > 規模でいじらないといけなさそうで... やってみました。 何ヶ所か気に入らないところがありますが(特にmypcloseの中身と exec_and_nowaitという関数名とその引数)、いちおう動いてるみ たいです。 子プロセスの戻り値が怪しいんではないかとかいう気はしてます が。 僕としては、これに皆さんの意見を投げてもらってから1.7に入れ てみようかと思ってるのですが、いかがなもんでしょう? 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/02 15:04:10 @@ -228,5 +228,5 @@ static st_table *pid_tbl; #endif -static int +int rb_waitpid(pid, flags, st) int pid; @@ -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, exec_and_nowait() exec rb_sys_fail() */ + pid = exec_and_nowait(RSTRING(cmd)->ptr, NULL, NULL, NULL); + 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/02 15:04:13 @@ -574,13 +574,8 @@ mypopen (char *cmd, char *mode) { int p[2]; + int pid; 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; @@ -596,44 +591,11 @@ mypopen (char *cmd, char *mode) } - 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; + pid = exec_and_nowait(cmd, &sa, NULL, 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; + pid = exec_and_nowait(cmd, &sa, hInFile, NULL); } - CloseHandle(aProcessInformation.hThread); - if (reading) { fd = _open_osfhandle((long)hInFile, (_O_RDONLY | pipemode)); @@ -647,5 +609,5 @@ mypopen (char *cmd, char *mode) if (fd == -1) { CloseHandle(reading ? hInFile : hOutFile); - CloseHandle(aProcessInformation.hProcess); + CloseHandle((HANDLE)pid); rb_sys_fail("mypopen: _open_osfhandle"); } @@ -653,5 +615,5 @@ mypopen (char *cmd, char *mode) if ((fp = (FILE *) fdopen(fd, mode)) == NULL) { _close(fd); - CloseHandle(aProcessInformation.hProcess); + CloseHandle((HANDLE)pid); rb_sys_fail("mypopen: fdopen"); } @@ -659,5 +621,5 @@ mypopen (char *cmd, char *mode) MyPopenRecord[slot].inuse = TRUE; MyPopenRecord[slot].pipe = fp; - MyPopenRecord[slot].pid = (int)aProcessInformation.hProcess; + MyPopenRecord[slot].pid = pid; return fp; } @@ -665,9 +627,12 @@ mypopen (char *cmd, char *mode) } +int rb_waitpid(int, int, int*); + int mypclose(FILE *fp) { int i; - DWORD exitcode; + int status = -1; + int ret; Sleep(100); @@ -683,33 +648,16 @@ mypclose(FILE *fp) // get the return status of the process // - -#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); + for (;;) { + ret = rb_waitpid(MyPopenRecord[i].pid, WNOHANG, &status); + if (ret > 0 || (ret == -1 && errno != EINTR)) { + // process is done, or die by some error. + break; } + + // process is still active + Sleep(100); + TerminateProcess((HANDLE)MyPopenRecord[i].pid, 0); } -#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 + CloseHandle((HANDLE)MyPopenRecord[i].pid); // @@ -728,5 +676,5 @@ mypclose(FILE *fp) MyPopenRecord[i].pid = 0; - return (int)((exitcode & 0xff) << 8); + return status; } #endif @@ -741,103 +689,81 @@ typedef char* CHARP; */ -int -do_spawn(cmd) -char *cmd; +int exec_and_nowait(char *cmd, SECURITY_ATTRIBUTES *psa, HANDLE hInput, HANDLE hOutput) { - 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; - - /* 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)); - - 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); - } + BOOL fRet; + LPCSTR lpApplicationName = NULL; + LPTSTR lpCommandLine; + LPTSTR lpCmd2 = NULL; + DWORD dwCreationFlags; + STARTUPINFO aStartupInfo; + PROCESS_INFORMATION aProcessInformation; + SECURITY_ATTRIBUTES sa; + char *shell; + + 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); + } + aStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); - 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'; + 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; } - *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]); + 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, &sa, &sa, + sa.bInheritHandle, dwCreationFlags, NULL, NULL, + &aStartupInfo, &aProcessInformation); + errno = GetLastError(); + }); + if (lpCmd2) + free(lpCmd2); + + if (!fRet) { + if (hInput) { + CloseHandle(hInput); } - if ((status = spawnvpe(mode, exec, argv, environ)) == -1) { - free(exec); - free(argv); - free(cmd2); - return -1; + if (hOutput) { + CloseHandle(hOutput); } + rb_sys_fail("exec_and_wait: CreateProcess"); } - free(exec); - free(cmd2); - free(argv); - return (int)((status & 0xff) << 8); + + CloseHandle(aProcessInformation.hThread); + + return (int)aProcessInformation.hProcess; } @@ -1034,5 +960,5 @@ NtHasRedirection (char *cmd) int inquote = 0; char quote = '\0'; - char *ptr ; + const char *ptr ; // @@ -1061,4 +987,5 @@ NtHasRedirection (char *cmd) case '>': case '<': + case '|': if (!inquote) 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/02 15:04:13 @@ -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 int exec_and_nowait(char *, SECURITY_ATTRIBUTES *, HANDLE, HANDLE); extern int kill(int, int); extern int isinf(double); それでは。 -- U.Nakamura