#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>
#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>
#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
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,
} 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 pid;
+ gboolean child;
guint32 exitstatus;
gpointer main_thread;
guint64 create_time;
size_t min_working_set;
size_t max_working_set;
gboolean exited;
- MonoProcess *mono_process;
+ Process *process;
} MonoW32HandleProcess;
/*
* 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 pid_t current_pid;
static gpointer current_process;
static const gunichar2 utf16_space_bytes [2] = { 0x20, 0 };
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(PLATFORM_MACOSX) || 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)
{
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,
- * 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);
if (alerted)
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) {
- pid_t res;
-
- 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;
- }
+ 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;
+ }
- /* 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);
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): PID: %d", __func__, handle, timeout, pid);
+ if (!process_handle->child) {
mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): waiting on non-child process", __func__, handle, timeout);
- 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);
+ 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);
+
+ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s (%p, %u): non-child process is not alive anymore (2)", __func__, handle, timeout);
return MONO_W32HANDLE_WAIT_RET_SUCCESS_0;
}
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;
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;
}
/* 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
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__);
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;
}
}
*/
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;
}
}
* 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);
process_handle = (MonoW32HandleProcess *) data;
g_free (process_handle->pname);
process_handle->pname = NULL;
- if (process_handle->mono_process)
- InterlockedDecrement (&process_handle->mono_process->handle_count);
+ if (process_handle->process)
+ InterlockedDecrement (&process_handle->process->handle_count);
processes_cleanup ();
}
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);
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)
{
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;
}
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);
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;
}
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);
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) {
g_free (pname);
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);
{
int status;
int pid;
- MonoProcess *p;
+ Process *process;
do {
do {
/*
* 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);
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);
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;
}
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;
}
}
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;
}
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 {
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;
}
}
/* 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;
}
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 {
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 {
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;
}
}
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 ());
}
/*
switch (pid = fork ()) {
case -1: /* Error */ {
- SetLastError (ERROR_OUTOFMEMORY);
+ mono_w32error_set_last (ERROR_OUTOFMEMORY);
ret = FALSE;
break;
}
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);
- /* 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);
+ 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);
- 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) {
return ret;
#else
- SetLastError (ERROR_NOT_SUPPORTED);
+ mono_w32error_set_last (ERROR_NOT_SUPPORTED);
return FALSE;
#endif // defined (HAVE_FORK) && defined (HAVE_EXECVE)
}
*/
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) {
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)
g_free (shell_path);
if (!ret)
- process_info->pid = -GetLastError ();
+ process_info->pid = -mono_w32error_get_last ();
return ret;
}
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;
}
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
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;
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;
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;
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;
}
return MONO_W32PROCESS_PRIORITY_CLASS_NORMAL;
#else
- SetLastError (ERROR_NOT_SUPPORTED);
+ mono_w32error_set_last (ERROR_NOT_SUPPORTED);
return 0;
#endif
}
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;
prio = -20;
break;
default:
- SetLastError (ERROR_INVALID_PARAMETER);
+ mono_w32error_set_last (ERROR_INVALID_PARAMETER);
return FALSE;
}
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
}
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);
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
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);
- SetLastError (ERROR_BAD_LENGTH);
+ mono_w32error_set_last (ERROR_BAD_LENGTH);
return(NULL);
}
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);
}
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);
}
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);
}
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);
- SetLastError (ERROR_BAD_LENGTH);
+ mono_w32error_set_last (ERROR_BAD_LENGTH);
return(NULL);
}
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);
}
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);
}
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);
}
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);
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);
- SetLastError (ERROR_BAD_LENGTH);
+ mono_w32error_set_last (ERROR_BAD_LENGTH);
g_free (filename_ext);
close (fd);
return(NULL);
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);