Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mono / metadata / w32process-unix.c
index cc4762ee7f56658fc9cc812124e68bbf41bd666f..f71dc34bdb758365d5b4d928476d27255c164a97 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * process.c: System.Diagnostics.Process support
+/**
+ * \file
+ * System.Diagnostics.Process support
  *
  * Author:
  *     Dick Porter (dick@ximian.com)
@@ -49,6 +50,7 @@
 #include <mono/metadata/w32process.h>
 #include <mono/metadata/w32process-internals.h>
 #include <mono/metadata/w32process-unix-internals.h>
+#include <mono/metadata/w32error.h>
 #include <mono/metadata/class.h>
 #include <mono/metadata/class-internals.h>
 #include <mono/metadata/object.h>
@@ -56,8 +58,8 @@
 #include <mono/metadata/metadata.h>
 #include <mono/metadata/metadata-internals.h>
 #include <mono/metadata/exception.h>
-#include <mono/io-layer/io-layer.h>
 #include <mono/metadata/w32handle.h>
+#include <mono/metadata/w32file.h>
 #include <mono/utils/mono-membar.h>
 #include <mono/utils/mono-logger-internals.h>
 #include <mono/utils/strenc.h>
@@ -68,6 +70,8 @@
 #include <mono/utils/mono-time.h>
 #include <mono/utils/mono-mmap.h>
 #include <mono/utils/strenc.h>
+#include <mono/utils/mono-io-portability.h>
+#include <mono/utils/w32api.h>
 
 #ifndef MAXPATHLEN
 #define MAXPATHLEN 242
@@ -95,18 +99,6 @@ static char *mono_environ[1] = { NULL };
 extern char **environ;
 #endif
 
-/*
- * Handles > _WAPI_PROCESS_UNHANDLED are pseudo handles which represent processes
- * not started by the runtime.
- */
-/* This marks a system process that we don't have a handle on */
-/* FIXME: Cope with PIDs > sizeof guint */
-#define _WAPI_PROCESS_UNHANDLED (1 << (8*sizeof(pid_t)-1))
-
-#define WAPI_IS_PSEUDO_PROCESS_HANDLE(handle) ((GPOINTER_TO_UINT(handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED)
-#define WAPI_PID_TO_HANDLE(pid) GINT_TO_POINTER (_WAPI_PROCESS_UNHANDLED + (pid))
-#define WAPI_HANDLE_TO_PID(handle) (GPOINTER_TO_UINT ((handle)) - _WAPI_PROCESS_UNHANDLED)
-
 typedef enum {
        STARTF_USESHOWWINDOW=0x001,
        STARTF_USESIZE=0x002,
@@ -138,9 +130,7 @@ typedef struct {
 /*
  * Process describes processes we create.
  * It contains a semaphore that can be waited on in order to wait
- * for process termination. It's accessed in our SIGCHLD handler,
- * when status is updated (and pid cleared, to not clash with
- * subsequent processes that may get executed).
+ * for process termination.
  */
 typedef struct _Process {
        pid_t pid; /* the pid of the process. This value is only valid until the process has exited. */
@@ -151,7 +141,6 @@ typedef struct _Process {
         * the process has exited, so that the information there isn't lost.
         */
        gpointer handle;
-       gboolean freeable;
        gboolean signalled;
        struct _Process *next;
 } Process;
@@ -159,6 +148,7 @@ typedef struct _Process {
 /* MonoW32HandleProcess is a structure containing all the required information for process handling. */
 typedef struct {
        pid_t pid;
+       gboolean child;
        guint32 exitstatus;
        gpointer main_thread;
        guint64 create_time;
@@ -537,21 +527,10 @@ static mono_lazy_init_t process_sig_chld_once = MONO_LAZY_INIT_STATUS_NOT_INITIA
 
 static gchar *cli_launcher;
 
-/* The signal-safe logic to use processes goes like this:
- * - The list must be safe to traverse for the signal handler at all times.
- *   It's safe to: prepend an entry (which is a single store to 'processes'),
- *   unlink an entry (assuming the unlinked entry isn't freed and doesn't
- *   change its 'next' pointer so that it can still be traversed).
- * When cleaning up we first unlink an entry, then we verify that
- * the read lock isn't locked. Then we can free the entry, since
- * we know that nobody is using the old version of the list (including
- * the unlinked entry).
- * We also need to lock when adding and cleaning up so that those two
- * operations don't mess with eachother. (This lock is not used in the
- * signal handler) */
 static Process *processes;
 static mono_mutex_t processes_mutex;
 
+static pid_t current_pid;
 static gpointer current_process;
 
 static const gunichar2 utf16_space_bytes [2] = { 0x20, 0 };
@@ -559,6 +538,33 @@ static const gunichar2 *utf16_space = utf16_space_bytes;
 static const gunichar2 utf16_quote_bytes [2] = { 0x22, 0 };
 static const gunichar2 *utf16_quote = utf16_quote_bytes;
 
+/* Check if a pid is valid - i.e. if a process exists with this pid. */
+static gboolean
+process_is_alive (pid_t pid)
+{
+#if defined(HOST_WATCHOS)
+       return TRUE; // TODO: Rewrite using sysctl
+#elif defined(HOST_DARWIN) || defined(__OpenBSD__) || defined(__FreeBSD__)
+       if (pid == 0)
+               return FALSE;
+       if (kill (pid, 0) == 0)
+               return TRUE;
+       if (errno == EPERM)
+               return TRUE;
+       return FALSE;
+#elif defined(__HAIKU__)
+       team_info teamInfo;
+       if (get_team_info ((team_id)pid, &teamInfo) == B_OK)
+               return TRUE;
+       return FALSE;
+#else
+       gchar *dir = g_strdup_printf ("/proc/%d", pid);
+       gboolean result = access (dir, F_OK) == 0;
+       g_free (dir);
+       return result;
+#endif
+}
+
 static void
 process_details (gpointer data)
 {
@@ -589,11 +595,7 @@ process_wait (gpointer handle, guint32 timeout, gboolean *alerted)
        Process *process;
        gboolean res;
 
-       /* FIXME: We can now easily wait on processes that aren't our own children,
-        * but WaitFor*Object won't call us for pseudo handles. */
-       g_assert (!WAPI_IS_PSEUDO_PROCESS_HANDLE (handle));
-
-       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u)", __func__, handle, timeout);
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT ")", __func__, handle, timeout);
 
        if (alerted)
                *alerted = FALSE;
@@ -606,56 +608,51 @@ process_wait (gpointer handle, guint32 timeout, gboolean *alerted)
 
        if (process_handle->exited) {
                /* We've already done this one */
-               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): Process already exited", __func__, handle, timeout);
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): Process already exited", __func__, handle, timeout);
                return MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
        }
 
        pid = process_handle->pid;
 
-       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): PID: %d", __func__, handle, timeout, pid);
-
-       /* We don't need to lock processes here, the entry
-        * has a handle_count > 0 which means it will not be freed. */
-       process = process_handle->process;
-       if (!process) {
-               pid_t res;
+       if (pid == mono_process_current_pid ()) {
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): waiting on current process", __func__, handle, timeout);
+               return MONO_W32HANDLE_WAIT_RET_TIMEOUT;
+       }
 
-               if (pid == mono_process_current_pid ()) {
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): waiting on current process", __func__, handle, timeout);
-                       return MONO_W32HANDLE_WAIT_RET_TIMEOUT;
-               }
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): PID: %d", __func__, handle, timeout, pid);
 
-               /* This path is used when calling Process.HasExited, so
-                * it is only used to poll the state of the process, not
-                * to actually wait on it to exit */
-               g_assert (timeout == 0);
+       if (!process_handle->child) {
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): waiting on non-child process", __func__, handle, timeout);
 
-               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): waiting on non-child process", __func__, handle, timeout);
+               if (!process_is_alive (pid)) {
+                       /* assume the process has exited */
+                       process_handle->exited = TRUE;
+                       process_handle->exitstatus = -1;
+                       mono_w32handle_set_signal_state (handle, TRUE, TRUE);
 
-               res = waitpid (pid, &status, WNOHANG);
-               if (res == 0) {
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): non-child process wait timeout", __func__, handle, timeout);
-                       return MONO_W32HANDLE_WAIT_RET_TIMEOUT;
-               }
-               if (res > 0) {
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): non-child process waited successfully", __func__, handle, timeout);
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): non-child process is not alive anymore (2)", __func__, handle, timeout);
                        return MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
                }
 
-               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): non-child process wait failed, error : %s (%d))", __func__, handle, timeout, g_strerror (errno), errno);
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): non-child process wait failed, error : %s (%d))", __func__, handle, timeout, g_strerror (errno), errno);
                return MONO_W32HANDLE_WAIT_RET_FAILED;
        }
 
+       /* We don't need to lock processes here, the entry
+        * has a handle_count > 0 which means it will not be freed. */
+       process = process_handle->process;
+       g_assert (process);
+
        start = mono_msec_ticks ();
        now = start;
 
        while (1) {
                if (timeout != MONO_INFINITE_WAIT) {
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): waiting on semaphore for %li ms...",
-                               __func__, handle, timeout, (long)(timeout - (now - start)));
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): waiting on semaphore for %" G_GINT64_FORMAT " ms...",
+                               __func__, handle, timeout, timeout - (now - start));
                        ret = mono_os_sem_timedwait (&process->exit_sem, (timeout - (now - start)), alerted ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE);
                } else {
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): waiting on semaphore forever...",
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): waiting on semaphore forever...",
                                __func__, handle, timeout);
                        ret = mono_os_sem_wait (&process->exit_sem, alerted ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE);
                }
@@ -667,25 +664,25 @@ process_wait (gpointer handle, guint32 timeout, gboolean *alerted)
                }
 
                if (ret == MONO_SEM_TIMEDWAIT_RET_TIMEDOUT) {
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): wait timeout (timeout = 0)", __func__, handle, timeout);
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): wait timeout (timeout = 0)", __func__, handle, timeout);
                        return MONO_W32HANDLE_WAIT_RET_TIMEOUT;
                }
 
                now = mono_msec_ticks ();
                if (now - start >= timeout) {
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): wait timeout", __func__, handle, timeout);
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): wait timeout", __func__, handle, timeout);
                        return MONO_W32HANDLE_WAIT_RET_TIMEOUT;
                }
 
                if (alerted && ret == MONO_SEM_TIMEDWAIT_RET_ALERTED) {
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): wait alerted", __func__, handle, timeout);
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): wait alerted", __func__, handle, timeout);
                        *alerted = TRUE;
                        return MONO_W32HANDLE_WAIT_RET_ALERTED;
                }
        }
 
        /* Process must have exited */
-       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): Waited successfully", __func__, handle, timeout);
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): Waited successfully", __func__, handle, timeout);
 
        status = process->status;
        if (WIFSIGNALED (status))
@@ -697,7 +694,7 @@ process_wait (gpointer handle, guint32 timeout, gboolean *alerted)
 
        process_handle->exited = TRUE;
 
-       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): Setting pid %d signalled, exit status %d",
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %" G_GUINT32_FORMAT "): Setting pid %d signalled, exit status %d",
                   __func__, handle, timeout, process_handle->pid, process_handle->exitstatus);
 
        mono_w32handle_set_signal_state (handle, TRUE, TRUE);
@@ -711,9 +708,6 @@ processes_cleanup (void)
        static gint32 cleaning_up;
        Process *process;
        Process *prev = NULL;
-       GSList *finished = NULL;
-       GSList *l;
-       gpointer unref_handle;
 
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s", __func__);
 
@@ -721,54 +715,39 @@ processes_cleanup (void)
        if (InterlockedCompareExchange (&cleaning_up, 1, 0) != 0)
                return;
 
+       /*
+        * This needs to be done outside the lock but atomically, hence the CAS above.
+        */
        for (process = processes; process; process = process->next) {
                if (process->signalled && process->handle) {
                        /* This process has exited and we need to remove the artifical ref
                         * on the handle */
-                       mono_w32handle_unref (process->handle);
+                       mono_w32handle_close (process->handle);
                        process->handle = NULL;
                }
        }
 
-       /*
-        * Remove processes which exited from the processes list.
-        * We need to synchronize with the sigchld handler here, which runs
-        * asynchronously. The handler requires that the processes list
-        * remain valid.
-        */
        mono_os_mutex_lock (&processes_mutex);
 
-       for (process = processes; process; process = process->next) {
-               if (process->handle_count == 0 && process->freeable) {
+       for (process = processes; process;) {
+               Process *next = process->next;
+               if (process->handle_count == 0 && process->signalled) {
                        /*
                         * Unlink the entry.
-                        * This code can run parallel with the sigchld handler, but the
-                        * modifications it makes are safe.
                         */
                        if (process == processes)
                                processes = process->next;
                        else
                                prev->next = process->next;
-                       finished = g_slist_prepend (finished, process);
+
+                       mono_os_sem_destroy (&process->exit_sem);
+                       g_free (process);
                } else {
                        prev = process;
                }
+               process = next;
        }
 
-       mono_memory_barrier ();
-
-       for (l = finished; l; l = l->next) {
-               /*
-                * All the entries in the finished list are unlinked from processes, and
-                * they have the 'finished' flag set, which means the sigchld handler is done
-                * accessing them.
-                */
-               process = (Process *)l->data;
-               mono_os_sem_destroy (&process->exit_sem);
-               g_free (process);
-       }
-       g_slist_free (finished);
-
        mono_os_mutex_unlock (&processes_mutex);
 
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s done", __func__);
@@ -843,13 +822,15 @@ mono_w32process_init (void)
        mono_w32handle_register_capabilities (MONO_W32HANDLE_PROCESS,
                (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SPECIAL_WAIT));
 
+       current_pid = getpid ();
+
        memset (&process_handle, 0, sizeof (process_handle));
-       process_handle.pid = wapi_getpid ();
+       process_handle.pid = current_pid;
        process_set_defaults (&process_handle);
        process_set_name (&process_handle);
 
        current_process = mono_w32handle_new (MONO_W32HANDLE_PROCESS, &process_handle);
-       g_assert (current_process);
+       g_assert (current_process != INVALID_HANDLE_VALUE);
 
        mono_os_mutex_init (&processes_mutex);
 }
@@ -860,31 +841,6 @@ mono_w32process_cleanup (void)
        g_free (cli_launcher);
 }
 
-/* Check if a pid is valid - i.e. if a process exists with this pid. */
-static gboolean
-is_pid_valid (pid_t pid)
-{
-       gboolean result = FALSE;
-
-#if defined(HOST_WATCHOS)
-       result = TRUE; // TODO: Rewrite using sysctl
-#elif defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__FreeBSD__)
-       if (((kill(pid, 0) == 0) || (errno == EPERM)) && pid != 0)
-               result = TRUE;
-#elif defined(__HAIKU__)
-       team_info teamInfo;
-       if (get_team_info ((team_id)pid, &teamInfo) == B_OK)
-               result = TRUE;
-#else
-       char *dir = g_strdup_printf ("/proc/%d", pid);
-       if (!access (dir, F_OK))
-               result = TRUE;
-       g_free (dir);
-#endif
-
-       return result;
-}
-
 static int
 len16 (const gunichar2 *str)
 {
@@ -935,14 +891,9 @@ mono_w32process_get_pid (gpointer handle)
        MonoW32HandleProcess *process_handle;
        gboolean res;
 
-       if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) {
-               /* This is a pseudo handle */
-               return WAPI_HANDLE_TO_PID (handle);
-       }
-
        res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
        if (!res) {
-               SetLastError (ERROR_INVALID_HANDLE);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
                return 0;
        }
 
@@ -966,8 +917,6 @@ get_process_foreach_callback (gpointer handle, gpointer handle_specific, gpointe
        if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_PROCESS)
                return FALSE;
 
-       g_assert (!WAPI_IS_PSEUDO_PROCESS_HANDLE (handle));
-
        process_handle = (MonoW32HandleProcess*) handle_specific;
 
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: looking at process %d", __func__, process_handle->pid);
@@ -984,8 +933,7 @@ get_process_foreach_callback (gpointer handle, gpointer handle_specific, gpointe
        if (mono_w32handle_issignalled (handle))
                return FALSE;
 
-       mono_w32handle_ref (handle);
-       foreach_data->handle = handle;
+       foreach_data->handle = mono_w32handle_duplicate (handle);
        return TRUE;
 }
 
@@ -1006,14 +954,28 @@ ves_icall_System_Diagnostics_Process_GetProcess_internal (guint32 pid)
                return handle;
        }
 
-       if (is_pid_valid (pid)) {
-               /* Return a pseudo handle for processes we don't have handles for */
-               return WAPI_PID_TO_HANDLE (pid);
+       if (process_is_alive (pid)) {
+               /* non-child process */
+               MonoW32HandleProcess process_handle;
+
+               memset (&process_handle, 0, sizeof (process_handle));
+               process_handle.pid = pid;
+               process_handle.pname = mono_w32process_get_name (pid);
+
+               handle = mono_w32handle_new (MONO_W32HANDLE_PROCESS, &process_handle);
+               if (handle == INVALID_HANDLE_VALUE) {
+                       g_warning ("%s: error creating process handle", __func__);
+
+                       mono_w32error_set_last (ERROR_OUTOFMEMORY);
+                       return NULL;
+               }
+
+               return handle;
        }
 
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find pid %d", __func__, pid);
 
-       SetLastError (ERROR_PROC_NOT_FOUND);
+       mono_w32error_set_last (ERROR_PROC_NOT_FOUND);
        return NULL;
 }
 
@@ -1058,7 +1020,7 @@ match_procname_to_modulename (char *procname, char *modulename)
        g_free (pname);
        g_free (mname);
 
-       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: result is %d", __func__, result);
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: result is %" G_GINT32_FORMAT, __func__, result);
        return result;
 }
 
@@ -1086,20 +1048,15 @@ mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 si
        if (size < sizeof(gpointer))
                return FALSE;
 
-       if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
-               pid = WAPI_HANDLE_TO_PID (process);
-               pname = mono_w32process_get_name (pid);
-       } else {
-               res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
-               if (!res) {
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process);
-                       return FALSE;
-               }
-
-               pid = process_handle->pid;
-               pname = g_strdup (process_handle->pname);
+       res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
+       if (!res) {
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process);
+               return FALSE;
        }
 
+       pid = process_handle->pid;
+       pname = g_strdup (process_handle->pname);
+
        if (!pname) {
                modules[0] = NULL;
                *needed = sizeof(gpointer);
@@ -1181,10 +1138,10 @@ mono_w32process_module_get_filename (gpointer process, gpointer module, gunichar
        bytes += 2;
 
        if (size < bytes) {
-               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %d smaller than needed (%ld); truncating", __func__, size, bytes);
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %" G_GUINT32_FORMAT " smaller than needed (%zd); truncating", __func__, size, bytes);
                memcpy (basename, proc_path, size);
        } else {
-               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %d larger than needed (%ld)", __func__, size, bytes);
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %" G_GUINT32_FORMAT " larger than needed (%zd)", __func__, size, bytes);
                memcpy (basename, proc_path, bytes);
        }
 
@@ -1207,31 +1164,26 @@ mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *b
        char *pname = NULL;
        gboolean res;
 
-       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Getting module base name, process handle %p module %p",
-                  __func__, process, module);
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Getting module base name, process handle %p module %p basename %p size %" G_GUINT32_FORMAT,
+                  __func__, process, module, basename, size);
 
        size = size * sizeof (gunichar2); /* adjust for unicode characters */
 
        if (basename == NULL || size == 0)
                return 0;
 
-       if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
-               /* This is a pseudo handle */
-               pid = (pid_t)WAPI_HANDLE_TO_PID (process);
-               pname = mono_w32process_get_name (pid);
-       } else {
-               res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
-               if (!res) {
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process);
-                       return 0;
-               }
-
-               pid = process_handle->pid;
-               pname = g_strdup (process_handle->pname);
+       res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
+       if (!res) {
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process);
+               return 0;
        }
 
+       pid = process_handle->pid;
+       pname = g_strdup (process_handle->pname);
+
        mods = mono_w32process_get_modules (pid);
-       if (!mods) {
+       if (!mods && module != NULL) {
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't get modules %p", __func__, process);
                g_free (pname);
                return 0;
        }
@@ -1252,11 +1204,14 @@ mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *b
        }
 
        if (procname_ext == NULL) {
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find procname_ext from procmods %p", __func__, process);
                /* If it's *still* null, we might have hit the
                 * case where reading /proc/$pid/maps gives an
                 * empty file for this user.
                 */
                procname_ext = mono_w32process_get_name (pid);
+               if (!procname_ext)
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find procname_ext from proc_get_name %p pid %d", __func__, process, pid);
        }
 
        g_slist_free (mods);
@@ -1268,6 +1223,7 @@ mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *b
 
                procname = mono_unicode_from_external (procname_ext, &bytes);
                if (procname == NULL) {
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't get procname %p", __func__, process);
                        /* bugger */
                        g_free (procname_ext);
                        return 0;
@@ -1279,11 +1235,11 @@ mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *b
                bytes += 2;
 
                if (size < bytes) {
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %d smaller than needed (%ld); truncating", __func__, size, bytes);
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %" G_GUINT32_FORMAT " smaller than needed (%zd); truncating", __func__, size, bytes);
 
                        memcpy (basename, procname, size);
                } else {
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %d larger than needed (%ld)",
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Size %" G_GUINT32_FORMAT " larger than needed (%zd)",
                                   __func__, size, bytes);
 
                        memcpy (basename, procname, bytes);
@@ -1295,6 +1251,7 @@ mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *b
                return len;
        }
 
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find procname_ext %p", __func__, process);
        return 0;
 }
 
@@ -1315,20 +1272,15 @@ mono_w32process_module_get_information (gpointer process, gpointer module, MODUL
        if (modinfo == NULL || size < sizeof (MODULEINFO))
                return FALSE;
 
-       if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
-               pid = (pid_t)WAPI_HANDLE_TO_PID (process);
-               pname = mono_w32process_get_name (pid);
-       } else {
-               res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
-               if (!res) {
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process);
-                       return FALSE;
-               }
-
-               pid = process_handle->pid;
-               pname = g_strdup (process_handle->pname);
+       res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
+       if (!res) {
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, process);
+               return FALSE;
        }
 
+       pid = process_handle->pid;
+       pname = g_strdup (process_handle->pname);
+
        mods = mono_w32process_get_modules (pid);
        if (!mods) {
                g_free (pname);
@@ -1375,6 +1327,39 @@ switch_dir_separators (char *path)
 #if HAVE_SIGACTION
 
 MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, siginfo_t *info, void *context))
+{
+       /*
+        * Don't want to do any complicated processing here so just wake up the finalizer thread which will call
+        * mono_w32process_signal_finished ().
+        */
+       int old_errno = errno;
+
+       mono_gc_finalize_notify ();
+
+       errno = old_errno;
+}
+
+static void
+process_add_sigchld_handler (void)
+{
+       struct sigaction sa;
+
+       sa.sa_sigaction = mono_sigchld_signal_handler;
+       sigemptyset (&sa.sa_mask);
+       sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO | SA_RESTART;
+       g_assert (sigaction (SIGCHLD, &sa, NULL) != -1);
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "Added SIGCHLD handler");
+}
+
+#endif
+
+/*
+ * mono_w32process_signal_finished:
+ *
+ *   Signal the exit semaphore for processes which have finished.
+ */
+void
+mono_w32process_signal_finished (void)
 {
        int status;
        int pid;
@@ -1388,9 +1373,8 @@ MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, sigi
                if (pid <= 0)
                        break;
 
-               /*
-                * This can run concurrently with the code in the rest of this module.
-                */
+               mono_os_mutex_lock (&processes_mutex);
+
                for (process = processes; process; process = process->next) {
                        if (process->pid != pid)
                                continue;
@@ -1400,28 +1384,13 @@ MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, sigi
                        process->signalled = TRUE;
                        process->status = status;
                        mono_os_sem_post (&process->exit_sem);
-                       mono_memory_barrier ();
-                       /* Mark this as freeable, the pointer becomes invalid afterwards */
-                       process->freeable = TRUE;
                        break;
                }
-       } while (1);
-}
 
-static void
-process_add_sigchld_handler (void)
-{
-       struct sigaction sa;
-
-       sa.sa_sigaction = mono_sigchld_signal_handler;
-       sigemptyset (&sa.sa_mask);
-       sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
-       g_assert (sigaction (SIGCHLD, &sa, NULL) != -1);
-       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "Added SIGCHLD handler");
+               mono_os_mutex_unlock (&processes_mutex);
+       } while (1);
 }
 
-#endif
-
 static gboolean
 is_readable_or_executable (const char *prog)
 {
@@ -1632,7 +1601,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline,
                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL",
                                   __func__);
 
-                       SetLastError (ERROR_PATH_NOT_FOUND);
+                       mono_w32error_set_last (ERROR_PATH_NOT_FOUND);
                        goto free_strings;
                }
 
@@ -1644,7 +1613,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline,
                if (args == NULL) {
                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
 
-                       SetLastError (ERROR_PATH_NOT_FOUND);
+                       mono_w32error_set_last (ERROR_PATH_NOT_FOUND);
                        goto free_strings;
                }
        }
@@ -1654,7 +1623,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline,
                if (dir == NULL) {
                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
 
-                       SetLastError (ERROR_PATH_NOT_FOUND);
+                       mono_w32error_set_last (ERROR_PATH_NOT_FOUND);
                        goto free_strings;
                }
 
@@ -1685,7 +1654,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline,
                                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s",
                                           __func__, prog);
                                g_free (unquoted);
-                               SetLastError (ERROR_FILE_NOT_FOUND);
+                               mono_w32error_set_last (ERROR_FILE_NOT_FOUND);
                                goto free_strings;
                        }
                } else {
@@ -1702,7 +1671,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline,
                                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s",
                                           __func__, prog);
                                g_free (unquoted);
-                               SetLastError (ERROR_FILE_NOT_FOUND);
+                               mono_w32error_set_last (ERROR_FILE_NOT_FOUND);
                                goto free_strings;
                        }
                }
@@ -1766,7 +1735,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline,
                        /* Give up */
                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find what to exec", __func__);
 
-                       SetLastError (ERROR_PATH_NOT_FOUND);
+                       mono_w32error_set_last (ERROR_PATH_NOT_FOUND);
                        goto free_strings;
                }
 
@@ -1793,7 +1762,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline,
                                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s",
                                           __func__, token);
                                g_free (token);
-                               SetLastError (ERROR_FILE_NOT_FOUND);
+                               mono_w32error_set_last (ERROR_FILE_NOT_FOUND);
                                goto free_strings;
                        }
                } else {
@@ -1820,7 +1789,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline,
                                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Couldn't find executable %s", __func__, token);
 
                                        g_free (token);
-                                       SetLastError (ERROR_FILE_NOT_FOUND);
+                                       mono_w32error_set_last (ERROR_FILE_NOT_FOUND);
                                        goto free_strings;
                                }
                        }
@@ -1859,7 +1828,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline,
        } else {
                if (!is_executable (prog)) {
                        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Executable permisson not set on %s", __func__, prog);
-                       SetLastError (ERROR_ACCESS_DENIED);
+                       mono_w32error_set_last (ERROR_ACCESS_DENIED);
                        goto free_strings;
                }
        }
@@ -1887,9 +1856,9 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline,
                out_fd = GPOINTER_TO_UINT (startup_handles->output);
                err_fd = GPOINTER_TO_UINT (startup_handles->error);
        } else {
-               in_fd = GPOINTER_TO_UINT (GetStdHandle (STD_INPUT_HANDLE));
-               out_fd = GPOINTER_TO_UINT (GetStdHandle (STD_OUTPUT_HANDLE));
-               err_fd = GPOINTER_TO_UINT (GetStdHandle (STD_ERROR_HANDLE));
+               in_fd = GPOINTER_TO_UINT (mono_w32file_get_console_input ());
+               out_fd = GPOINTER_TO_UINT (mono_w32file_get_console_output ());
+               err_fd = GPOINTER_TO_UINT (mono_w32file_get_console_error ());
        }
 
        /*
@@ -1955,7 +1924,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline,
 
        switch (pid = fork ()) {
        case -1: /* Error */ {
-               SetLastError (ERROR_OUTOFMEMORY);
+               mono_w32error_set_last (ERROR_OUTOFMEMORY);
                ret = FALSE;
                break;
        }
@@ -1976,17 +1945,17 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline,
                dup2 (err_fd, 2);
 
                /* Close all file descriptors */
-               for (i = mono_w32handle_fd_reserve - 1; i > 2; i--)
+               for (i = eg_getdtablesize() - 1; i > 2; i--)
                        close (i);
 
 #ifdef DEBUG_ENABLED
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: exec()ing [%s] in dir [%s]", __func__, cmd,
                           dir == NULL?".":dir);
                for (i = 0; argv[i] != NULL; i++)
-                       g_message ("arg %d: [%s]", i, argv[i]);
+                       g_message ("arg %" G_GUINT32_FORMAT ": [%s]", i, argv[i]);
 
                for (i = 0; env_strings[i] != NULL; i++)
-                       g_message ("env %d: [%s]", i, env_strings[i]);
+                       g_message ("env %" G_GUINT32_FORMAT ": [%s]", i, env_strings[i]);
 #endif
 
                /* set cwd */
@@ -2008,6 +1977,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline,
 
                memset (&process_handle, 0, sizeof (process_handle));
                process_handle.pid = pid;
+               process_handle.child = TRUE;
                process_handle.pname = g_strdup (prog);
                process_set_defaults (&process_handle);
 
@@ -2026,15 +1996,14 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline,
                        mono_os_sem_destroy (&process->exit_sem);
                        g_free (process);
 
-                       SetLastError (ERROR_OUTOFMEMORY);
+                       mono_w32error_set_last (ERROR_OUTOFMEMORY);
                        ret = FALSE;
                        break;
                }
 
                /* Keep the process handle artificially alive until the process
                 * exits so that the information in the handle isn't lost. */
-               mono_w32handle_ref (handle);
-               process->handle = handle;
+               process->handle = mono_w32handle_duplicate (handle);
 
                mono_os_mutex_lock (&processes_mutex);
                process->next = processes;
@@ -2085,7 +2054,7 @@ free_strings:
 
        return ret;
 #else
-       SetLastError (ERROR_NOT_SUPPORTED);
+       mono_w32error_set_last (ERROR_NOT_SUPPORTED);
        return FALSE;
 #endif // defined (HAVE_FORK) && defined (HAVE_EXECVE)
 }
@@ -2117,14 +2086,14 @@ ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoW32ProcessStar
         */
        args = utf16_concat (utf16_quote, lpFile, utf16_quote, lpParameters == NULL ? NULL : utf16_space, lpParameters, NULL);
        if (args == NULL) {
-               SetLastError (ERROR_INVALID_DATA);
+               mono_w32error_set_last (ERROR_INVALID_DATA);
                ret = FALSE;
                goto done;
        }
        ret = process_create (NULL, args, lpDirectory, NULL, process_info);
        g_free (args);
 
-       if (!ret && GetLastError () == ERROR_OUTOFMEMORY)
+       if (!ret && mono_w32error_get_last () == ERROR_OUTOFMEMORY)
                goto done;
 
        if (!ret) {
@@ -2136,7 +2105,7 @@ ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoW32ProcessStar
                        goto done;
                }
 
-#ifdef PLATFORM_MACOSX
+#ifdef HOST_DARWIN
                handler = g_strdup ("/usr/bin/open");
 #else
                /*
@@ -2174,26 +2143,26 @@ ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoW32ProcessStar
                args = utf16_concat (handler_utf16, utf16_space, utf16_quote, lpFile, utf16_quote,
                        lpParameters == NULL ? NULL : utf16_space, lpParameters, NULL);
                if (args == NULL) {
-                       SetLastError (ERROR_INVALID_DATA);
+                       mono_w32error_set_last (ERROR_INVALID_DATA);
                        ret = FALSE;
                        goto done;
                }
                ret = process_create (NULL, args, lpDirectory, NULL, process_info);
                g_free (args);
                if (!ret) {
-                       if (GetLastError () != ERROR_OUTOFMEMORY)
-                               SetLastError (ERROR_INVALID_DATA);
+                       if (mono_w32error_get_last () != ERROR_OUTOFMEMORY)
+                               mono_w32error_set_last (ERROR_INVALID_DATA);
                        ret = FALSE;
                        goto done;
                }
                /* Shell exec should not return a process handle when it spawned a GUI thing, like a browser. */
-               CloseHandle (process_info->process_handle);
+               mono_w32handle_close (process_info->process_handle);
                process_info->process_handle = NULL;
        }
 
 done:
        if (ret == FALSE) {
-               process_info->pid = -GetLastError ();
+               process_info->pid = -mono_w32error_get_last ();
        } else {
                process_info->thread_handle = NULL;
 #if !defined(MONO_CROSS_COMPILE)
@@ -2289,7 +2258,7 @@ ves_icall_System_Diagnostics_Process_CreateProcess_internal (MonoW32ProcessStart
                g_free (shell_path);
 
        if (!ret)
-               process_info->pid = -GetLastError ();
+               process_info->pid = -mono_w32error_get_last ();
 
        return ret;
 }
@@ -2334,7 +2303,6 @@ mono_w32process_set_cli_launcher (gchar *path)
 gpointer
 ves_icall_Microsoft_Win32_NativeMethods_GetCurrentProcess (void)
 {
-       mono_w32handle_ref (current_process);
        return current_process;
 }
 
@@ -2342,32 +2310,18 @@ MonoBoolean
 ves_icall_Microsoft_Win32_NativeMethods_GetExitCodeProcess (gpointer handle, gint32 *exitcode)
 {
        MonoW32HandleProcess *process_handle;
-       guint32 pid;
        gboolean res;
 
        if (!exitcode)
                return FALSE;
 
-       if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) {
-               pid = WAPI_HANDLE_TO_PID (handle);
-               /* This is a pseudo handle, so we don't know what the exit
-                * code was, but we can check whether it's alive or not */
-               if (is_pid_valid (pid)) {
-                       *exitcode = STILL_ACTIVE;
-                       return TRUE;
-               } else {
-                       *exitcode = -1;
-                       return TRUE;
-               }
-       }
-
        res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
        if (!res) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle);
                return FALSE;
        }
 
-       if (process_handle->pid == wapi_getpid ()) {
+       if (process_handle->pid == current_pid) {
                *exitcode = STILL_ACTIVE;
                return TRUE;
        }
@@ -2385,9 +2339,7 @@ ves_icall_Microsoft_Win32_NativeMethods_GetExitCodeProcess (gpointer handle, gin
 MonoBoolean
 ves_icall_Microsoft_Win32_NativeMethods_CloseProcess (gpointer handle)
 {
-       if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle))
-               return TRUE;
-       return CloseHandle (handle);
+       return mono_w32handle_close (handle);
 }
 
 MonoBoolean
@@ -2397,32 +2349,26 @@ ves_icall_Microsoft_Win32_NativeMethods_TerminateProcess (gpointer handle, gint3
        MonoW32HandleProcess *process_handle;
        int ret;
        pid_t pid;
+       gboolean res;
 
-       if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) {
-               /* This is a pseudo handle */
-               pid = (pid_t)WAPI_HANDLE_TO_PID (handle);
-       } else {
-               gboolean res;
-
-               res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
-               if (!res) {
-                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle);
-                       SetLastError (ERROR_INVALID_HANDLE);
-                       return FALSE;
-               }
-
-               pid = process_handle->pid;
+       res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
+       if (!res) {
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle);
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
+               return FALSE;
        }
 
+       pid = process_handle->pid;
+
        ret = kill (pid, exitcode == -1 ? SIGKILL : SIGTERM);
        if (ret == 0)
                return TRUE;
 
        switch (errno) {
-       case EINVAL: SetLastError (ERROR_INVALID_PARAMETER); break;
-       case EPERM:  SetLastError (ERROR_ACCESS_DENIED);     break;
-       case ESRCH:  SetLastError (ERROR_PROC_NOT_FOUND);    break;
-       default:     SetLastError (ERROR_GEN_FAILURE);       break;
+       case EINVAL: mono_w32error_set_last (ERROR_INVALID_PARAMETER); break;
+       case EPERM:  mono_w32error_set_last (ERROR_ACCESS_DENIED);     break;
+       case ESRCH:  mono_w32error_set_last (ERROR_PROC_NOT_FOUND);    break;
+       default:     mono_w32error_set_last (ERROR_GEN_FAILURE);       break;
        }
 
        return FALSE;
@@ -2440,15 +2386,15 @@ ves_icall_Microsoft_Win32_NativeMethods_GetProcessWorkingSetSize (gpointer handl
        if (!min || !max)
                return FALSE;
 
-       if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle))
-               return FALSE;
-
        res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
        if (!res) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle);
                return FALSE;
        }
 
+       if (!process_handle->child)
+               return FALSE;
+
        *min = process_handle->min_working_set;
        *max = process_handle->max_working_set;
        return TRUE;
@@ -2460,15 +2406,15 @@ ves_icall_Microsoft_Win32_NativeMethods_SetProcessWorkingSetSize (gpointer handl
        MonoW32HandleProcess *process_handle;
        gboolean res;
 
-       if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle))
-               return FALSE;
-
        res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
        if (!res) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle);
                return FALSE;
        }
 
+       if (!process_handle->child)
+               return FALSE;
+
        process_handle->min_working_set = min;
        process_handle->max_working_set = max;
        return TRUE;
@@ -2481,35 +2427,29 @@ ves_icall_Microsoft_Win32_NativeMethods_GetPriorityClass (gpointer handle)
        MonoW32HandleProcess *process_handle;
        gint ret;
        pid_t pid;
+       gboolean res;
 
-       if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) {
-               /* This is a pseudo handle */
-               pid = (pid_t)WAPI_HANDLE_TO_PID (handle);
-       } else {
-               gboolean res;
-
-               res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
-               if (!res) {
-                       SetLastError (ERROR_INVALID_HANDLE);
-                       return 0;
-               }
-
-               pid = process_handle->pid;
+       res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
+       if (!res) {
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
+               return 0;
        }
 
+       pid = process_handle->pid;
+
        errno = 0;
        ret = getpriority (PRIO_PROCESS, pid);
        if (ret == -1 && errno != 0) {
                switch (errno) {
                case EPERM:
                case EACCES:
-                       SetLastError (ERROR_ACCESS_DENIED);
+                       mono_w32error_set_last (ERROR_ACCESS_DENIED);
                        break;
                case ESRCH:
-                       SetLastError (ERROR_PROC_NOT_FOUND);
+                       mono_w32error_set_last (ERROR_PROC_NOT_FOUND);
                        break;
                default:
-                       SetLastError (ERROR_GEN_FAILURE);
+                       mono_w32error_set_last (ERROR_GEN_FAILURE);
                }
                return 0;
        }
@@ -2529,7 +2469,7 @@ ves_icall_Microsoft_Win32_NativeMethods_GetPriorityClass (gpointer handle)
 
        return MONO_W32PROCESS_PRIORITY_CLASS_NORMAL;
 #else
-       SetLastError (ERROR_NOT_SUPPORTED);
+       mono_w32error_set_last (ERROR_NOT_SUPPORTED);
        return 0;
 #endif
 }
@@ -2542,22 +2482,16 @@ ves_icall_Microsoft_Win32_NativeMethods_SetPriorityClass (gpointer handle, gint3
        int ret;
        int prio;
        pid_t pid;
+       gboolean res;
 
-       if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) {
-               /* This is a pseudo handle */
-               pid = (pid_t)WAPI_HANDLE_TO_PID (handle);
-       } else {
-               gboolean res;
-
-               res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
-               if (!res) {
-                       SetLastError (ERROR_INVALID_HANDLE);
-                       return FALSE;
-               }
-
-               pid = process_handle->pid;
+       res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
+       if (!res) {
+               mono_w32error_set_last (ERROR_INVALID_HANDLE);
+               return FALSE;
        }
 
+       pid = process_handle->pid;
+
        switch (priorityClass) {
        case MONO_W32PROCESS_PRIORITY_CLASS_IDLE:
                prio = 19;
@@ -2578,7 +2512,7 @@ ves_icall_Microsoft_Win32_NativeMethods_SetPriorityClass (gpointer handle, gint3
                prio = -20;
                break;
        default:
-               SetLastError (ERROR_INVALID_PARAMETER);
+               mono_w32error_set_last (ERROR_INVALID_PARAMETER);
                return FALSE;
        }
 
@@ -2587,19 +2521,19 @@ ves_icall_Microsoft_Win32_NativeMethods_SetPriorityClass (gpointer handle, gint3
                switch (errno) {
                case EPERM:
                case EACCES:
-                       SetLastError (ERROR_ACCESS_DENIED);
+                       mono_w32error_set_last (ERROR_ACCESS_DENIED);
                        break;
                case ESRCH:
-                       SetLastError (ERROR_PROC_NOT_FOUND);
+                       mono_w32error_set_last (ERROR_PROC_NOT_FOUND);
                        break;
                default:
-                       SetLastError (ERROR_GEN_FAILURE);
+                       mono_w32error_set_last (ERROR_GEN_FAILURE);
                }
        }
 
        return ret == 0;
 #else
-       SetLastError (ERROR_NOT_SUPPORTED);
+       mono_w32error_set_last (ERROR_NOT_SUPPORTED);
        return FALSE;
 #endif
 }
@@ -2633,24 +2567,24 @@ ves_icall_Microsoft_Win32_NativeMethods_GetProcessTimes (gpointer handle, gint64
        memset (kernel_processtime, 0, sizeof (ProcessTime));
        memset (user_processtime, 0, sizeof (ProcessTime));
 
-       if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) {
+       res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
+       if (!res) {
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle);
+               return FALSE;
+       }
+
+       if (!process_handle->child) {
                gint64 start_ticks, user_ticks, kernel_ticks;
 
-               mono_process_get_times (GINT_TO_POINTER (WAPI_HANDLE_TO_PID (handle)),
+               mono_process_get_times (GINT_TO_POINTER (process_handle->pid),
                        &start_ticks, &user_ticks, &kernel_ticks);
 
                ticks_to_processtime (start_ticks, creation_processtime);
-               ticks_to_processtime (user_ticks, kernel_processtime);
-               ticks_to_processtime (kernel_ticks, user_processtime);
+               ticks_to_processtime (kernel_ticks, kernel_processtime);
+               ticks_to_processtime (user_ticks, user_processtime);
                return TRUE;
        }
 
-       res = mono_w32handle_lookup (handle, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
-       if (!res) {
-               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find process %p", __func__, handle);
-               return FALSE;
-       }
-
        ticks_to_processtime (process_handle->create_time, creation_processtime);
 
        /* A process handle is only signalled if the process has
@@ -2797,14 +2731,14 @@ find_pe_file_resources32 (gpointer file_map, guint32 map_size, guint32 res_id, g
        if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Bad dos signature 0x%x", __func__, dos_header->e_magic);
 
-               SetLastError (ERROR_INVALID_DATA);
+               mono_w32error_set_last (ERROR_INVALID_DATA);
                return(NULL);
        }
 
        if (map_size < sizeof(IMAGE_NT_HEADERS32) + GUINT32_FROM_LE (dos_header->e_lfanew)) {
-               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File is too small: %d", __func__, map_size);
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File is too small: %" G_GUINT32_FORMAT, __func__, map_size);
 
-               SetLastError (ERROR_BAD_LENGTH);
+               mono_w32error_set_last (ERROR_BAD_LENGTH);
                return(NULL);
        }
 
@@ -2812,7 +2746,7 @@ find_pe_file_resources32 (gpointer file_map, guint32 map_size, guint32 res_id, g
        if (nt_headers->Signature != IMAGE_NT_SIGNATURE) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Bad NT signature 0x%x", __func__, nt_headers->Signature);
 
-               SetLastError (ERROR_INVALID_DATA);
+               mono_w32error_set_last (ERROR_INVALID_DATA);
                return(NULL);
        }
 
@@ -2826,7 +2760,7 @@ find_pe_file_resources32 (gpointer file_map, guint32 map_size, guint32 res_id, g
        if (resource_rva == 0) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: No resources in file!", __func__);
 
-               SetLastError (ERROR_INVALID_DATA);
+               mono_w32error_set_last (ERROR_INVALID_DATA);
                return(NULL);
        }
 
@@ -2834,7 +2768,7 @@ find_pe_file_resources32 (gpointer file_map, guint32 map_size, guint32 res_id, g
        if (resource_dir == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find resource directory", __func__);
 
-               SetLastError (ERROR_INVALID_DATA);
+               mono_w32error_set_last (ERROR_INVALID_DATA);
                return(NULL);
        }
 
@@ -2869,14 +2803,14 @@ find_pe_file_resources64 (gpointer file_map, guint32 map_size, guint32 res_id, g
        if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Bad dos signature 0x%x", __func__, dos_header->e_magic);
 
-               SetLastError (ERROR_INVALID_DATA);
+               mono_w32error_set_last (ERROR_INVALID_DATA);
                return(NULL);
        }
 
        if (map_size < sizeof(IMAGE_NT_HEADERS64) + GUINT32_FROM_LE (dos_header->e_lfanew)) {
-               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File is too small: %d", __func__, map_size);
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File is too small: %" G_GUINT32_FORMAT, __func__, map_size);
 
-               SetLastError (ERROR_BAD_LENGTH);
+               mono_w32error_set_last (ERROR_BAD_LENGTH);
                return(NULL);
        }
 
@@ -2885,7 +2819,7 @@ find_pe_file_resources64 (gpointer file_map, guint32 map_size, guint32 res_id, g
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Bad NT signature 0x%x", __func__,
                           nt_headers->Signature);
 
-               SetLastError (ERROR_INVALID_DATA);
+               mono_w32error_set_last (ERROR_INVALID_DATA);
                return(NULL);
        }
 
@@ -2899,7 +2833,7 @@ find_pe_file_resources64 (gpointer file_map, guint32 map_size, guint32 res_id, g
        if (resource_rva == 0) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: No resources in file!", __func__);
 
-               SetLastError (ERROR_INVALID_DATA);
+               mono_w32error_set_last (ERROR_INVALID_DATA);
                return(NULL);
        }
 
@@ -2907,7 +2841,7 @@ find_pe_file_resources64 (gpointer file_map, guint32 map_size, guint32 res_id, g
        if (resource_dir == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Can't find resource directory", __func__);
 
-               SetLastError (ERROR_INVALID_DATA);
+               mono_w32error_set_last (ERROR_INVALID_DATA);
                return(NULL);
        }
 
@@ -2958,24 +2892,47 @@ map_pe_file (gunichar2 *filename, gint32 *map_size, void **handle)
        if (filename_ext == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unicode conversion returned NULL", __func__);
 
-               SetLastError (ERROR_INVALID_NAME);
+               mono_w32error_set_last (ERROR_INVALID_NAME);
                return(NULL);
        }
 
-       fd = _wapi_open (filename_ext, O_RDONLY, 0);
-       if (fd == -1) {
-               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error opening file %s: %s", __func__, filename_ext, strerror (errno));
+       fd = open (filename_ext, O_RDONLY, 0);
+       if (fd == -1 && (errno == ENOENT || errno == ENOTDIR) && IS_PORTABILITY_SET) {
+               gint saved_errno;
+               gchar *located_filename;
 
-               SetLastError (_wapi_get_win32_file_error (errno));
-               g_free (filename_ext);
+               saved_errno = errno;
 
-               return(NULL);
+               located_filename = mono_portability_find_file (filename_ext, TRUE);
+               if (!located_filename) {
+                       errno = saved_errno;
+
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error opening file %s (1): %s", __func__, filename_ext, strerror (errno));
+
+                       g_free (filename_ext);
+
+                       mono_w32error_set_last (mono_w32error_unix_to_win32 (errno));
+                       return NULL;
+               }
+
+               fd = open (located_filename, O_RDONLY, 0);
+               if (fd == -1) {
+                       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error opening file %s (2): %s", __func__, filename_ext, strerror (errno));
+
+                       g_free (filename_ext);
+                       g_free (located_filename);
+
+                       mono_w32error_set_last (mono_w32error_unix_to_win32 (errno));
+                       return NULL;
+               }
+
+               g_free (located_filename);
        }
 
        if (fstat (fd, &statbuf) == -1) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error stat()ing file %s: %s", __func__, filename_ext, strerror (errno));
 
-               SetLastError (_wapi_get_win32_file_error (errno));
+               mono_w32error_set_last (mono_w32error_unix_to_win32 (errno));
                g_free (filename_ext);
                close (fd);
                return(NULL);
@@ -2984,9 +2941,9 @@ map_pe_file (gunichar2 *filename, gint32 *map_size, void **handle)
 
        /* Check basic file size */
        if (statbuf.st_size < sizeof(IMAGE_DOS_HEADER)) {
-               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File %s is too small: %lld", __func__, filename_ext, statbuf.st_size);
+               mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: File %s is too small: %lld", __func__, filename_ext, (long long) statbuf.st_size);
 
-               SetLastError (ERROR_BAD_LENGTH);
+               mono_w32error_set_last (ERROR_BAD_LENGTH);
                g_free (filename_ext);
                close (fd);
                return(NULL);
@@ -2996,7 +2953,7 @@ map_pe_file (gunichar2 *filename, gint32 *map_size, void **handle)
        if (file_map == NULL) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Error mmap()int file %s: %s", __func__, filename_ext, strerror (errno));
 
-               SetLastError (_wapi_get_win32_file_error (errno));
+               mono_w32error_set_last (mono_w32error_unix_to_win32 (errno));
                g_free (filename_ext);
                close (fd);
                return(NULL);