I've created a diff basing on knowledge I got from browsing svn
repository. After I patched mono-1.2.1 against it I get no more zombie
processes. Try it out and tell me what your results are :)

Best regards,
Jurek 'Koxta' Bartuszek
--- trunk/mono/mono/io-layer/process-private.h  2006/05/12 10:38:20     60618
+++ trunk/mono/mono/io-layer/process-private.h  2006/11/23 00:39:10     68378
@@ -31,6 +31,7 @@
        gchar proc_name[_WAPI_PROC_NAME_MAX_LEN];
        size_t min_working_set;
        size_t max_working_set;
+       gboolean waited;
 };
 
 extern void _wapi_process_reap (void);

--- trunk/mono/mono/io-layer/processes.c        2006/11/18 19:02:51     68130
+++ trunk/mono/mono/io-layer/processes.c        2006/11/23 00:39:10     68378
@@ -80,6 +80,10 @@
                process_handle->exitstatus = WEXITSTATUS(status);
        }
        _wapi_time_t_to_filetime (time(NULL), &process_handle->exit_time);
+
+       /* Don't set process_handle->waited here, it needs to only
+        * happen in the parent when wait() has been called.
+        */
        
 #ifdef DEBUG
        g_message ("%s: Setting handle %p signalled", __func__, handle);
@@ -108,17 +112,17 @@
        int status;
        pid_t ret;
        
-       if (_wapi_handle_issignalled (test)) {
-               /* We've already done this one */
-               return (FALSE);
-       }
-       
        ok = _wapi_lookup_handle (test, WAPI_HANDLE_PROCESS,
                                  (gpointer *)&process);
        if (ok == FALSE) {
                /* The handle must have been too old and was reaped */
                return (FALSE);
        }
+
+       if (process->waited) {
+               /* We've already done this one */
+               return(FALSE);
+       }
        
        do {
                ret = waitpid (process->id, &status, WNOHANG);
@@ -138,6 +142,8 @@
        g_message ("%s: Process %d finished", __func__, ret);
 #endif
 
+       process->waited = TRUE;
+       
        *(int *)user_data = status;
        
        return (TRUE);
@@ -185,8 +191,16 @@
 #ifdef DEBUG
        g_message ("%s: Waiting for process %p", __func__, handle);
 #endif
+
+       ok = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
+                                 (gpointer *)&process_handle);
+       if (ok == FALSE) {
+               g_warning ("%s: error looking up process handle %p", __func__,
+                          handle);
+               return(WAIT_FAILED);
+       }
        
-       if (_wapi_handle_issignalled (handle)) {
+       if (process_handle->waited) {
                /* We've already done this one */
 #ifdef DEBUG
                g_message ("%s: Process %p already signalled", __func__,
@@ -195,14 +209,6 @@
 
                return (WAIT_OBJECT_0);
        }
-
-       ok = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
-                                 (gpointer *)&process_handle);
-       if (ok == FALSE) {
-               g_warning ("%s: error looking up process handle %p", __func__,
-                          handle);
-               return(WAIT_FAILED);
-       }
        
        pid = process_handle->id;
        
@@ -211,9 +217,15 @@
 #endif
 
        if (timeout == INFINITE) {
-               while ((ret = waitpid (pid, &status, 0)) != pid) {
-                       if (ret == (pid_t)-1 && errno != EINTR) {
-                               return(WAIT_FAILED);
+               if (pid == _wapi_getpid ()) {
+                       do {
+                               Sleep (10000);
+                       } while(1);
+               } else {
+                       while ((ret = waitpid (pid, &status, 0)) != pid) {
+                               if (ret == (pid_t)-1 && errno != EINTR) {
+                                       return(WAIT_FAILED);
+                               }
                        }
                }
        } else if (timeout == 0) {
@@ -224,18 +236,47 @@
                }
        } else {
                /* Poll in a loop */
-               do {
-                       ret = waitpid (pid, &status, WNOHANG);
-                       if (ret == pid) {
-                               break;
-                       } else if (ret == (pid_t)-1 && errno != EINTR) {
-                               return(WAIT_FAILED);
-                       }
+               if (pid == _wapi_getpid ()) {
+                       Sleep (timeout);
+                       return(WAIT_TIMEOUT);
+               } else {
+                       do {
+                               ret = waitpid (pid, &status, WNOHANG);
+#ifdef DEBUG
+                               g_message ("%s: waitpid returns: %d, timeout is 
%d", __func__, ret, timeout);
+#endif
+                               
+                               if (ret == pid) {
+                                       break;
+                               } else if (ret == (pid_t)-1 &&
+                                          errno != EINTR) {
+#ifdef DEBUG
+                                       g_message ("%s: waitpid failure: %s",
+                                                  __func__,
+                                                  g_strerror (errno));
+#endif
 
-                       _wapi_handle_spin (100);
-                       timeout -= 100;
-               } while (timeout > 0);
+                                       if (errno == ECHILD &&
+                                           process_handle->waited) {
+                                               /* The background
+                                                * process reaper must
+                                                * have got this one
+                                                */
+#ifdef DEBUG
+                                               g_message ("%s: Process %p 
already reaped", __func__, handle);
+#endif
 
+                                               return(WAIT_OBJECT_0);
+                                       } else {
+                                               return(WAIT_FAILED);
+                                       }
+                               }
+
+                               _wapi_handle_spin (100);
+                               timeout -= 100;
+                       } while (timeout > 0);
+               }
+               
                if (timeout <= 0) {
                        return(WAIT_TIMEOUT);
                }
@@ -251,7 +292,8 @@
                SetLastError (ERROR_OUTOFMEMORY);
                return (WAIT_FAILED);
        }
-
+       process_handle->waited = TRUE;
+       
        return(WAIT_OBJECT_0);
 }
 
@@ -268,6 +310,8 @@
        process_handle->min_working_set = 204800;
        process_handle->max_working_set = 1413120;
 
+       process_handle->waited = FALSE;
+       
        _wapi_time_t_to_filetime (time (NULL), &process_handle->create_time);
 }
 
@@ -919,6 +963,11 @@
                g_strfreev (env_strings);
        }
        
+#ifdef DEBUG
+       g_message ("%s: returning handle %p for pid %d", __func__, handle,
+                  pid);
+#endif
+
        return(ret);
 }
                
@@ -960,6 +1009,8 @@
        const char *handle_env;
        struct _WapiHandle_process process_handle = {0};
        
+       mono_once (&process_ops_once, process_ops_init);
+       
        handle_env = g_getenv ("_WAPI_PROCESS_HANDLE_OFFSET");
        g_unsetenv ("_WAPI_PROCESS_HANDLE_OFFSET");
        
--- trunk/mono/mono/io-layer/wapi-private.h     2006/03/24 12:19:30     58409
+++ trunk/mono/mono/io-layer/wapi-private.h     2006/11/23 00:39:10     68378
@@ -24,8 +24,7 @@
 /* Increment this whenever an incompatible change is made to the
  * shared handle structure.
  */
-/* Next time I change this, remember to fix the process count in shared.c */
-#define _WAPI_HANDLE_VERSION 10
+#define _WAPI_HANDLE_VERSION 11
 
 typedef enum {
        WAPI_HANDLE_UNUSED=0,

--- trunk/mono/mono/io-layer/shared.c   2006/07/25 12:56:51     62955
+++ trunk/mono/mono/io-layer/shared.c   2006/11/23 00:39:10     68378
@@ -292,12 +292,11 @@
        for (i = 0; i < _WAPI_SHARED_SEM_COUNT; i++) {
                def_vals[i] = 1;
        }
-#ifdef NEXT_VERSION_INC
+
        /* Process count must start at '0' - the 1 for all the others
         * sets the semaphore to "unlocked"
         */
        def_vals[_WAPI_SHARED_SEM_PROCESS_COUNT] = 0;
-#endif
        
        defs.array = def_vals;
        
@@ -438,19 +437,9 @@
        
        proc_count = semctl (_wapi_sem_id, _WAPI_SHARED_SEM_PROCESS_COUNT,
                             GETVAL);
-#ifdef NEXT_VERSION_INC
+
        g_assert (proc_count > 0);
        if (proc_count == 1) {
-#else
-       /* Compatibility - the semaphore was initialised to '1' (which
-        * normally means 'unlocked'.  Instead of fixing that right
-        * now, which would mean a shared file version increment, just
-        * cope with the value starting too high for now.  Fix this
-        * next time I have to change the file version.
-        */
-       g_assert (proc_count > 1);
-       if (proc_count == 2) {
-#endif
                /* Just us, so blow away the semaphores and the shared
                 * files
                 */
_______________________________________________
Mono-list maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-list

Reply via email to