[io-layer] Extract file (#4255)
[mono.git] / mono / metadata / w32process-unix.c
index 390614d2a520db83237e454dfecc64207d09821e..e81b50a1acfebfd7e4ec759ecb0068639626b606 100644 (file)
@@ -58,6 +58,7 @@
 #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 +69,7 @@
 #include <mono/utils/mono-time.h>
 #include <mono/utils/mono-mmap.h>
 #include <mono/utils/strenc.h>
+#include <mono/utils/mono-io-portability.h>
 
 #ifndef MAXPATHLEN
 #define MAXPATHLEN 242
@@ -136,38 +138,38 @@ typedef struct {
 } ProcessTime;
 
 /*
- * MonoProcess describes processes we create.
+ * 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).
  */
-typedef struct _MonoProcess MonoProcess;
-struct _MonoProcess {
+typedef struct _Process {
        pid_t pid; /* the pid of the process. This value is only valid until the process has exited. */
        MonoSemType exit_sem; /* this semaphore will be released when the process exits */
        int status; /* the exit status */
-       gint32 handle_count; /* the number of handles to this mono_process instance */
+       gint32 handle_count; /* the number of handles to this process instance */
        /* we keep a ref to the creating _WapiHandle_process handle until
         * the process has exited, so that the information there isn't lost.
         */
        gpointer handle;
        gboolean freeable;
-       MonoProcess *next;
-};
+       gboolean signalled;
+       struct _Process *next;
+} Process;
 
 /* MonoW32HandleProcess is a structure containing all the required information for process handling. */
 typedef struct {
-       pid_t id;
+       pid_t pid;
        guint32 exitstatus;
        gpointer main_thread;
        guint64 create_time;
        guint64 exit_time;
-       char *proc_name;
+       char *pname;
        size_t min_working_set;
        size_t max_working_set;
        gboolean exited;
-       MonoProcess *mono_process;
+       Process *process;
 } MonoW32HandleProcess;
 
 /*
@@ -549,7 +551,7 @@ static gchar *cli_launcher;
  * 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 MonoProcess *processes;
+static Process *processes;
 static mono_mutex_t processes_mutex;
 
 static gpointer current_process;
@@ -563,8 +565,8 @@ static void
 process_details (gpointer data)
 {
        MonoW32HandleProcess *process_handle = (MonoW32HandleProcess *) data;
-       g_print ("id: %d, exited: %s, exitstatus: %d",
-               process_handle->id, process_handle->exited ? "true" : "false", process_handle->exitstatus);
+       g_print ("pid: %d, exited: %s, exitstatus: %d",
+               process_handle->pid, process_handle->exited ? "true" : "false", process_handle->exitstatus);
 }
 
 static const gchar*
@@ -586,7 +588,7 @@ process_wait (gpointer handle, guint32 timeout, gboolean *alerted)
        pid_t pid G_GNUC_UNUSED, ret;
        int status;
        gint64 start, now;
-       MonoProcess *mp;
+       Process *process;
        gboolean res;
 
        /* FIXME: We can now easily wait on processes that aren't our own children,
@@ -610,14 +612,14 @@ process_wait (gpointer handle, guint32 timeout, gboolean *alerted)
                return MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
        }
 
-       pid = process_handle->id;
+       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. */
-       mp = process_handle->mono_process;
-       if (!mp) {
+       process = process_handle->process;
+       if (!process) {
                pid_t res;
 
                if (pid == mono_process_current_pid ()) {
@@ -653,16 +655,16 @@ process_wait (gpointer handle, guint32 timeout, gboolean *alerted)
                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)));
-                       ret = mono_os_sem_timedwait (&mp->exit_sem, (timeout - (now - start)), alerted ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE);
+                       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...",
                                __func__, handle, timeout);
-                       ret = mono_os_sem_wait (&mp->exit_sem, alerted ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE);
+                       ret = mono_os_sem_wait (&process->exit_sem, alerted ? MONO_SEM_FLAGS_ALERTABLE : MONO_SEM_FLAGS_NONE);
                }
 
                if (ret == MONO_SEM_TIMEDWAIT_RET_SUCCESS) {
                        /* Success, process has exited */
-                       mono_os_sem_post (&mp->exit_sem);
+                       mono_os_sem_post (&process->exit_sem);
                        break;
                }
 
@@ -687,7 +689,7 @@ process_wait (gpointer handle, guint32 timeout, gboolean *alerted)
        /* Process must have exited */
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): Waited successfully", __func__, handle, timeout);
 
-       status = mp->status;
+       status = process->status;
        if (WIFSIGNALED (status))
                process_handle->exitstatus = 128 + WTERMSIG (status);
        else
@@ -698,7 +700,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",
-                  __func__, handle, timeout, process_handle->id, process_handle->exitstatus);
+                  __func__, handle, timeout, process_handle->pid, process_handle->exitstatus);
 
        mono_w32handle_set_signal_state (handle, TRUE, TRUE);
 
@@ -709,11 +711,10 @@ static void
 processes_cleanup (void)
 {
        static gint32 cleaning_up;
-       MonoProcess *mp;
-       MonoProcess *prev = NULL;
+       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,16 +722,12 @@ processes_cleanup (void)
        if (InterlockedCompareExchange (&cleaning_up, 1, 0) != 0)
                return;
 
-       for (mp = processes; mp; mp = mp->next) {
-               if (mp->pid == 0 && mp->handle) {
+       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_os_mutex_lock (&processes_mutex);
-                       unref_handle = mp->handle;
-                       mp->handle = NULL;
-                       mono_os_mutex_unlock (&processes_mutex);
-                       if (unref_handle)
-                               mono_w32handle_unref (unref_handle);
+                       mono_w32handle_unref (process->handle);
+                       process->handle = NULL;
                }
        }
 
@@ -742,24 +739,20 @@ processes_cleanup (void)
         */
        mono_os_mutex_lock (&processes_mutex);
 
-       mp = processes;
-       while (mp) {
-               if (mp->handle_count == 0 && mp->freeable) {
+       for (process = processes; process; process = process->next) {
+               if (process->handle_count == 0 && process->freeable) {
                        /*
                         * Unlink the entry.
                         * This code can run parallel with the sigchld handler, but the
                         * modifications it makes are safe.
                         */
-                       if (mp == processes)
-                               processes = mp->next;
+                       if (process == processes)
+                               processes = process->next;
                        else
-                               prev->next = mp->next;
-                       finished = g_slist_prepend (finished, mp);
-
-                       mp = mp->next;
+                               prev->next = process->next;
+                       finished = g_slist_prepend (finished, process);
                } else {
-                       prev = mp;
-                       mp = mp->next;
+                       prev = process;
                }
        }
 
@@ -771,9 +764,9 @@ processes_cleanup (void)
                 * they have the 'finished' flag set, which means the sigchld handler is done
                 * accessing them.
                 */
-               mp = (MonoProcess *)l->data;
-               mono_os_sem_destroy (&mp->exit_sem);
-               g_free (mp);
+               process = (Process *)l->data;
+               mono_os_sem_destroy (&process->exit_sem);
+               g_free (process);
        }
        g_slist_free (finished);
 
@@ -792,10 +785,10 @@ process_close (gpointer handle, gpointer data)
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s", __func__);
 
        process_handle = (MonoW32HandleProcess *) data;
-       g_free (process_handle->proc_name);
-       process_handle->proc_name = NULL;
-       if (process_handle->mono_process)
-               InterlockedDecrement (&process_handle->mono_process->handle_count);
+       g_free (process_handle->pname);
+       process_handle->pname = NULL;
+       if (process_handle->process)
+               InterlockedDecrement (&process_handle->process->handle_count);
        processes_cleanup ();
 }
 
@@ -834,9 +827,9 @@ process_set_name (MonoW32HandleProcess *process_handle)
        if (utf8_progname) {
                slash = strrchr (utf8_progname, '/');
                if (slash)
-                       process_handle->proc_name = g_strdup (slash+1);
+                       process_handle->pname = g_strdup (slash+1);
                else
-                       process_handle->proc_name = g_strdup (utf8_progname);
+                       process_handle->pname = g_strdup (utf8_progname);
                g_free (utf8_progname);
        }
 }
@@ -852,7 +845,7 @@ mono_w32process_init (void)
                (MonoW32HandleCapability)(MONO_W32HANDLE_CAP_WAIT | MONO_W32HANDLE_CAP_SPECIAL_WAIT));
 
        memset (&process_handle, 0, sizeof (process_handle));
-       process_handle.id = wapi_getpid ();
+       process_handle.pid = wapi_getpid ();
        process_set_defaults (&process_handle);
        process_set_name (&process_handle);
 
@@ -954,7 +947,7 @@ mono_w32process_get_pid (gpointer handle)
                return 0;
        }
 
-       return process_handle->id;
+       return process_handle->pid;
 }
 
 typedef struct {
@@ -978,9 +971,9 @@ get_process_foreach_callback (gpointer handle, gpointer handle_specific, gpointe
 
        process_handle = (MonoW32HandleProcess*) handle_specific;
 
-       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: looking at process %d", __func__, process_handle->id);
+       mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: looking at process %d", __func__, process_handle->pid);
 
-       pid = process_handle->id;
+       pid = process_handle->pid;
        if (pid == 0)
                return FALSE;
 
@@ -1079,7 +1072,7 @@ mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 si
        guint32 count, avail = size / sizeof(gpointer);
        int i;
        pid_t pid;
-       char *proc_name = NULL;
+       char *pname = NULL;
        gboolean res;
 
        /* Store modules in an array of pointers (main module as
@@ -1096,7 +1089,7 @@ mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 si
 
        if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
                pid = WAPI_HANDLE_TO_PID (process);
-               proc_name = mono_w32process_get_name (pid);
+               pname = mono_w32process_get_name (pid);
        } else {
                res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
                if (!res) {
@@ -1104,11 +1097,11 @@ mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 si
                        return FALSE;
                }
 
-               pid = process_handle->id;
-               proc_name = g_strdup (process_handle->proc_name);
+               pid = process_handle->pid;
+               pname = g_strdup (process_handle->pname);
        }
 
-       if (!proc_name) {
+       if (!pname) {
                modules[0] = NULL;
                *needed = sizeof(gpointer);
                return TRUE;
@@ -1118,7 +1111,7 @@ mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 si
        if (!mods) {
                modules[0] = NULL;
                *needed = sizeof(gpointer);
-               g_free (proc_name);
+               g_free (pname);
                return TRUE;
        }
 
@@ -1139,7 +1132,7 @@ mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 si
                        module = (MonoW32ProcessModule *)mods_iter->data;
                        if (modules[0] != NULL)
                                modules[i] = module->address_start;
-                       else if (match_procname_to_modulename (proc_name, module->filename))
+                       else if (match_procname_to_modulename (pname, module->filename))
                                modules[0] = module->address_start;
                        else
                                modules[i + 1] = module->address_start;
@@ -1153,7 +1146,7 @@ mono_w32process_try_get_modules (gpointer process, gpointer *modules, guint32 si
        *needed = sizeof(gpointer) * (count + 1);
 
        g_slist_free (mods);
-       g_free (proc_name);
+       g_free (pname);
 
        return TRUE;
 }
@@ -1212,7 +1205,7 @@ mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *b
        gsize bytes;
        GSList *mods = NULL, *mods_iter;
        MonoW32ProcessModule *found_module;
-       char *proc_name = NULL;
+       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",
@@ -1226,7 +1219,7 @@ mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *b
        if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
                /* This is a pseudo handle */
                pid = (pid_t)WAPI_HANDLE_TO_PID (process);
-               proc_name = mono_w32process_get_name (pid);
+               pname = mono_w32process_get_name (pid);
        } else {
                res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
                if (!res) {
@@ -1234,13 +1227,13 @@ mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *b
                        return 0;
                }
 
-               pid = process_handle->id;
-               proc_name = g_strdup (process_handle->proc_name);
+               pid = process_handle->pid;
+               pname = g_strdup (process_handle->pname);
        }
 
        mods = mono_w32process_get_modules (pid);
        if (!mods) {
-               g_free (proc_name);
+               g_free (pname);
                return 0;
        }
 
@@ -1251,7 +1244,7 @@ mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *b
        for (mods_iter = mods; mods_iter; mods_iter = g_slist_next (mods_iter)) {
                found_module = (MonoW32ProcessModule *)mods_iter->data;
                if (procname_ext == NULL &&
-                       ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) ||
+                       ((module == NULL && match_procname_to_modulename (pname, found_module->filename)) ||
                         (module != NULL && found_module->address_start == module))) {
                        procname_ext = g_path_get_basename (found_module->filename);
                }
@@ -1268,7 +1261,7 @@ mono_w32process_module_get_name (gpointer process, gpointer module, gunichar2 *b
        }
 
        g_slist_free (mods);
-       g_free (proc_name);
+       g_free (pname);
 
        if (procname_ext) {
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Process name is [%s]", __func__,
@@ -1314,7 +1307,7 @@ mono_w32process_module_get_information (gpointer process, gpointer module, MODUL
        GSList *mods = NULL, *mods_iter;
        MonoW32ProcessModule *found_module;
        gboolean ret = FALSE;
-       char *proc_name = NULL;
+       char *pname = NULL;
        gboolean res;
 
        mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Getting module info, process handle %p module %p",
@@ -1325,7 +1318,7 @@ mono_w32process_module_get_information (gpointer process, gpointer module, MODUL
 
        if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) {
                pid = (pid_t)WAPI_HANDLE_TO_PID (process);
-               proc_name = mono_w32process_get_name (pid);
+               pname = mono_w32process_get_name (pid);
        } else {
                res = mono_w32handle_lookup (process, MONO_W32HANDLE_PROCESS, (gpointer*) &process_handle);
                if (!res) {
@@ -1333,13 +1326,13 @@ mono_w32process_module_get_information (gpointer process, gpointer module, MODUL
                        return FALSE;
                }
 
-               pid = process_handle->id;
-               proc_name = g_strdup (process_handle->proc_name);
+               pid = process_handle->pid;
+               pname = g_strdup (process_handle->pname);
        }
 
        mods = mono_w32process_get_modules (pid);
        if (!mods) {
-               g_free (proc_name);
+               g_free (pname);
                return FALSE;
        }
 
@@ -1350,7 +1343,7 @@ mono_w32process_module_get_information (gpointer process, gpointer module, MODUL
        for (mods_iter = mods; mods_iter; mods_iter = g_slist_next (mods_iter)) {
                        found_module = (MonoW32ProcessModule *)mods_iter->data;
                        if (ret == FALSE &&
-                               ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) ||
+                               ((module == NULL && match_procname_to_modulename (pname, found_module->filename)) ||
                                 (module != NULL && found_module->address_start == module))) {
                                modinfo->lpBaseOfDll = found_module->address_start;
                                modinfo->SizeOfImage = (gsize)(found_module->address_end) - (gsize)(found_module->address_start);
@@ -1362,7 +1355,7 @@ mono_w32process_module_get_information (gpointer process, gpointer module, MODUL
        }
 
        g_slist_free (mods);
-       g_free (proc_name);
+       g_free (pname);
 
        return ret;
 }
@@ -1386,7 +1379,7 @@ MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, sigi
 {
        int status;
        int pid;
-       MonoProcess *p;
+       Process *process;
 
        do {
                do {
@@ -1399,16 +1392,18 @@ MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, sigi
                /*
                 * This can run concurrently with the code in the rest of this module.
                 */
-               for (p = processes; p; p = p->next) {
-                       if (p->pid != pid)
+               for (process = processes; process; process = process->next) {
+                       if (process->pid != pid)
+                               continue;
+                       if (process->signalled)
                                continue;
 
-                       p->pid = 0; /* this pid doesn't exist anymore, clear it */
-                       p->status = status;
-                       mono_os_sem_post (&p->exit_sem);
+                       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 */
-                       p->freeable = TRUE;
+                       process->freeable = TRUE;
                        break;
                }
        } while (1);
@@ -1586,13 +1581,13 @@ leave:
 }
 
 static gboolean
-process_create (const gunichar2 *appname, const gunichar2 *cmdline, gpointer new_environ,
+process_create (const gunichar2 *appname, const gunichar2 *cmdline,
        const gunichar2 *cwd, StartupHandles *startup_handles, MonoW32ProcessInfo *process_info)
 {
 #if defined (HAVE_FORK) && defined (HAVE_EXECVE)
        char *cmd = NULL, *prog = NULL, *full_prog = NULL, *args = NULL, *args_after_prog = NULL;
        char *dir = NULL, **env_strings = NULL, **argv = NULL;
-       guint32 i, env_count = 0;
+       guint32 i;
        gboolean ret = FALSE;
        gpointer handle = NULL;
        GError *gerr = NULL;
@@ -1600,7 +1595,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, gpointer new
        pid_t pid = 0;
        int startup_pipe [2] = {-1, -1};
        int dummy;
-       MonoProcess *mono_process;
+       Process *process;
 
 #if HAVE_SIGACTION
        mono_lazy_initialize (&process_sig_chld_once, process_add_sigchld_handler);
@@ -1855,7 +1850,7 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, gpointer new
                        g_free (newapp);
 
                        if (newcmd) {
-                               ret = process_create (NULL, newcmd, new_environ, cwd, startup_handles, process_info);
+                               ret = process_create (NULL, newcmd, cwd, startup_handles, process_info);
 
                                g_free (newcmd);
 
@@ -1893,64 +1888,61 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, gpointer new
                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 ());
        }
 
-       /* new_environ is a block of NULL-terminated strings, which
-        * is itself NULL-terminated. Of course, passing an array of
-        * string pointers would have made things too easy :-(
+       /*
+        * process->env_variables is a an array of MonoString*
         *
         * If new_environ is not NULL it specifies the entire set of
         * environment variables in the new process.  Otherwise the
         * new process inherits the same environment.
         */
-       if (new_environ) {
-               gunichar2 *new_environp;
+       if (process_info->env_variables) {
+               gint i, str_length, var_length;
+               MonoString *var;
+               gunichar2 *str;
 
-               /* Count the number of strings */
-               for (new_environp = (gunichar2 *)new_environ; *new_environp; new_environp++) {
-                       env_count++;
-                       while (*new_environp)
-                               new_environp++;
-               }
+               /* +2: one for the process handle value, and the last one is NULL */
+               env_strings = g_new0 (gchar*, mono_array_length (process_info->env_variables) + 2);
 
-               /* +2: one for the process handle value, and the last
-                * one is NULL
-                */
-               env_strings = g_new0 (char *, env_count + 2);
+               str = NULL;
+               str_length = 0;
 
-               /* Copy each environ string into 'strings' turning it
-                * into utf8 (or the requested encoding) at the same
-                * time
-                */
-               env_count = 0;
-               for (new_environp = (gunichar2 *)new_environ; *new_environp; new_environp++) {
-                       env_strings[env_count] = mono_unicode_to_external (new_environp);
-                       env_count++;
-                       while (*new_environp) {
-                               new_environp++;
+               /* Copy each environ string into 'strings' turning it into utf8 (or the requested encoding) at the same time */
+               for (i = 0; i < mono_array_length (process_info->env_variables); ++i) {
+                       var = mono_array_get (process_info->env_variables, MonoString*, i);
+                       var_length = mono_string_length (var);
+
+                       /* str is a null-terminated copy of var */
+
+                       if (var_length + 1 > str_length) {
+                               str_length = var_length + 1;
+                               str = g_renew (gunichar2, str, str_length);
                        }
+
+                       memcpy (str, mono_string_chars (var), var_length * sizeof (gunichar2));
+                       str [var_length] = '\0';
+
+                       env_strings [i] = mono_unicode_to_external (str);
                }
+
+               g_free (str);
        } else {
+               guint32 env_count;
+
+               env_count = 0;
                for (i = 0; environ[i] != NULL; i++)
                        env_count++;
 
-               /* +2: one for the process handle value, and the last
-                * one is NULL
-                */
-               env_strings = g_new0 (char *, env_count + 2);
+               /* +2: one for the process handle value, and the last one is NULL */
+               env_strings = g_new0 (gchar*, env_count + 2);
 
-               /* Copy each environ string into 'strings' turning it
-                * into utf8 (or the requested encoding) at the same
-                * time
-                */
-               env_count = 0;
-               for (i = 0; environ[i] != NULL; i++) {
-                       env_strings[env_count] = g_strdup (environ[i]);
-                       env_count++;
-               }
+               /* Copy each environ string into 'strings' turning it into utf8 (or the requested encoding) at the same time */
+               for (i = 0; i < env_count; i++)
+                       env_strings [i] = g_strdup (environ[i]);
        }
 
        /* Create a pipe to make sure the child doesn't exit before
@@ -1962,10 +1954,6 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, gpointer new
                mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: new process startup not synchronized. We may not notice if the newly created process exits immediately.", __func__);
        }
 
-#if HAVE_SIGACTION
-       /* FIXME: block SIGCHLD */
-#endif
-
        switch (pid = fork ()) {
        case -1: /* Error */ {
                SetLastError (ERROR_OUTOFMEMORY);
@@ -2020,24 +2008,24 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, gpointer new
                MonoW32HandleProcess process_handle;
 
                memset (&process_handle, 0, sizeof (process_handle));
-               process_handle.id = pid;
-               process_handle.proc_name = g_strdup (prog);
+               process_handle.pid = pid;
+               process_handle.pname = g_strdup (prog);
                process_set_defaults (&process_handle);
 
-               /* Add our mono_process into the linked list of processes */
-               mono_process = (MonoProcess *) g_malloc0 (sizeof (MonoProcess));
-               mono_process->pid = pid;
-               mono_process->handle_count = 1;
-               mono_os_sem_init (&mono_process->exit_sem, 0);
+               /* Add our process into the linked list of processes */
+               process = (Process *) g_malloc0 (sizeof (Process));
+               process->pid = pid;
+               process->handle_count = 1;
+               mono_os_sem_init (&process->exit_sem, 0);
 
-               process_handle.mono_process = mono_process;
+               process_handle.process = process;
 
                handle = mono_w32handle_new (MONO_W32HANDLE_PROCESS, &process_handle);
                if (handle == INVALID_HANDLE_VALUE) {
                        g_warning ("%s: error creating process handle", __func__);
 
-                       mono_os_sem_destroy (&mono_process->exit_sem);
-                       g_free (mono_process);
+                       mono_os_sem_destroy (&process->exit_sem);
+                       g_free (process);
 
                        SetLastError (ERROR_OUTOFMEMORY);
                        ret = FALSE;
@@ -2047,11 +2035,12 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, gpointer new
                /* Keep the process handle artificially alive until the process
                 * exits so that the information in the handle isn't lost. */
                mono_w32handle_ref (handle);
-               mono_process->handle = handle;
+               process->handle = handle;
 
                mono_os_mutex_lock (&processes_mutex);
-               mono_process->next = processes;
-               processes = mono_process;
+               process->next = processes;
+               mono_memory_barrier ();
+               processes = process;
                mono_os_mutex_unlock (&processes_mutex);
 
                if (process_info != NULL) {
@@ -2067,10 +2056,6 @@ process_create (const gunichar2 *appname, const gunichar2 *cmdline, gpointer new
        }
        }
 
-#if HAVE_SIGACTION
-       /* FIXME: unblock SIGCHLD */
-#endif
-
        if (startup_pipe [1] != -1) {
                /* Write 1 byte, doesn't matter what */
                ssize_t _i G_GNUC_UNUSED = write (startup_pipe [1], startup_pipe, 1);
@@ -2137,7 +2122,7 @@ ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoW32ProcessStar
                ret = FALSE;
                goto done;
        }
-       ret = process_create (NULL, args, NULL, lpDirectory, NULL, process_info);
+       ret = process_create (NULL, args, lpDirectory, NULL, process_info);
        g_free (args);
 
        if (!ret && GetLastError () == ERROR_OUTOFMEMORY)
@@ -2194,7 +2179,7 @@ ves_icall_System_Diagnostics_Process_ShellExecuteEx_internal (MonoW32ProcessStar
                        ret = FALSE;
                        goto done;
                }
-               ret = process_create (NULL, args, NULL, lpDirectory, NULL, process_info);
+               ret = process_create (NULL, args, lpDirectory, NULL, process_info);
                g_free (args);
                if (!ret) {
                        if (GetLastError () != ERROR_OUTOFMEMORY)
@@ -2258,20 +2243,18 @@ process_get_complete_path (const gunichar2 *appname, gchar **completed)
 }
 
 static gboolean
-process_get_shell_arguments (MonoW32ProcessStartInfo *proc_start_info, gunichar2 **shell_path, MonoString **cmd)
+process_get_shell_arguments (MonoW32ProcessStartInfo *proc_start_info, gunichar2 **shell_path)
 {
-       gchar *spath = NULL;
+       gchar *complete_path = NULL;
 
        *shell_path = NULL;
-       *cmd = proc_start_info->arguments;
 
-       process_get_complete_path (mono_string_chars (proc_start_info->filename), &spath);
-       if (spath != NULL) {
-               *shell_path = g_utf8_to_utf16 (spath, -1, NULL, NULL, NULL);
-               g_free (spath);
+       if (process_get_complete_path (mono_string_chars (proc_start_info->filename), &complete_path)) {
+               *shell_path = g_utf8_to_utf16 (complete_path, -1, NULL, NULL, NULL);
+               g_free (complete_path);
        }
 
-       return (*shell_path != NULL) ? TRUE : FALSE;
+       return *shell_path != NULL;
 }
 
 MonoBoolean
@@ -2282,67 +2265,27 @@ ves_icall_System_Diagnostics_Process_CreateProcess_internal (MonoW32ProcessStart
        gunichar2 *dir;
        StartupHandles startup_handles;
        gunichar2 *shell_path = NULL;
-       gchar *env_vars = NULL;
-       MonoString *cmd = NULL;
+       gunichar2 *args = NULL;
 
        memset (&startup_handles, 0, sizeof (startup_handles));
        startup_handles.input = stdin_handle;
        startup_handles.output = stdout_handle;
        startup_handles.error = stderr_handle;
 
-       if (process_get_shell_arguments (proc_start_info, &shell_path, &cmd) == FALSE) {
+       if (!process_get_shell_arguments (proc_start_info, &shell_path)) {
                process_info->pid = -ERROR_FILE_NOT_FOUND;
                return FALSE;
        }
 
-       if (process_info->env_keys) {
-               gint i, len; 
-               MonoString *ms;
-               MonoString *key, *value;
-               gunichar2 *str, *ptr;
-               gunichar2 *equals16;
-
-               for (len = 0, i = 0; i < mono_array_length (process_info->env_keys); i++) {
-                       ms = mono_array_get (process_info->env_values, MonoString *, i);
-                       if (ms == NULL)
-                               continue;
-
-                       len += mono_string_length (ms) * sizeof (gunichar2);
-                       ms = mono_array_get (process_info->env_keys, MonoString *, i);
-                       len += mono_string_length (ms) * sizeof (gunichar2);
-                       len += 2 * sizeof (gunichar2);
-               }
-
-               equals16 = g_utf8_to_utf16 ("=", 1, NULL, NULL, NULL);
-               ptr = str = g_new0 (gunichar2, len + 1);
-               for (i = 0; i < mono_array_length (process_info->env_keys); i++) {
-                       value = mono_array_get (process_info->env_values, MonoString *, i);
-                       if (value == NULL)
-                               continue;
-
-                       key = mono_array_get (process_info->env_keys, MonoString *, i);
-                       memcpy (ptr, mono_string_chars (key), mono_string_length (key) * sizeof (gunichar2));
-                       ptr += mono_string_length (key);
-
-                       memcpy (ptr, equals16, sizeof (gunichar2));
-                       ptr++;
-
-                       memcpy (ptr, mono_string_chars (value), mono_string_length (value) * sizeof (gunichar2));
-                       ptr += mono_string_length (value);
-                       ptr++;
-               }
+       args = proc_start_info->arguments && mono_string_length (proc_start_info->arguments) > 0 ?
+                       mono_string_chars (proc_start_info->arguments): NULL;
 
-               g_free (equals16);
-               env_vars = (gchar *) str;
-       }
-       
        /* The default dir name is "".  Turn that into NULL to mean "current directory" */
        dir = proc_start_info->working_directory && mono_string_length (proc_start_info->working_directory) > 0 ?
                        mono_string_chars (proc_start_info->working_directory) : NULL;
 
-       ret = process_create (shell_path, cmd ? mono_string_chars (cmd): NULL, env_vars, dir, &startup_handles, process_info);
+       ret = process_create (shell_path, args, dir, &startup_handles, process_info);
 
-       g_free (env_vars);
        if (shell_path != NULL)
                g_free (shell_path);
 
@@ -2425,7 +2368,7 @@ ves_icall_Microsoft_Win32_NativeMethods_GetExitCodeProcess (gpointer handle, gin
                return FALSE;
        }
 
-       if (process_handle->id == wapi_getpid ()) {
+       if (process_handle->pid == wapi_getpid ()) {
                *exitcode = STILL_ACTIVE;
                return TRUE;
        }
@@ -2469,7 +2412,7 @@ ves_icall_Microsoft_Win32_NativeMethods_TerminateProcess (gpointer handle, gint3
                        return FALSE;
                }
 
-               pid = process_handle->id;
+               pid = process_handle->pid;
        }
 
        ret = kill (pid, exitcode == -1 ? SIGKILL : SIGTERM);
@@ -2552,7 +2495,7 @@ ves_icall_Microsoft_Win32_NativeMethods_GetPriorityClass (gpointer handle)
                        return 0;
                }
 
-               pid = process_handle->id;
+               pid = process_handle->pid;
        }
 
        errno = 0;
@@ -2613,7 +2556,7 @@ ves_icall_Microsoft_Win32_NativeMethods_SetPriorityClass (gpointer handle, gint3
                        return FALSE;
                }
 
-               pid = process_handle->id;
+               pid = process_handle->pid;
        }
 
        switch (priorityClass) {
@@ -2717,7 +2660,7 @@ ves_icall_Microsoft_Win32_NativeMethods_GetProcessTimes (gpointer handle, gint64
                ticks_to_processtime (process_handle->exit_time, exit_processtime);
 
 #ifdef HAVE_GETRUSAGE
-       if (process_handle->id == getpid ()) {
+       if (process_handle->pid == getpid ()) {
                struct rusage time_data;
                if (getrusage (RUSAGE_SELF, &time_data) == 0) {
                        ticks_to_processtime ((guint64)time_data.ru_utime.tv_sec * 10000000 + (guint64)time_data.ru_utime.tv_usec * 10, user_processtime);
@@ -3020,14 +2963,37 @@ map_pe_file (gunichar2 *filename, gint32 *map_size, void **handle)
                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);
+
+                       SetLastError (_wapi_get_win32_file_error (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);
+
+                       SetLastError (_wapi_get_win32_file_error (errno));
+                       return NULL;
+               }
+
+               g_free (located_filename);
        }
 
        if (fstat (fd, &statbuf) == -1) {