waitpid() now handles externally spawned pids correctly;
Gurusamy Sarathy [Thu, 17 Aug 2000 00:19:20 +0000 (00:19 +0000)]
fixes for backtick/wait/waitpid failures on Windows 9x

these changes make the pid returned by process functions on
Windows 9x always positive by clearing the high bit (which
is always set on Win9x); pseudo-process PIDs are likewise
always negative now on Win9x (just as on NT/2000)

p4raw-id: //depot/perl@6661

pp_sys.c
win32/perlhost.h
win32/win32.c

index ba9e3bf..8a77c09 100644 (file)
--- a/pp_sys.c
+++ b/pp_sys.c
@@ -3868,6 +3868,8 @@ PP(pp_system)
     }
     PerlProc__exit(-1);
 #else /* ! FORK or VMS or OS/2 */
+    PL_statusvalue = 0;
+    result = 0;
     if (PL_op->op_flags & OPf_STACKED) {
        SV *really = *++MARK;
        value = (I32)do_aspawn(really, (void **)MARK, (void **)SP);
@@ -3877,10 +3879,12 @@ PP(pp_system)
     else {
        value = (I32)do_spawn(SvPVx(sv_mortalcopy(*SP), n_a));
     }
+    if (PL_statusvalue == -1)  /* hint that value must be returned as is */
+       result = 1;
     STATUS_NATIVE_SET(value);
     do_execfree();
     SP = ORIGMARK;
-    PUSHi(STATUS_CURRENT);
+    PUSHi(result ? value : STATUS_CURRENT);
 #endif /* !FORK or VMS */
     RETURN;
 }
index 3b1d8ca..4509a2c 100644 (file)
@@ -1666,6 +1666,11 @@ win32_start_child(LPVOID arg)
     w32_pseudo_id = id;
 #else
     w32_pseudo_id = GetCurrentThreadId();
+    if (IsWin95()) {
+       int pid = (int)w32_pseudo_id;
+       if (pid < 0)
+           w32_pseudo_id = -pid;
+    }
 #endif
     if (tmpgv = gv_fetchpv("$", TRUE, SVt_PV))
        sv_setiv(GvSV(tmpgv), -(IV)w32_pseudo_id);
@@ -1781,6 +1786,11 @@ PerlProcFork(struct IPerlProc* piPerl)
        errno = EAGAIN;
        return -1;
     }
+    if (IsWin95()) {
+       int pid = (int)id;
+       if (pid < 0)
+           id = -pid;
+    }
     w32_pseudo_child_handles[w32_num_pseudo_children] = handle;
     w32_pseudo_child_pids[w32_num_pseudo_children] = id;
     ++w32_num_pseudo_children;
index 56ebdaf..5af22ff 100644 (file)
@@ -436,12 +436,19 @@ win32_os_id(void)
 DllExport int
 win32_getpid(void)
 {
+    int pid;
 #ifdef USE_ITHREADS
     dTHXo;
     if (w32_pseudo_id)
        return -((int)w32_pseudo_id);
 #endif
-    return _getpid();
+    pid = _getpid();
+    /* Windows 9x appears to always reports a pid for threads and processes
+     * that has the high bit set. So we treat the lower 31 bits as the
+     * "real" PID for Perl's purposes. */
+    if (IsWin95() && pid < 0)
+       pid = -pid;
+    return pid;
 }
 
 /* Tokenize a string.  Words are null-separated, and the list
@@ -568,7 +575,11 @@ do_aspawn(void *vreally, void **vmark, void **vsp)
                               (const char* const*)argv);
     }
 
-    if (flag != P_NOWAIT) {
+    if (flag == P_NOWAIT) {
+       if (IsWin95())
+           PL_statusvalue = -1;        /* >16bits hint for pp_system() */
+    }
+    else {
        if (status < 0) {
            dTHR;
            if (ckWARN(WARN_EXEC))
@@ -657,7 +668,11 @@ do_spawn2(char *cmd, int exectype)
        cmd = argv[0];
        Safefree(argv);
     }
-    if (exectype != EXECF_SPAWN_NOWAIT) {
+    if (exectype == EXECF_SPAWN_NOWAIT) {
+       if (IsWin95())
+           PL_statusvalue = -1;        /* >16bits hint for pp_system() */
+    }
+    else {
        if (status < 0) {
            dTHR;
            if (ckWARN(WARN_EXEC))
@@ -1034,6 +1049,10 @@ win32_kill(int pid, int sig)
                return 0;
            }
        }
+       else if (IsWin95()) {
+           pid = -pid;
+           goto alien_process;
+       }
     }
     else
 #endif
@@ -1049,7 +1068,9 @@ win32_kill(int pid, int sig)
            }
        }
        else {
-           hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
+alien_process:
+           hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
+                                  (IsWin95() ? -pid : pid));
            if (hProcess) {
                if (!sig)
                    return 0;
@@ -1636,6 +1657,7 @@ DllExport int
 win32_waitpid(int pid, int *status, int flags)
 {
     dTHXo;
+    DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
     int retval = -1;
     if (pid == -1)                             /* XXX threadid == 1 ? */
        return win32_wait(status);
@@ -1644,7 +1666,6 @@ win32_waitpid(int pid, int *status, int flags)
        long child = find_pseudo_pid(-pid);
        if (child >= 0) {
            HANDLE hThread = w32_pseudo_child_handles[child];
-           DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
            DWORD waitcode = WaitForSingleObject(hThread, timeout);
            if (waitcode == WAIT_TIMEOUT) {
                return 0;
@@ -1660,35 +1681,53 @@ win32_waitpid(int pid, int *status, int flags)
            else
                errno = ECHILD;
        }
+       else if (IsWin95()) {
+           pid = -pid;
+           goto alien_process;
+       }
     }
 #endif
     else {
+       HANDLE hProcess;
+       DWORD waitcode;
        long child = find_pid(pid);
        if (child >= 0) {
-           HANDLE hProcess = w32_child_handles[child];
-           DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
-           DWORD waitcode = WaitForSingleObject(hProcess, timeout);
+           hProcess = w32_child_handles[child];
+           waitcode = WaitForSingleObject(hProcess, timeout);
            if (waitcode == WAIT_TIMEOUT) {
                return 0;
            }
            else if (waitcode != WAIT_FAILED) {
-                if (GetExitCodeProcess(hProcess, &waitcode)) {
-                    *status = (int)((waitcode & 0xff) << 8);
-                    retval = (int)w32_child_pids[child];
-                    remove_dead_process(child);
-                    return retval;
-                }
+               if (GetExitCodeProcess(hProcess, &waitcode)) {
+                   *status = (int)((waitcode & 0xff) << 8);
+                   retval = (int)w32_child_pids[child];
+                   remove_dead_process(child);
+                   return retval;
+               }
            }
            else
                errno = ECHILD;
        }
        else {
-           retval = cwait(status, pid, WAIT_CHILD);
-           /* cwait() returns "correctly" on Borland */
-#ifndef __BORLANDC__
-           if (status)
-               *status *= 256;
-#endif
+alien_process:
+           hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
+                                  (IsWin95() ? -pid : pid));
+           if (hProcess) {
+               waitcode = WaitForSingleObject(hProcess, timeout);
+               if (waitcode == WAIT_TIMEOUT) {
+                   return 0;
+               }
+               else if (waitcode != WAIT_FAILED) {
+                   if (GetExitCodeProcess(hProcess, &waitcode)) {
+                       *status = (int)((waitcode & 0xff) << 8);
+                       CloseHandle(hProcess);
+                       return pid;
+                   }
+               }
+               CloseHandle(hProcess);
+           }
+           else
+               errno = ECHILD;
        }
     }
     return retval >= 0 ? pid : retval;                
@@ -3273,9 +3312,12 @@ RETRY:
 
     if (mode == P_NOWAIT) {
        /* asynchronous spawn -- store handle, return PID */
-       w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
-       w32_child_pids[w32_num_children] = ProcessInformation.dwProcessId;
        ret = (int)ProcessInformation.dwProcessId;
+       if (IsWin95() && ret < 0)
+           ret = -ret;
+
+       w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
+       w32_child_pids[w32_num_children] = (DWORD)ret;
        ++w32_num_children;
     }
     else  {
@@ -3835,8 +3877,11 @@ XS(w32_Spawn)
                &stStartInfo,           /* -> Startup info */
                &stProcInfo))           /* <- Process info (if OK) */
     {
+       int pid = (int)stProcInfo.dwProcessId;
+       if (IsWin95() && pid < 0)
+           pid = -pid;
+       sv_setiv(ST(2), pid);
        CloseHandle(stProcInfo.hThread);/* library source code does this. */
-       sv_setiv(ST(2), stProcInfo.dwProcessId);
        bSuccess = TRUE;
     }
     XSRETURN_IV(bSuccess);