X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fio-layer%2Fprocesses.c;h=ce7aee14c884732d669200fc8bcbc3a2599d718b;hb=24748ce981a554c4a8f9529e5848a88c743a1901;hp=c65bf23813c0ce954166d7595113fdf40ca6a3e7;hpb=e003c4e8f9e5ffef89a7527595c94d7457abe1a6;p=mono.git diff --git a/mono/io-layer/processes.c b/mono/io-layer/processes.c index c65bf23813c..ce7aee14c88 100644 --- a/mono/io-layer/processes.c +++ b/mono/io-layer/processes.c @@ -19,20 +19,31 @@ #include #include #include +#ifdef HAVE_SIGNAL_H #include -#include +#endif #include -#include #include #ifdef HAVE_SYS_PARAM_H #include #endif #include +#ifdef HAVE_SYS_WAIT_H +#include +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif + #ifdef HAVE_SYS_MKDEV_H #include #endif +#ifdef HAVE_UTIME_H +#include +#endif + /* sys/resource.h (for rusage) is required when using osx 10.3 (but not 10.4) */ #ifdef __APPLE__ #include @@ -79,14 +90,15 @@ #include #include #include +#include /* The process' environment strings */ -#if defined(__APPLE__) && !defined (__arm__) +#if defined(__APPLE__) && !defined (__arm__) && !defined (__aarch64__) /* Apple defines this in crt_externs.h but doesn't provide that header for * arm-apple-darwin9. We'll manually define the symbol on Apple as it does * in fact exist on all implementations (so far) */ -gchar ***_NSGetEnviron(void); +char ***_NSGetEnviron(void); #define environ (*_NSGetEnviron()) #else extern char **environ; @@ -103,7 +115,7 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl static void process_close (gpointer handle, gpointer data); static gboolean is_pid_valid (pid_t pid); -#if !defined(__OpenBSD__) +#if !(defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__HAIKU__)) static FILE * open_process_map (int pid, const char *mode); #endif @@ -137,27 +149,29 @@ static void process_add_sigchld_handler (void); * signal handler) */ static struct MonoProcess *mono_processes = NULL; -static volatile gint32 mono_processes_read_lock = 0; static volatile gint32 mono_processes_cleaning_up = 0; static mono_mutex_t mono_processes_mutex; static void mono_processes_cleanup (void); -static mono_once_t process_current_once=MONO_ONCE_INIT; -static gpointer current_process=NULL; +static gpointer current_process; static char *cli_launcher; -static mono_once_t process_ops_once=MONO_ONCE_INIT; - -static void process_ops_init (void) +static WapiHandle_process * +lookup_process_handle (gpointer handle) { - _wapi_handle_register_capabilities (WAPI_HANDLE_PROCESS, - WAPI_HANDLE_CAP_WAIT | - WAPI_HANDLE_CAP_SPECIAL_WAIT); -} + WapiHandle_process *process_data; + gboolean ret; + ret = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS, + (gpointer *)&process_data); + if (!ret) + return NULL; + return process_data; +} /* Check if a pid is valid - i.e. if a process exists with this pid. */ -static gboolean is_pid_valid (pid_t pid) +static gboolean +is_pid_valid (pid_t pid) { gboolean result = FALSE; @@ -169,7 +183,7 @@ static gboolean is_pid_valid (pid_t pid) if (get_team_info ((team_id)pid, &teamInfo) == B_OK) result = TRUE; #else - gchar *dir = g_strdup_printf ("/proc/%d", pid); + char *dir = g_strdup_printf ("/proc/%d", pid); if (!access (dir, F_OK)) result = TRUE; g_free (dir); @@ -178,7 +192,8 @@ static gboolean is_pid_valid (pid_t pid) return result; } -static void process_set_defaults (struct _WapiHandle_process *process_handle) +static void +process_set_defaults (WapiHandle_process *process_handle) { /* These seem to be the defaults on w2k */ process_handle->min_working_set = 204800; @@ -233,42 +248,6 @@ utf16_concat (const gunichar2 *first, ...) return ret; } -#ifdef PLATFORM_MACOSX - -/* 0 = no detection; -1 = not 10.5 or higher; 1 = 10.5 or higher */ -static int osx_10_5_or_higher; - -static void -detect_osx_10_5_or_higher (void) -{ - struct utsname u; - char *p; - int v; - - if (uname (&u) != 0){ - osx_10_5_or_higher = 1; - return; - } - - p = u.release; - v = atoi (p); - - if (v < 9) - osx_10_5_or_higher = -1; - else - osx_10_5_or_higher = 1; -} - -static gboolean -is_macos_10_5_or_higher (void) -{ - if (osx_10_5_or_higher == 0) - detect_osx_10_5_or_higher (); - - return (osx_10_5_or_higher == 1); -} -#endif - static const gunichar2 utf16_space_bytes [2] = { 0x20, 0 }; static const gunichar2 *utf16_space = utf16_space_bytes; static const gunichar2 utf16_quote_bytes [2] = { 0x22, 0 }; @@ -279,7 +258,7 @@ static const gunichar2 *utf16_quote = utf16_quote_bytes; void print_utf16 (gunichar2 *str) { - gchar *res; + char *res; res = g_utf16_to_utf8 (str, -1, NULL, NULL, NULL); g_print ("%s\n", res); @@ -288,7 +267,8 @@ print_utf16 (gunichar2 *str) #endif /* Implemented as just a wrapper around CreateProcess () */ -gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) +gboolean +ShellExecuteEx (WapiShellExecuteInfo *sei) { gboolean ret; WapiProcessInformation process_info; @@ -299,13 +279,12 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) * that */ SetLastError (ERROR_INVALID_PARAMETER); - return (FALSE); + return FALSE; } - if (sei->lpFile == NULL) { + if (sei->lpFile == NULL) /* w2k returns TRUE for this, for some reason. */ - return (TRUE); - } + return TRUE; /* Put both executable and parameters into the second argument * to CreateProcess (), so it searches $PATH. The conversion @@ -313,9 +292,9 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) * g_strdup_printf () equivalent for gunichar2 :-( */ args = utf16_concat (utf16_quote, sei->lpFile, utf16_quote, sei->lpParameters == NULL ? NULL : utf16_space, sei->lpParameters, NULL); - if (args == NULL){ + if (args == NULL) { SetLastError (ERROR_INVALID_DATA); - return (FALSE); + return FALSE; } ret = CreateProcess (NULL, args, NULL, NULL, TRUE, CREATE_UNICODE_ENVIRONMENT, NULL, @@ -346,7 +325,7 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) handler = g_find_program_in_path ("kfmclient"); if (handler == NULL){ handler_utf16 = (gunichar2 *) -1; - return (FALSE); + return FALSE; } else { /* kfmclient needs exec argument */ char *old = handler; @@ -370,7 +349,7 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) sei->lpFile, utf16_quote, sei->lpParameters == NULL ? NULL : utf16_space, sei->lpParameters, NULL); - if (args == NULL){ + if (args == NULL) { SetLastError (ERROR_INVALID_DATA); return FALSE; } @@ -378,7 +357,7 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) CREATE_UNICODE_ENVIRONMENT, NULL, sei->lpDirectory, NULL, &process_info); g_free (args); - if (!ret){ + if (!ret) { if (GetLastError () != ERROR_OUTOFMEMORY) SetLastError (ERROR_INVALID_DATA); return FALSE; @@ -388,17 +367,16 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei) process_info.hProcess = NULL; } - if (sei->fMask & SEE_MASK_NOCLOSEPROCESS) { + if (sei->fMask & SEE_MASK_NOCLOSEPROCESS) sei->hProcess = process_info.hProcess; - } else { + else CloseHandle (process_info.hProcess); - } - return (ret); + return ret; } static gboolean -is_managed_binary (const gchar *filename) +is_managed_binary (const char *filename) { int original_errno = errno; #if defined(HAVE_LARGE_FILE_SUPPORT) && defined(O_LARGEFILE) @@ -505,22 +483,38 @@ leave: return managed; } -gboolean CreateProcessWithLogonW (const gunichar2 *username, - const gunichar2 *domain, - const gunichar2 *password, - const guint32 logonFlags, - const gunichar2 *appname, - const gunichar2 *cmdline, - guint32 create_flags, - gpointer env, - const gunichar2 *cwd, - WapiStartupInfo *startup, - WapiProcessInformation *process_info) +gboolean +CreateProcessWithLogonW (const gunichar2 *username, + const gunichar2 *domain, + const gunichar2 *password, + const guint32 logonFlags, + const gunichar2 *appname, + const gunichar2 *cmdline, + guint32 create_flags, + gpointer env, + const gunichar2 *cwd, + WapiStartupInfo *startup, + WapiProcessInformation *process_info) { /* FIXME: use user information */ return CreateProcess (appname, cmdline, NULL, NULL, FALSE, create_flags, env, cwd, startup, process_info); } +static gboolean +is_readable_or_executable (const char *prog) +{ + struct stat buf; + int a = access (prog, R_OK); + int b = access (prog, X_OK); + if (a != 0 && b != 0) + return FALSE; + if (stat (prog, &buf)) + return FALSE; + if (S_ISREG (buf.st_mode)) + return TRUE; + return FALSE; +} + static gboolean is_executable (const char *prog) { @@ -535,17 +529,15 @@ is_executable (const char *prog) } static void -switchDirectorySeparators(gchar *path) +switch_dir_separators (char *path) { size_t i, pathLength = strlen(path); /* Turn all the slashes round the right way, except for \' */ /* There are probably other characters that need to be excluded as well. */ - for (i = 0; i < pathLength; i++) - { - if (path[i] == '\\' && i < pathLength - 1 && path[i+1] != '\'' ) { + for (i = 0; i < pathLength; i++) { + if (path[i] == '\\' && i < pathLength - 1 && path[i+1] != '\'' ) path[i] = '/'; - } } } @@ -557,11 +549,12 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, WapiStartupInfo *startup, WapiProcessInformation *process_info) { - gchar *cmd=NULL, *prog = NULL, *full_prog = NULL, *args = NULL, *args_after_prog = NULL, *dir = NULL, **env_strings = NULL, **argv = NULL; + 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; gboolean ret = FALSE; gpointer handle; - struct _WapiHandle_process process_handle = {0}, *process_handle_data; + WapiHandle_process process_handle = {0}, *process_handle_data; GError *gerr = NULL; int in_fd, out_fd, err_fd; pid_t pid; @@ -570,10 +563,9 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, int dummy; struct MonoProcess *mono_process; gboolean fork_failed = FALSE; - - mono_once (&process_ops_once, process_ops_init); + mono_once (&process_sig_chld_once, process_add_sigchld_handler); - + /* appname and cmdline specify the executable and its args: * * If appname is not NULL, it is the name of the executable. @@ -610,7 +602,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, goto free_strings; } - switchDirectorySeparators(cmd); + switch_dir_separators(cmd); } if (cmdline != NULL) { @@ -633,13 +625,13 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, } /* Turn all the slashes round the right way */ - switchDirectorySeparators(dir); + switch_dir_separators(dir); } /* We can't put off locating the executable any longer :-( */ if (cmd != NULL) { - gchar *unquoted; + char *unquoted; if (g_ascii_isalpha (cmd[0]) && (cmd[1] == ':')) { /* Strip off the drive letter. I can't * believe that CP/M holdover is still @@ -655,7 +647,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, prog = g_strdup (unquoted); /* Executable existing ? */ - if (!is_executable (prog)) { + if (!is_readable_or_executable (prog)) { DEBUG ("%s: Couldn't find executable %s", __func__, prog); g_free (unquoted); @@ -671,8 +663,8 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, prog = g_strdup_printf ("%s/%s", curdir, unquoted); g_free (curdir); - /* And make sure it's executable */ - if (!is_executable (prog)) { + /* And make sure it's readable */ + if (!is_readable_or_executable (prog)) { DEBUG ("%s: Couldn't find executable %s", __func__, prog); g_free (unquoted); @@ -684,7 +676,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, args_after_prog = args; } else { - gchar *token = NULL; + char *token = NULL; char quote; /* Dig out the first token from args, taking quotation @@ -747,7 +739,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, /* Turn all the slashes round the right way. Only for * the prg. name */ - switchDirectorySeparators(token); + switch_dir_separators(token); if (g_ascii_isalpha (token[0]) && (token[1] == ':')) { /* Strip off the drive letter. I can't @@ -763,14 +755,13 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, prog = g_strdup (token); /* Executable existing ? */ - if (!is_executable (prog)) { + if (!is_readable_or_executable (prog)) { DEBUG ("%s: Couldn't find executable %s", __func__, token); g_free (token); SetLastError (ERROR_FILE_NOT_FOUND); goto free_strings; } - } else { char *curdir = g_get_current_dir (); @@ -785,8 +776,10 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, /* I assume X_OK is the criterion to use, * rather than F_OK + * + * X_OK is too strict *if* the target is a CLR binary */ - if (!is_executable (prog)) { + if (!is_readable_or_executable (prog)) { g_free (prog); prog = g_find_program_in_path (token); if (prog == NULL) { @@ -843,10 +836,17 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, goto free_strings; } } + } else { + if (!is_executable (prog)) { + DEBUG ("%s: Executable permisson not set on %s", __func__, prog); + g_free (prog); + SetLastError (ERROR_ACCESS_DENIED); + goto free_strings; + } } if (args_after_prog != NULL && *args_after_prog) { - gchar *qprog; + char *qprog; qprog = g_shell_quote (prog); full_prog = g_strconcat (qprog, " ", args_after_prog, NULL); @@ -873,8 +873,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, err_fd = GPOINTER_TO_UINT (GetStdHandle (STD_ERROR_HANDLE)); } - g_strlcpy (process_handle.proc_name, prog, - _WAPI_PROC_NAME_MAX_LEN - 1); + process_handle.proc_name = g_strdup (prog); process_set_defaults (&process_handle); @@ -895,7 +894,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, * environment variables in the new process. Otherwise the * new process inherits the same environment. */ - if (new_environ != NULL) { + if (new_environ) { gunichar2 *new_environp; /* Count the number of strings */ @@ -910,7 +909,7 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, /* +2: one for the process handle value, and the last * one is NULL */ - env_strings = g_new0 (gchar *, env_count + 2); + env_strings = g_new0 (char *, env_count + 2); /* Copy each environ string into 'strings' turning it * into utf8 (or the requested encoding) at the same @@ -926,14 +925,13 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, } } } else { - for (i = 0; environ[i] != NULL; i++) { + 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 (gchar *, env_count + 2); + env_strings = g_new0 (char *, env_count + 2); /* Copy each environ string into 'strings' turning it * into utf8 (or the requested encoding) at the same @@ -945,18 +943,6 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, env_count++; } } - /* pass process handle info to the child, so it doesn't have - * to do an expensive search over the whole list - */ - if (env_strings != NULL) { - struct _WapiHandleUnshared *handle_data; - struct _WapiHandle_shared_ref *ref; - - handle_data = &_WAPI_PRIVATE_HANDLES(GPOINTER_TO_UINT(handle)); - ref = &handle_data->u.shared; - - env_strings[env_count] = g_strdup_printf ("_WAPI_PROCESS_HANDLE_OFFSET=%d", ref->offset); - } /* Create a pipe to make sure the child doesn't exit before * we can add the process to the linked list of mono_processes */ @@ -1000,20 +986,17 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, } /* Close all file descriptors */ - for (i = getdtablesize () - 1; i > 2; i--) { + for (i = wapi_getdtablesize () - 1; i > 2; i--) close (i); - } #ifdef DEBUG_ENABLED DEBUG ("%s: exec()ing [%s] in dir [%s]", __func__, cmd, - dir==NULL?".":dir); - for (i = 0; argv[i] != NULL; i++) { + dir == NULL?".":dir); + for (i = 0; argv[i] != NULL; i++) g_message ("arg %d: [%s]", i, argv[i]); - } - for (i = 0; env_strings[i] != NULL; i++) { + for (i = 0; env_strings[i] != NULL; i++) g_message ("env %d: [%s]", i, env_strings[i]); - } #endif /* set cwd */ @@ -1030,9 +1013,8 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, } /* parent */ - ret = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS, - (gpointer *)&process_handle_data); - if (ret == FALSE) { + process_handle_data = lookup_process_handle (handle); + if (!process_handle_data) { g_warning ("%s: error looking up process handle %p", __func__, handle); _wapi_handle_unref (handle); @@ -1057,7 +1039,6 @@ gboolean CreateProcess (const gunichar2 *appname, const gunichar2 *cmdline, _wapi_handle_ref (handle); mono_process->handle = handle; - process_handle_data->self = _wapi_getpid (); process_handle_data->mono_process = mono_process; mono_mutex_lock (&mono_processes_mutex); @@ -1091,27 +1072,20 @@ cleanup: } free_strings: - if (cmd != NULL) { + if (cmd) g_free (cmd); - } - if (full_prog != NULL) { + if (full_prog) g_free (full_prog); - } - if (prog != NULL) { + if (prog) g_free (prog); - } - if (args != NULL) { + if (args) g_free (args); - } - if (dir != NULL) { + if (dir) g_free (dir); - } - if(env_strings != NULL) { + if (env_strings) g_strfreev (env_strings); - } - if (argv != NULL) { + if (argv) g_strfreev (argv); - } DEBUG ("%s: returning handle %p for pid %d", __func__, handle, pid); @@ -1119,98 +1093,39 @@ free_strings: /* Check if something needs to be cleaned up. */ mono_processes_cleanup (); - return(ret); + return ret; } -static void process_set_name (struct _WapiHandle_process *process_handle) +static void +process_set_name (WapiHandle_process *process_handle) { - gchar *progname, *utf8_progname, *slash; + char *progname, *utf8_progname, *slash; - progname=g_get_prgname (); - utf8_progname=mono_utf8_from_external (progname); + progname = g_get_prgname (); + utf8_progname = mono_utf8_from_external (progname); DEBUG ("%s: using [%s] as prog name", __func__, progname); - if(utf8_progname!=NULL) { - slash=strrchr (utf8_progname, '/'); - if(slash!=NULL) { - g_strlcpy (process_handle->proc_name, slash+1, - _WAPI_PROC_NAME_MAX_LEN - 1); - } else { - g_strlcpy (process_handle->proc_name, utf8_progname, - _WAPI_PROC_NAME_MAX_LEN - 1); - } - + if (utf8_progname) { + slash = strrchr (utf8_progname, '/'); + if (slash) + process_handle->proc_name = g_strdup (slash+1); + else + process_handle->proc_name = g_strdup (utf8_progname); g_free (utf8_progname); } } -extern void _wapi_time_t_to_filetime (time_t timeval, WapiFileTime *filetime); - -#if !GLIB_CHECK_VERSION (2,4,0) -#define g_setenv(a,b,c) setenv(a,b,c) -#define g_unsetenv(a) unsetenv(a) -#endif - -static void process_set_current (void) +void +wapi_processes_init (void) { pid_t pid = _wapi_getpid (); - const char *handle_env; - struct _WapiHandle_process process_handle = {0}; - - mono_once (&process_ops_once, process_ops_init); - - handle_env = g_getenv ("_WAPI_PROCESS_HANDLE_OFFSET"); - g_unsetenv ("_WAPI_PROCESS_HANDLE_OFFSET"); - - if (handle_env != NULL) { - struct _WapiHandle_process *process_handlep; - gchar *procname = NULL; - gboolean ok; - - current_process = _wapi_handle_new_from_offset (WAPI_HANDLE_PROCESS, atoi (handle_env), TRUE); - - DEBUG ("%s: Found my process handle: %p (offset %d 0x%x)", - __func__, current_process, atoi (handle_env), - atoi (handle_env)); - - ok = _wapi_lookup_handle (current_process, WAPI_HANDLE_PROCESS, - (gpointer *)&process_handlep); - if (ok) { - /* This test will probably break on linuxthreads, but - * that should be ancient history on all distros we - * care about by now - */ - if (process_handlep->id == pid) { - procname = process_handlep->proc_name; - if (!strcmp (procname, "mono")) { - /* Set a better process name */ - DEBUG ("%s: Setting better process name", __func__); - - process_set_name (process_handlep); - } else { - DEBUG ("%s: Leaving process name: %s", __func__, procname); - } - - return; - } - - /* Wrong pid, so drop this handle and fall through to - * create a new one - */ - _wapi_handle_unref (current_process); - } - } - - /* We get here if the handle wasn't specified in the - * environment, or if the process ID was wrong, or if the - * handle lookup failed (eg if the parent process forked and - * quit immediately, and deleted the shared data before the - * child got a chance to attach it.) - */ - - DEBUG ("%s: Need to create my own process handle", __func__); + WapiHandle_process process_handle = {0}; + _wapi_handle_register_capabilities (WAPI_HANDLE_PROCESS, + WAPI_HANDLE_CAP_WAIT | + WAPI_HANDLE_CAP_SPECIAL_WAIT); + process_handle.id = pid; process_set_defaults (&process_handle); @@ -1218,273 +1133,60 @@ static void process_set_current (void) current_process = _wapi_handle_new (WAPI_HANDLE_PROCESS, &process_handle); - if (current_process == _WAPI_HANDLE_INVALID) { - g_warning ("%s: error creating process handle", __func__); - return; - } + g_assert (current_process); } -gpointer _wapi_process_duplicate () +gpointer +_wapi_process_duplicate (void) { - mono_once (&process_current_once, process_set_current); - _wapi_handle_ref (current_process); - return(current_process); + return current_process; } /* Returns a pseudo handle that doesn't need to be closed afterwards */ -gpointer GetCurrentProcess (void) +gpointer +GetCurrentProcess (void) { - mono_once (&process_current_once, process_set_current); - - return(_WAPI_PROCESS_CURRENT); + return _WAPI_PROCESS_CURRENT; } -guint32 GetProcessId (gpointer handle) +guint32 +GetProcessId (gpointer handle) { - struct _WapiHandle_process *process_handle; - gboolean ok; + WapiHandle_process *process_handle; - if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) /* This is a pseudo handle */ - return(GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED_PID_MASK); - } + return WAPI_HANDLE_TO_PID (handle); - ok = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS, - (gpointer *)&process_handle); - if (ok == FALSE) { + process_handle = lookup_process_handle (handle); + if (!process_handle) { SetLastError (ERROR_INVALID_HANDLE); - return (0); + return 0; } - return (process_handle->id); + return process_handle->id; } -guint32 GetCurrentProcessId (void) +static gboolean +process_open_compare (gpointer handle, gpointer user_data) { - mono_once (&process_current_once, process_set_current); - - return (GetProcessId (current_process)); -} + pid_t wanted_pid; + WapiHandle_process *process_handle; + pid_t checking_pid; -/* Returns the process id as a convenience to the functions that call this */ -static pid_t signal_process_if_gone (gpointer handle) -{ - struct _WapiHandle_process *process_handle; - gboolean ok; + g_assert (!WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)); - g_assert ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) != _WAPI_PROCESS_UNHANDLED); - - /* Make sure the process is signalled if it has exited - if - * the parent process didn't wait for it then it won't be - */ - ok = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS, - (gpointer *)&process_handle); - if (ok == FALSE) { - /* It's possible that the handle has vanished during - * the _wapi_search_handle before it gets here, so - * don't spam the console with warnings. - */ -/* g_warning ("%s: error looking up process handle %p", - __func__, handle);*/ - - return (0); - } + process_handle = lookup_process_handle (handle); + g_assert (process_handle); DEBUG ("%s: looking at process %d", __func__, process_handle->id); - if (kill (process_handle->id, 0) == -1 && - (errno == ESRCH || - errno == EPERM)) { - /* The process is dead, (EPERM tells us a new process - * has that ID, but as it's owned by someone else it - * can't be the one listed in our shared memory file) - */ - _wapi_shared_handle_set_signal_state (handle, TRUE); - } - - return (process_handle->id); -} - -#ifdef UNUSED_CODE -static gboolean process_enum (gpointer handle, gpointer user_data) -{ - GArray *processes=user_data; - pid_t pid = signal_process_if_gone (handle); - int i; - - if (pid == 0) { - return (FALSE); - } - - /* Ignore processes that have already exited (ie they are signalled) */ - if (_wapi_handle_issignalled (handle) == FALSE) { - DEBUG ("%s: process %d added to array", __func__, pid); - - /* This ensures that duplicates aren't returned (see - * the comment above _wapi_search_handle () for why - * it's needed - */ - for (i = 0; i < processes->len; i++) { - if (g_array_index (processes, pid_t, i) == pid) { - /* We've already got this one, return - * FALSE to keep searching - */ - return (FALSE); - } - } - - g_array_append_val (processes, pid); - } - - /* Return false to keep searching */ - return(FALSE); -} -#endif /* UNUSED_CODE */ - -#if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) - -gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed) -{ - guint32 count, fit, i, j; - gint32 err; - gboolean done; - size_t proclength, size; -#if defined(__OpenBSD__) - struct kinfo_proc *result; - int name[6]; - name[0] = CTL_KERN; - name[1] = KERN_PROC; - name[2] = KERN_PROC_ALL; - name[3] = 0; - name[4] = sizeof(struct kinfo_proc); - name[5] = 0; -#else - struct kinfo_proc *result; - static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }; -#endif - - mono_once (&process_current_once, process_set_current); - - result = NULL; - done = FALSE; - - do { - proclength = 0; -#if defined(__OpenBSD__) - size = (sizeof(name) / sizeof(*name)); -#else - size = (sizeof(name) / sizeof(*name)) - 1; -#endif - err = sysctl ((int *)name, size, NULL, &proclength, NULL, 0); - - if (err == 0) { - result = malloc (proclength); - - if (result == NULL) - return FALSE; - -#if defined(__OpenBSD__) - name[5] = (int)(proclength / sizeof(struct kinfo_proc)); -#endif - - err = sysctl ((int *) name, size, result, &proclength, NULL, 0); - - if (err == 0) - done = TRUE; - else { - free (result); - result = NULL; - } - } - } while (err == 0 && !done); - - if (err != 0) { - if (result != NULL) { - free (result); - result = NULL; - } - return(FALSE); - } - - count = proclength / sizeof(struct kinfo_proc); - - fit = len / sizeof(guint32); - for (i = 0, j = 0; j< fit && i < count; i++) { -#if defined(__OpenBSD__) - pids [j++] = result [i].p_pid; -#else - if (result[i].kp_proc.p_pid > 0) /* Pid 0 not supported */ - pids [j++] = result [i].kp_proc.p_pid; -#endif - } - free (result); - result = NULL; - *needed = j * sizeof(guint32); - - return(TRUE); -} -#elif defined(__HAIKU__) - -gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed) -{ - guint32 fit, i = 0; - int32 cookie = 0; - team_info teamInfo; - - mono_once (&process_current_once, process_set_current); - - fit = len / sizeof (guint32); - while (get_next_team_info (&cookie, &teamInfo) == B_OK && i < fit) { - pids [i++] = teamInfo.team; - } - *needed = i * sizeof (guint32); - - return TRUE; -} -#else -gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed) -{ - guint32 fit, i; - DIR *dir; - struct dirent *entry; - - mono_once (&process_current_once, process_set_current); - - dir = opendir ("/proc"); - if (dir == NULL) { - return(FALSE); - } - - i = 0; - fit = len / sizeof (guint32); - while(i < fit && (entry = readdir (dir)) != NULL) { - pid_t pid; - char *endptr; - - if (!isdigit (entry->d_name[0])) - continue; - - pid = (pid_t) strtol (entry->d_name, &endptr, 10); - if (*endptr == '\0') - pids [i++] = (guint32) pid; - } - closedir (dir); - *needed = i * sizeof(guint32); - - return(TRUE); -} -#endif - -static gboolean process_open_compare (gpointer handle, gpointer user_data) -{ - pid_t wanted_pid; - pid_t checking_pid = signal_process_if_gone (handle); + checking_pid = process_handle->id; - if (checking_pid == 0) { - return(FALSE); - } + if (checking_pid == 0) + return FALSE; wanted_pid = GPOINTER_TO_UINT (user_data); @@ -1493,37 +1195,34 @@ static gboolean process_open_compare (gpointer handle, gpointer user_data) * unsignalled */ if (checking_pid == wanted_pid && - _wapi_handle_issignalled (handle) == FALSE) { + !_wapi_handle_issignalled (handle)) { /* If the handle is blown away in the window between * returning TRUE here and _wapi_search_handle pinging * the timestamp, the search will continue */ - return(TRUE); + return TRUE; } else { - return(FALSE); + return FALSE; } } -gboolean CloseProcess(gpointer handle) +gboolean +CloseProcess (gpointer handle) { - if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { - /* This is a pseudo handle */ - return(TRUE); - } - + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (handle)) + return TRUE; return CloseHandle (handle); } /* * The caller owns the returned handle and must call CloseProcess () on it to clean it up. */ -gpointer OpenProcess (guint32 req_access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 pid) +gpointer +OpenProcess (guint32 req_access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 pid) { /* Find the process handle that corresponds to pid */ gpointer handle = NULL; - mono_once (&process_current_once, process_set_current); - DEBUG ("%s: looking for process %d", __func__, pid); handle = _wapi_search_handle (WAPI_HANDLE_PROCESS, @@ -1534,34 +1233,31 @@ gpointer OpenProcess (guint32 req_access G_GNUC_UNUSED, gboolean inherit G_GNUC_ /* Return a pseudo handle for processes we * don't have handles for */ - return GINT_TO_POINTER (_WAPI_PROCESS_UNHANDLED + pid); + return WAPI_PID_TO_HANDLE (pid); } else { DEBUG ("%s: Can't find pid %d", __func__, pid); SetLastError (ERROR_PROC_NOT_FOUND); - return(NULL); + return NULL; } } /* _wapi_search_handle () already added a ref */ - return(handle); + return handle; } -gboolean GetExitCodeProcess (gpointer process, guint32 *code) +gboolean +GetExitCodeProcess (gpointer process, guint32 *code) { - struct _WapiHandle_process *process_handle; - gboolean ok; + WapiHandle_process *process_handle; guint32 pid = -1; - mono_once (&process_current_once, process_set_current); - - if(code==NULL) { - return(FALSE); - } + if (!code) + return FALSE; - pid = GPOINTER_TO_UINT (process) - _WAPI_PROCESS_UNHANDLED; - if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { + pid = WAPI_HANDLE_TO_PID (process); /* 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 */ @@ -1573,14 +1269,18 @@ gboolean GetExitCodeProcess (gpointer process, guint32 *code) } } - ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *)&process_handle); - if(ok==FALSE) { + process_handle = lookup_process_handle (process); + if (!process_handle) { DEBUG ("%s: Can't find process %p", __func__, process); - return(FALSE); + return FALSE; } - + + if (process_handle->id == _wapi_getpid ()) { + *code = STILL_ACTIVE; + return TRUE; + } + /* A process handle is only signalled if the process has exited * and has been waited for */ @@ -1589,53 +1289,54 @@ gboolean GetExitCodeProcess (gpointer process, guint32 *code) */ process_wait (process, 0, TRUE); - if (_wapi_handle_issignalled (process) == TRUE) { + if (_wapi_handle_issignalled (process)) *code = process_handle->exitstatus; - } else { + else *code = STILL_ACTIVE; - } - return(TRUE); + return TRUE; } -gboolean GetProcessTimes (gpointer process, WapiFileTime *create_time, - WapiFileTime *exit_time, WapiFileTime *kernel_time, - WapiFileTime *user_time) +gboolean +GetProcessTimes (gpointer process, WapiFileTime *create_time, + WapiFileTime *exit_time, WapiFileTime *kernel_time, + WapiFileTime *user_time) { - struct _WapiHandle_process *process_handle; - gboolean ok; + WapiHandle_process *process_handle; gboolean ku_times_set = FALSE; - mono_once (&process_current_once, process_set_current); - - if(create_time==NULL || exit_time==NULL || kernel_time==NULL || - user_time==NULL) { + if (create_time == NULL || exit_time == NULL || kernel_time == NULL || + user_time == NULL) /* Not sure if w32 allows NULLs here or not */ - return(FALSE); - } + return FALSE; - if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { - /* This is a pseudo handle, so just fail for now - */ - return(FALSE); + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { + gpointer pid = GINT_TO_POINTER (WAPI_HANDLE_TO_PID(process)); + gint64 start_ticks, user_ticks, kernel_ticks; + + mono_process_get_times (pid, &start_ticks, &user_ticks, &kernel_ticks); + + _wapi_guint64_to_filetime (start_ticks, create_time); + _wapi_guint64_to_filetime (user_ticks, kernel_time); + _wapi_guint64_to_filetime (kernel_ticks, user_time); + + return TRUE; } - - ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *)&process_handle); - if(ok==FALSE) { + + process_handle = lookup_process_handle (process); + if (!process_handle) { DEBUG ("%s: Can't find process %p", __func__, process); - return(FALSE); + return FALSE; } - *create_time=process_handle->create_time; + *create_time = process_handle->create_time; /* A process handle is only signalled if the process has * exited. Otherwise exit_time isn't set */ - if(_wapi_handle_issignalled (process)==TRUE) { - *exit_time=process_handle->exit_time; - } + if (_wapi_handle_issignalled (process)) + *exit_time = process_handle->exit_time; #ifdef HAVE_GETRUSAGE if (process_handle->id == getpid ()) { @@ -1655,18 +1356,18 @@ gboolean GetProcessTimes (gpointer process, WapiFileTime *create_time, memset (user_time, 0, sizeof (WapiFileTime)); } - return(TRUE); + return TRUE; } typedef struct { gpointer address_start; gpointer address_end; - gchar *perms; + char *perms; gpointer address_offset; - dev_t device; - ino_t inode; - gchar *filename; + guint64 device; + guint64 inode; + char *filename; } WapiProcModule; static void free_procmodule (WapiProcModule *mod) @@ -1734,7 +1435,7 @@ static GSList *load_modules (void) mod->perms = g_strdup ("r--p"); mod->address_offset = 0; mod->device = makedev (0, 0); - mod->inode = (ino_t) i; + mod->inode = i; mod->filename = g_strdup (name); if (g_slist_find_custom (ret, mod, find_procmodule) == NULL) { @@ -1786,7 +1487,7 @@ static GSList *load_modules (void) info->dlpi_phdr[info->dlpi_phnum - 1].p_vaddr); mod->perms = g_strdup ("r--p"); mod->address_offset = 0; - mod->inode = (ino_t) i; + mod->inode = i; mod->filename = g_strdup (info->dlpi_name); DEBUG ("%s: inode=%d, filename=%s, address_start=%p, address_end=%p", __func__, @@ -1843,13 +1544,13 @@ static GSList *load_modules (FILE *fp) { GSList *ret = NULL; WapiProcModule *mod; - gchar buf[MAXPATHLEN + 1], *p, *endp; - gchar *start_start, *end_start, *prot_start, *offset_start; - gchar *maj_dev_start, *min_dev_start, *inode_start, prot_buf[5]; + char buf[MAXPATHLEN + 1], *p, *endp; + char *start_start, *end_start, *prot_start, *offset_start; + char *maj_dev_start, *min_dev_start, *inode_start, prot_buf[5]; gpointer address_start, address_end, address_offset; guint32 maj_dev, min_dev; - ino_t inode; - dev_t device; + guint64 inode; + guint64 device; while (fgets (buf, sizeof(buf), fp)) { p = buf; @@ -1922,7 +1623,7 @@ static GSList *load_modules (FILE *fp) if (!g_ascii_isxdigit (*inode_start)) { continue; } - inode = (ino_t)strtol (inode_start, &endp, 10); + inode = (guint64)strtol (inode_start, &endp, 10); p = endp; if (!g_ascii_isspace (*p)) { continue; @@ -1959,7 +1660,7 @@ static GSList *load_modules (FILE *fp) } #endif -static gboolean match_procname_to_modulename (gchar *procname, gchar *modulename) +static gboolean match_procname_to_modulename (char *procname, char *modulename) { char* lastsep = NULL; char* lastsep2 = NULL; @@ -2001,18 +1702,18 @@ static gboolean match_procname_to_modulename (gchar *procname, gchar *modulename return result; } -#if !defined(__OpenBSD__) +#if !(defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__HAIKU__)) static FILE * open_process_map (int pid, const char *mode) { FILE *fp = NULL; - const gchar *proc_path[] = { + const char *proc_path[] = { "/proc/%d/maps", /* GNU/Linux */ "/proc/%d/map", /* FreeBSD */ NULL }; int i; - gchar *filename; + char *filename; for (i = 0; fp == NULL && proc_path [i]; i++) { filename = g_strdup_printf (proc_path[i], pid); @@ -2027,8 +1728,7 @@ open_process_map (int pid, const char *mode) gboolean EnumProcessModules (gpointer process, gpointer *modules, guint32 size, guint32 *needed) { - struct _WapiHandle_process *process_handle; - gboolean ok; + WapiHandle_process *process_handle; #if !defined(__OpenBSD__) && !defined(PLATFORM_MACOSX) FILE *fp; #endif @@ -2037,7 +1737,7 @@ gboolean EnumProcessModules (gpointer process, gpointer *modules, guint32 count, avail = size / sizeof(gpointer); int i; pid_t pid; - gchar *proc_name = NULL; + char *proc_name = NULL; /* Store modules in an array of pointers (main module as * modules[0]), using the load address for each module as a @@ -2048,72 +1748,76 @@ gboolean EnumProcessModules (gpointer process, gpointer *modules, * implement /dev/kmem reading or whatever other horrid * technique is needed. */ - if (size < sizeof(gpointer)) { - return(FALSE); - } + if (size < sizeof(gpointer)) + return FALSE; - if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { - /* This is a pseudo handle */ - pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK); + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { + pid = WAPI_HANDLE_TO_PID (process); } else { - ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *)&process_handle); - if (ok == FALSE) { + process_handle = lookup_process_handle (process); + if (!process_handle) { DEBUG ("%s: Can't find process %p", __func__, process); - return(FALSE); + return FALSE; } pid = process_handle->id; proc_name = process_handle->proc_name; } #if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__HAIKU__) - { - mods = load_modules (); + mods = load_modules (); + if (!proc_name) { + modules[0] = NULL; + *needed = sizeof(gpointer); + return TRUE; + } #else - if ((fp = open_process_map (pid, "r")) == NULL) { + fp = open_process_map (pid, "r"); + if (!fp) { /* No /proc//maps so just return the main module * shortcut for now */ modules[0] = NULL; *needed = sizeof(gpointer); - } else { - mods = load_modules (fp); - fclose (fp); + return TRUE; + } + mods = load_modules (fp); + fclose (fp); #endif - count = g_slist_length (mods); + count = g_slist_length (mods); - /* count + 1 to leave slot 0 for the main module */ - *needed = sizeof(gpointer) * (count + 1); - - /* Use the NULL shortcut, as the first line in - * /proc//maps isn't the executable, and we need - * that first in the returned list. Check the module name - * to see if it ends with the proc name and substitute - * the first entry with it. FIXME if this turns out to - * be a problem. - */ - modules[0] = NULL; - for (i = 0; i < (avail - 1) && i < count; i++) { - module = (WapiProcModule *)g_slist_nth_data (mods, i); - if (modules[0] != NULL) - modules[i] = module->address_start; - else if (match_procname_to_modulename (proc_name, module->filename)) - modules[0] = module->address_start; - else - modules[i + 1] = module->address_start; - } + /* count + 1 to leave slot 0 for the main module */ + *needed = sizeof(gpointer) * (count + 1); + + /* + * Use the NULL shortcut, as the first line in + * /proc//maps isn't the executable, and we need + * that first in the returned list. Check the module name + * to see if it ends with the proc name and substitute + * the first entry with it. FIXME if this turns out to + * be a problem. + */ + modules[0] = NULL; + for (i = 0; i < (avail - 1) && i < count; i++) { + module = (WapiProcModule *)g_slist_nth_data (mods, i); + if (modules[0] != NULL) + modules[i] = module->address_start; + else if (match_procname_to_modulename (proc_name, module->filename)) + modules[0] = module->address_start; + else + modules[i + 1] = module->address_start; + } - for (i = 0; i < count; i++) { - free_procmodule (g_slist_nth_data (mods, i)); - } - g_slist_free (mods); + for (i = 0; i < count; i++) { + free_procmodule (g_slist_nth_data (mods, i)); } + g_slist_free (mods); - return(TRUE); + return TRUE; } -static gchar *get_process_name_from_proc (pid_t pid) +static char * +get_process_name_from_proc (pid_t pid) { #if defined(__OpenBSD__) int mib [6]; @@ -2127,10 +1831,10 @@ static gchar *get_process_name_from_proc (pid_t pid) #endif #else FILE *fp; - gchar *filename = NULL; + char *filename = NULL; #endif - gchar buf[256]; - gchar *ret = NULL; + char buf[256]; + char *ret = NULL; #if defined(PLATFORM_SOLARIS) filename = g_strdup_printf ("/proc/%d/psinfo", pid); @@ -2239,7 +1943,7 @@ retry: filename = g_strdup_printf ("/proc/%d/stat", pid); if ((fp = fopen (filename, "r")) != NULL) { if (fgets (buf, 256, fp) != NULL) { - gchar *start, *end; + char *start, *end; start = strchr (buf, '('); if (start != NULL) { @@ -2266,11 +1970,11 @@ retry: * Return the full path of the executable of the process PID, or NULL if it cannot be determined. * Returns malloc-ed memory. */ -gchar* +char* wapi_process_get_path (pid_t pid) { #if defined(PLATFORM_MACOSX) && !defined(__mono_ppc__) && defined(TARGET_OSX) - gchar buf [PROC_PIDPATHINFO_MAXSIZE]; + char buf [PROC_PIDPATHINFO_MAXSIZE]; int res; res = proc_pidpath (pid, buf, sizeof (buf)); @@ -2296,15 +2000,15 @@ wapi_process_set_cli_launcher (char *path) cli_launcher = path ? g_strdup (path) : NULL; } -static guint32 get_module_name (gpointer process, gpointer module, - gunichar2 *basename, guint32 size, - gboolean base) +static guint32 +get_module_name (gpointer process, gpointer module, + gunichar2 *basename, guint32 size, + gboolean base) { - struct _WapiHandle_process *process_handle; - gboolean ok; + WapiHandle_process *process_handle; pid_t pid; gunichar2 *procname; - gchar *procname_ext = NULL; + char *procname_ext = NULL; glong len; gsize bytes; #if !defined(__OpenBSD__) && !defined(PLATFORM_MACOSX) @@ -2314,31 +2018,27 @@ static guint32 get_module_name (gpointer process, gpointer module, WapiProcModule *found_module; guint32 count; int i; - gchar *proc_name = NULL; + char *proc_name = NULL; - mono_once (&process_current_once, process_set_current); - DEBUG ("%s: Getting module base name, process handle %p module %p", __func__, process, module); - size = size*sizeof(gunichar2); /* adjust for unicode characters */ + size = size * sizeof (gunichar2); /* adjust for unicode characters */ - if (basename == NULL || size == 0) { - return(0); - } + if (basename == NULL || size == 0) + return 0; - if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { /* This is a pseudo handle */ - pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK); + pid = (pid_t)WAPI_HANDLE_TO_PID (process); proc_name = get_process_name_from_proc (pid); } else { - ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *)&process_handle); - if (ok == FALSE) { + process_handle = lookup_process_handle (process); + if (!process_handle) { DEBUG ("%s: Can't find process %p", __func__, process); - return(0); + return 0; } pid = process_handle->id; proc_name = g_strdup (process_handle->proc_name); @@ -2346,10 +2046,10 @@ static guint32 get_module_name (gpointer process, gpointer module, /* Look up the address in /proc//maps */ #if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__HAIKU__) - { - mods = load_modules (); + mods = load_modules (); #else - if ((fp = open_process_map (pid, "r")) == NULL) { + fp = open_process_map (pid, "r"); + if (fp == NULL) { if (errno == EACCES && module == NULL && base == TRUE) { procname_ext = get_process_name_from_proc (pid); } else { @@ -2357,47 +2057,45 @@ static guint32 get_module_name (gpointer process, gpointer module, * for now */ g_free (proc_name); - return(0); + return 0; } } else { mods = load_modules (fp); fclose (fp); + } #endif - count = g_slist_length (mods); - - /* If module != NULL compare the address. - * If module == NULL we are looking for the main module. - * The best we can do for now check it the module name end with the process name. - */ - for (i = 0; i < count; i++) { - found_module = (WapiProcModule *)g_slist_nth_data (mods, i); - if (procname_ext == NULL && - ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) || - (module != NULL && found_module->address_start == module))) { - if (base) { - procname_ext = g_path_get_basename (found_module->filename); - } else { - procname_ext = g_strdup (found_module->filename); - } - } + count = g_slist_length (mods); - free_procmodule (found_module); + /* If module != NULL compare the address. + * If module == NULL we are looking for the main module. + * The best we can do for now check it the module name end with the process name. + */ + for (i = 0; i < count; i++) { + found_module = (WapiProcModule *)g_slist_nth_data (mods, i); + if (procname_ext == NULL && + ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) || + (module != NULL && found_module->address_start == module))) { + if (base) + procname_ext = g_path_get_basename (found_module->filename); + else + procname_ext = g_strdup (found_module->filename); } - if (procname_ext == NULL) - { - /* 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 = get_process_name_from_proc (pid); - } + free_procmodule (found_module); + } - g_slist_free (mods); - g_free (proc_name); + if (procname_ext == NULL) { + /* 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 = get_process_name_from_proc (pid); } - if (procname_ext != NULL) { + g_slist_free (mods); + g_free (proc_name); + + if (procname_ext) { DEBUG ("%s: Process name is [%s]", __func__, procname_ext); @@ -2405,7 +2103,7 @@ static guint32 get_module_name (gpointer process, gpointer module, if (procname == NULL) { /* bugger */ g_free (procname_ext); - return(0); + return 0; } len = (bytes / 2); @@ -2427,29 +2125,31 @@ static guint32 get_module_name (gpointer process, gpointer module, g_free (procname); g_free (procname_ext); - return(len); + return len; } - return(0); + return 0; } -guint32 GetModuleBaseName (gpointer process, gpointer module, - gunichar2 *basename, guint32 size) +guint32 +GetModuleBaseName (gpointer process, gpointer module, + gunichar2 *basename, guint32 size) { - return(get_module_name (process, module, basename, size, TRUE)); + return get_module_name (process, module, basename, size, TRUE); } -guint32 GetModuleFileNameEx (gpointer process, gpointer module, - gunichar2 *filename, guint32 size) +guint32 +GetModuleFileNameEx (gpointer process, gpointer module, + gunichar2 *filename, guint32 size) { - return(get_module_name (process, module, filename, size, FALSE)); + return get_module_name (process, module, filename, size, FALSE); } -gboolean GetModuleInformation (gpointer process, gpointer module, - WapiModuleInfo *modinfo, guint32 size) +gboolean +GetModuleInformation (gpointer process, gpointer module, + WapiModuleInfo *modinfo, guint32 size) { - struct _WapiHandle_process *process_handle; - gboolean ok; + WapiHandle_process *process_handle; pid_t pid; #if !defined(__OpenBSD__) && !defined(PLATFORM_MACOSX) FILE *fp; @@ -2459,37 +2159,31 @@ gboolean GetModuleInformation (gpointer process, gpointer module, guint32 count; int i; gboolean ret = FALSE; - gchar *proc_name = NULL; - - mono_once (&process_current_once, process_set_current); + char *proc_name = NULL; DEBUG ("%s: Getting module info, process handle %p module %p", __func__, process, module); - if (modinfo == NULL || size < sizeof(WapiModuleInfo)) { - return(FALSE); - } + if (modinfo == NULL || size < sizeof (WapiModuleInfo)) + return FALSE; - if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { - /* This is a pseudo handle */ - pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK); + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { + pid = (pid_t)WAPI_HANDLE_TO_PID (process); proc_name = get_process_name_from_proc (pid); } else { - ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *)&process_handle); - if (ok == FALSE) { + process_handle = lookup_process_handle (process); + if (!process_handle) { DEBUG ("%s: Can't find process %p", __func__, process); - return(FALSE); + return FALSE; } pid = process_handle->id; proc_name = g_strdup (process_handle->proc_name); } #if defined(PLATFORM_MACOSX) || defined(__OpenBSD__) || defined(__HAIKU__) - { - mods = load_modules (); + mods = load_modules (); #else /* Look up the address in /proc//maps */ if ((fp = open_process_map (pid, "r")) == NULL) { @@ -2497,22 +2191,22 @@ gboolean GetModuleInformation (gpointer process, gpointer module, * for now */ g_free (proc_name); - return(FALSE); - } else { - mods = load_modules (fp); - fclose (fp); + return FALSE; + } + mods = load_modules (fp); + fclose (fp); #endif - count = g_slist_length (mods); + count = g_slist_length (mods); - /* If module != NULL compare the address. - * If module == NULL we are looking for the main module. - * The best we can do for now check it the module name end with the process name. - */ - for (i = 0; i < count; i++) { + /* If module != NULL compare the address. + * If module == NULL we are looking for the main module. + * The best we can do for now check it the module name end with the process name. + */ + for (i = 0; i < count; i++) { found_module = (WapiProcModule *)g_slist_nth_data (mods, i); - if ( ret == FALSE && - ((module == NULL && match_procname_to_modulename (proc_name, found_module->filename)) || - (module != NULL && found_module->address_start == module))) { + if (ret == FALSE && + ((module == NULL && match_procname_to_modulename (proc_name, 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); modinfo->EntryPoint = found_module->address_offset; @@ -2520,94 +2214,79 @@ gboolean GetModuleInformation (gpointer process, gpointer module, } free_procmodule (found_module); - } - - g_slist_free (mods); - g_free (proc_name); } - return(ret); + g_slist_free (mods); + g_free (proc_name); + + return ret; } -gboolean GetProcessWorkingSetSize (gpointer process, size_t *min, size_t *max) +gboolean +GetProcessWorkingSetSize (gpointer process, size_t *min, size_t *max) { - struct _WapiHandle_process *process_handle; - gboolean ok; + WapiHandle_process *process_handle; - mono_once (&process_current_once, process_set_current); - - if(min==NULL || max==NULL) { + if (min == NULL || max == NULL) /* Not sure if w32 allows NULLs here or not */ - return(FALSE); - } + return FALSE; - if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { - /* This is a pseudo handle, so just fail for now - */ - return(FALSE); - } + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) + /* This is a pseudo handle, so just fail for now */ + return FALSE; - ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *)&process_handle); - if(ok==FALSE) { + process_handle = lookup_process_handle (process); + if (!process_handle) { DEBUG ("%s: Can't find process %p", __func__, process); - return(FALSE); + return FALSE; } - *min=process_handle->min_working_set; - *max=process_handle->max_working_set; + *min = process_handle->min_working_set; + *max = process_handle->max_working_set; - return(TRUE); + return TRUE; } -gboolean SetProcessWorkingSetSize (gpointer process, size_t min, size_t max) +gboolean +SetProcessWorkingSetSize (gpointer process, size_t min, size_t max) { - struct _WapiHandle_process *process_handle; - gboolean ok; + WapiHandle_process *process_handle; - mono_once (&process_current_once, process_set_current); - - if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) /* This is a pseudo handle, so just fail for now */ - return(FALSE); - } + return FALSE; - ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *)&process_handle); - if(ok==FALSE) { + process_handle = lookup_process_handle (process); + if (!process_handle) { DEBUG ("%s: Can't find process %p", __func__, process); - return(FALSE); + return FALSE; } - process_handle->min_working_set=min; - process_handle->max_working_set=max; + process_handle->min_working_set = min; + process_handle->max_working_set = max; - return(TRUE); + return TRUE; } gboolean TerminateProcess (gpointer process, gint32 exitCode) { - struct _WapiHandle_process *process_handle; - gboolean ok; + WapiHandle_process *process_handle; int signo; int ret; pid_t pid; - if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { /* This is a pseudo handle */ - pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK); + pid = (pid_t)WAPI_HANDLE_TO_PID (process); } else { - ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *) &process_handle); - - if (ok == FALSE) { - DEBUG ("%s: Can't find process %p", __func__, - process); + process_handle = lookup_process_handle (process); + if (!process_handle) { + DEBUG ("%s: Can't find process %p", __func__, process); SetLastError (ERROR_INVALID_HANDLE); return FALSE; } @@ -2639,19 +2318,16 @@ guint32 GetPriorityClass (gpointer process) { #ifdef HAVE_GETPRIORITY - struct _WapiHandle_process *process_handle; - gboolean ok; + WapiHandle_process *process_handle; int ret; pid_t pid; - if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { /* This is a pseudo handle */ - pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK); + pid = (pid_t)WAPI_HANDLE_TO_PID (process); } else { - ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *) &process_handle); - - if (!ok) { + process_handle = lookup_process_handle (process); + if (!process_handle) { SetLastError (ERROR_INVALID_HANDLE); return FALSE; } @@ -2699,20 +2375,17 @@ gboolean SetPriorityClass (gpointer process, guint32 priority_class) { #ifdef HAVE_SETPRIORITY - struct _WapiHandle_process *process_handle; - gboolean ok; + WapiHandle_process *process_handle; int ret; int prio; pid_t pid; - if ((GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { + if (WAPI_IS_PSEUDO_PROCESS_HANDLE (process)) { /* This is a pseudo handle */ - pid = (pid_t)(GPOINTER_TO_UINT (process) & _WAPI_PROCESS_UNHANDLED_PID_MASK); + pid = (pid_t)WAPI_HANDLE_TO_PID (process); } else { - ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS, - (gpointer *) &process_handle); - - if (!ok) { + process_handle = lookup_process_handle (process); + if (!process_handle) { SetLastError (ERROR_INVALID_HANDLE); return FALSE; } @@ -2770,9 +2443,9 @@ mono_processes_cleanup (void) { struct MonoProcess *mp; struct MonoProcess *prev = NULL; - struct MonoProcess *candidate = NULL; + GSList *finished = NULL; + GSList *l; gpointer unref_handle; - int spin; DEBUG ("%s", __func__); @@ -2780,9 +2453,8 @@ mono_processes_cleanup (void) if (InterlockedCompareExchange (&mono_processes_cleaning_up, 1, 0) != 0) return; - mp = mono_processes; - while (mp != NULL) { - if (mp->pid == 0 && mp->handle != NULL) { + for (mp = mono_processes; mp; mp = mp->next) { + if (mp->pid == 0 && mp->handle) { /* This process has exited and we need to remove the artifical ref * on the handle */ mono_mutex_lock (&mono_processes_mutex); @@ -2791,63 +2463,53 @@ mono_processes_cleanup (void) mono_mutex_unlock (&mono_processes_mutex); if (unref_handle) _wapi_handle_unref (unref_handle); - continue; } - mp = mp->next; } - mp = mono_processes; - spin = 0; - while (mp != NULL) { - if ((mp->handle_count == 0 && mp->pid == 0) || candidate != NULL) { - if (spin > 0) { - _wapi_handle_spin (spin); - spin <<= 1; - } - - /* We've found a candidate */ - mono_mutex_lock (&mono_processes_mutex); - if (candidate == NULL) { - /* unlink it */ - if (mp == mono_processes) { - mono_processes = mp->next; - } else { - prev->next = mp->next; - } - candidate = mp; - } + /* + * Remove processes which exited from the mono_processes list. + * We need to synchronize with the sigchld handler here, which runs + * asynchronously. The handler requires that the mono_processes list + * remain valid. + */ + mono_mutex_lock (&mono_processes_mutex); - /* It's still safe to traverse the structure.*/ - mono_memory_barrier (); + mp = mono_processes; + while (mp) { + if (mp->handle_count == 0 && mp->freeable) { + /* + * Unlink the entry. + * This code can run parallel with the sigchld handler, but the + * modifications it makes are safe. + */ + if (mp == mono_processes) + mono_processes = mp->next; + else + prev->next = mp->next; + finished = g_slist_prepend (finished, mp); - if (mono_processes_read_lock != 0) { - /* The sigchld handler is watching us. Spin a bit and try again */ - if (spin == 0) { - spin = 1; - } else if (spin >= 8) { - /* Just give up for now */ - mono_mutex_unlock (&mono_processes_mutex); - break; - } - } else { - /* We've modified the list of processes, and we know the sigchld handler - * isn't executing, so even if it executes at any moment, it'll see the - * new version of the list. So now we can free the candidate. */ - DEBUG ("%s: freeing candidate %p", __func__, candidate); - mp = candidate->next; - MONO_SEM_DESTROY (&candidate->exit_sem); - g_free (candidate); - candidate = NULL; - } + mp = mp->next; + } else { + prev = mp; + mp = mp->next; + } + } - mono_mutex_unlock (&mono_processes_mutex); + mono_memory_barrier (); - continue; - } - spin = 0; - prev = mp; - mp = mp->next; + for (l = finished; l; l = l->next) { + /* + * All the entries in the finished list are unlinked from mono_processes, and + * they have the 'finished' flag set, which means the sigchld handler is done + * accessing them. + */ + mp = l->data; + MONO_SEM_DESTROY (&mp->exit_sem); + g_free (mp); } + g_slist_free (finished); + + mono_mutex_unlock (&mono_processes_mutex); DEBUG ("%s done", __func__); @@ -2857,12 +2519,14 @@ mono_processes_cleanup (void) static void process_close (gpointer handle, gpointer data) { - struct _WapiHandle_process *process_handle; + WapiHandle_process *process_handle; DEBUG ("%s", __func__); - process_handle = (struct _WapiHandle_process *) data; - if (process_handle->mono_process && process_handle->self == _wapi_getpid ()) + process_handle = (WapiHandle_process *) data; + g_free (process_handle->proc_name); + process_handle->proc_name = NULL; + if (process_handle->mono_process) InterlockedDecrement (&process_handle->mono_process->handle_count); mono_processes_cleanup (); } @@ -2874,11 +2538,7 @@ MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, sigi int pid; struct MonoProcess *p; -#if DEBUG - fprintf (stdout, "SIG CHILD handler for pid: %i\n", info->si_pid); -#endif - - InterlockedIncrement (&mono_processes_read_lock); + DEBUG ("SIG CHILD handler for pid: %i\n", info->si_pid); do { do { @@ -2888,31 +2548,33 @@ MONO_SIGNAL_HANDLER_FUNC (static, mono_sigchld_signal_handler, (int _dummy, sigi if (pid <= 0) break; -#if DEBUG - fprintf (stdout, "child ended: %i", pid); -#endif - p = mono_processes; - while (p != NULL) { + DEBUG ("child ended: %i", pid); + + /* + * This can run concurrently with the code in the rest of this module. + */ + for (p = mono_processes; p; p = p->next) { if (p->pid == pid) { - p->pid = 0; /* this pid doesn't exist anymore, clear it */ - p->status = status; - MONO_SEM_POST (&p->exit_sem); break; } - p = p->next; + } + if (p) { + p->pid = 0; /* this pid doesn't exist anymore, clear it */ + p->status = status; + MONO_SEM_POST (&p->exit_sem); + mono_memory_barrier (); + /* Mark this as freeable, the pointer becomes invalid afterwards */ + p->freeable = TRUE; } } while (1); - InterlockedDecrement (&mono_processes_read_lock); - -#if DEBUG - fprintf (stdout, "SIG CHILD handler: done looping."); -#endif + DEBUG ("SIG CHILD handler: done looping."); } #endif -static void process_add_sigchld_handler (void) +static void +process_add_sigchld_handler (void) { #if HAVE_SIGACTION struct sigaction sa; @@ -2925,23 +2587,15 @@ static void process_add_sigchld_handler (void) #endif } -static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertable) +static guint32 +process_wait (gpointer handle, guint32 timeout, gboolean alertable) { - struct _WapiHandle_process *process_handle; - gboolean ok; - pid_t pid, ret; + WapiHandle_process *process_handle; + pid_t pid G_GNUC_UNUSED, ret; int status; guint32 start; guint32 now; struct MonoProcess *mp; - gboolean spin; - gpointer current_thread; - - current_thread = wapi_get_current_thread_handle (); - if (current_thread == NULL) { - SetLastError (ERROR_INVALID_HANDLE); - return WAIT_FAILED; - } /* FIXME: We can now easily wait on processes that aren't our own children, * but WaitFor*Object won't call us for pseudo handles. */ @@ -2949,8 +2603,8 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl DEBUG ("%s (%p, %u)", __func__, handle, timeout); - ok = _wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS, (gpointer *)&process_handle); - if (ok == FALSE) { + process_handle = lookup_process_handle (handle); + if (!process_handle) { g_warning ("%s: error looking up process handle %p", __func__, handle); return WAIT_FAILED; } @@ -2968,48 +2622,33 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl /* We don't need to lock mono_processes here, the entry * has a handle_count > 0 which means it will not be freed. */ mp = process_handle->mono_process; - if (mp && process_handle->self != _wapi_getpid ()) { - /* mono_process points to memory in another process' address space: we can't use it */ - mp = NULL; - } + g_assert (mp); start = mono_msec_ticks (); now = start; - spin = mp == NULL; while (1) { - if (mp != NULL) { - /* We have a semaphore we can wait on */ - if (timeout != INFINITE) { - DEBUG ("%s (%p, %u): waiting on semaphore for %li ms...", - __func__, handle, timeout, (timeout - (now - start))); + if (timeout != INFINITE) { + DEBUG ("%s (%p, %u): waiting on semaphore for %li ms...", + __func__, handle, timeout, (timeout - (now - start))); - ret = MONO_SEM_TIMEDWAIT_ALERTABLE (&mp->exit_sem, (timeout - (now - start)), alertable); - } else { - DEBUG ("%s (%p, %u): waiting on semaphore forever...", - __func__, handle, timeout); - ret = MONO_SEM_WAIT_ALERTABLE (&mp->exit_sem, alertable); - } + ret = MONO_SEM_TIMEDWAIT_ALERTABLE (&mp->exit_sem, (timeout - (now - start)), alertable); + } else { + DEBUG ("%s (%p, %u): waiting on semaphore forever...", + __func__, handle, timeout); + ret = MONO_SEM_WAIT_ALERTABLE (&mp->exit_sem, alertable); + } - if (ret == -1 && errno != EINTR && errno != ETIMEDOUT) { - DEBUG ("%s (%p, %u): sem_timedwait failure: %s", - __func__, handle, timeout, g_strerror (errno)); - /* Should we return a failure here? */ - } + if (ret == -1 && errno != EINTR && errno != ETIMEDOUT) { + DEBUG ("%s (%p, %u): sem_timedwait failure: %s", + __func__, handle, timeout, g_strerror (errno)); + /* Should we return a failure here? */ + } - if (ret == 0) { - /* Success, process has exited */ - MONO_SEM_POST (&mp->exit_sem); - break; - } - } else { - /* We did not create this process, so we can't waidpid / sem_wait it. - * We need to poll for the pid existence */ - DEBUG ("%s (%p, %u): polling on pid...", __func__, handle, timeout); - if (!is_pid_valid (pid)) { - /* Success, process has exited */ - break; - } + if (ret == 0) { + /* Success, process has exited */ + MONO_SEM_POST (&mp->exit_sem); + break; } if (timeout == 0) { @@ -3022,14 +2661,8 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl DEBUG ("%s (%p, %u): WAIT_TIMEOUT", __func__, handle, timeout); return WAIT_TIMEOUT; } - - if (spin) { - /* "timeout - (now - start)" will not underflow, since timeout is always >=0, - * and we passed the check just above */ - _wapi_handle_spin (MIN (100, timeout - (now - start))); - } - if (alertable && _wapi_thread_apc_pending (current_thread)) { + if (alertable && _wapi_thread_cur_apc_pending ()) { DEBUG ("%s (%p, %u): WAIT_IO_COMPLETION", __func__, handle, timeout); return WAIT_IO_COMPLETION; } @@ -3042,11 +2675,10 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl g_assert (ret == 0); status = mp ? mp->status : 0; - if (WIFSIGNALED (status)) { + if (WIFSIGNALED (status)) process_handle->exitstatus = 128 + WTERMSIG (status); - } else { + else process_handle->exitstatus = WEXITSTATUS (status); - } _wapi_time_t_to_filetime (time (NULL), &process_handle->exit_time); process_handle->exited = TRUE; @@ -3054,7 +2686,7 @@ static guint32 process_wait (gpointer handle, guint32 timeout, gboolean alertabl DEBUG ("%s (%p, %u): Setting pid %d signalled, exit status %d", __func__, handle, timeout, process_handle->id, process_handle->exitstatus); - _wapi_shared_handle_set_signal_state (handle, TRUE); + _wapi_handle_set_signal_state (handle, TRUE, TRUE); _wapi_handle_unlock_shared_handles ();