Implement vararg support for s390. Minor fix to atomic operation for s390.
[mono.git] / mono / io-layer / processes.c
blobd9345cb5733a7272f13af959494244d020a1e9e6
1 /*
2 * processes.c: Process handles
4 * Author:
5 * Dick Porter (dick@ximian.com)
7 * (C) 2002 Ximian, Inc.
8 */
10 #include <config.h>
11 #if HAVE_BOEHM_GC
12 #include <mono/os/gc_wrapper.h>
13 #include "mono/utils/mono-hash.h"
14 #endif
15 #include <glib.h>
16 #include <string.h>
17 #include <pthread.h>
18 #include <sched.h>
19 #include <sys/time.h>
20 #include <errno.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <signal.h>
25 #include <mono/io-layer/wapi.h>
26 #include <mono/io-layer/wapi-private.h>
27 #include <mono/io-layer/handles-private.h>
28 #include <mono/io-layer/misc-private.h>
29 #include <mono/io-layer/mono-mutex.h>
30 #include <mono/io-layer/process-private.h>
31 #include <mono/io-layer/threads.h>
32 #include <mono/utils/strenc.h>
34 /* The process' environment strings */
35 extern char **environ;
37 #undef DEBUG
39 static void process_close_shared (gpointer handle);
41 struct _WapiHandleOps _wapi_process_ops = {
42 process_close_shared, /* close_shared */
43 NULL, /* close_private */
44 NULL, /* signal */
45 NULL, /* own */
46 NULL, /* is_owned */
49 static mono_once_t process_current_once=MONO_ONCE_INIT;
50 static gpointer current_process=NULL;
52 static mono_once_t process_ops_once=MONO_ONCE_INIT;
54 static void process_ops_init (void)
56 _wapi_handle_register_capabilities (WAPI_HANDLE_PROCESS,
57 WAPI_HANDLE_CAP_WAIT);
60 static void process_close_shared (gpointer handle G_GNUC_UNUSED)
62 struct _WapiHandle_process *process_handle;
63 gboolean ok;
65 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
66 (gpointer *)&process_handle, NULL);
67 if(ok==FALSE) {
68 g_warning (G_GNUC_PRETTY_FUNCTION
69 ": error looking up process handle %p", handle);
70 return;
73 #ifdef DEBUG
74 g_message (G_GNUC_PRETTY_FUNCTION
75 ": closing process handle %p with id %d", handle,
76 process_handle->id);
77 #endif
79 if(process_handle->proc_name!=0) {
80 _wapi_handle_scratch_delete (process_handle->proc_name);
81 process_handle->proc_name=0;
85 gboolean CreateProcess (const gunichar2 *appname, gunichar2 *cmdline,
86 WapiSecurityAttributes *process_attrs G_GNUC_UNUSED,
87 WapiSecurityAttributes *thread_attrs G_GNUC_UNUSED,
88 gboolean inherit_handles, guint32 create_flags,
89 gpointer new_environ, const gunichar2 *cwd,
90 WapiStartupInfo *startup,
91 WapiProcessInformation *process_info)
93 gchar *cmd=NULL, *prog = NULL, *full_prog = NULL, *args=NULL, *args_after_prog=NULL, *dir=NULL;
94 guint32 env=0, stored_dir=0, stored_prog=0, i;
95 gboolean ret=FALSE;
96 gpointer stdin_handle, stdout_handle, stderr_handle;
97 guint32 pid, tid;
98 gpointer process_handle, thread_handle;
99 struct _WapiHandle_process *process_handle_data;
101 mono_once (&process_ops_once, process_ops_init);
103 /* appname and cmdline specify the executable and its args:
105 * If appname is not NULL, it is the name of the executable.
106 * Otherwise the executable is the first token in cmdline.
108 * Executable searching:
110 * If appname is not NULL, it can specify the full path and
111 * file name, or else a partial name and the current directory
112 * will be used. There is no additional searching.
114 * If appname is NULL, the first whitespace-delimited token in
115 * cmdline is used. If the name does not contain a full
116 * directory path, the search sequence is:
118 * 1) The directory containing the current process
119 * 2) The current working directory
120 * 3) The windows system directory (Ignored)
121 * 4) The windows directory (Ignored)
122 * 5) $PATH
124 * Just to make things more interesting, tokens can contain
125 * white space if they are surrounded by quotation marks. I'm
126 * beginning to understand just why windows apps are generally
127 * so crap, with an API like this :-(
129 if(appname!=NULL) {
130 cmd=mono_unicode_to_external (appname);
131 if(cmd==NULL) {
132 #ifdef DEBUG
133 g_message (G_GNUC_PRETTY_FUNCTION
134 ": unicode conversion returned NULL");
135 #endif
137 SetLastError(ERROR_PATH_NOT_FOUND);
138 goto cleanup;
141 /* Turn all the slashes round the right way */
142 for(i=0; i<strlen (cmd); i++) {
143 if(cmd[i]=='\\') {
144 cmd[i]='/';
149 if(cmdline!=NULL) {
150 args=mono_unicode_to_external (cmdline);
151 if(args==NULL) {
152 #ifdef DEBUG
153 g_message (G_GNUC_PRETTY_FUNCTION
154 ": unicode conversion returned NULL");
155 #endif
157 SetLastError(ERROR_PATH_NOT_FOUND);
158 goto cleanup;
162 if(cwd!=NULL) {
163 dir=mono_unicode_to_external (cwd);
164 if(dir==NULL) {
165 #ifdef DEBUG
166 g_message (G_GNUC_PRETTY_FUNCTION
167 ": unicode conversion returned NULL");
168 #endif
170 SetLastError(ERROR_PATH_NOT_FOUND);
171 goto cleanup;
174 /* Turn all the slashes round the right way */
175 for(i=0; i<strlen (dir); i++) {
176 if(dir[i]=='\\') {
177 dir[i]='/';
180 } else {
181 dir=g_get_current_dir ();
183 stored_dir=_wapi_handle_scratch_store (dir, strlen (dir));
186 /* new_environ is a block of NULL-terminated strings, which
187 * is itself NULL-terminated. Of course, passing an array of
188 * string pointers would have made things too easy :-(
190 * If new_environ is not NULL it specifies the entire set of
191 * environment variables in the new process. Otherwise the
192 * new process inherits the same environment.
194 if(new_environ!=NULL) {
195 gchar **strings;
196 guint32 count=0;
197 gunichar2 *new_environp;
199 /* Count the number of strings */
200 for(new_environp=(gunichar2 *)new_environ; *new_environp;
201 new_environp++) {
202 count++;
203 while(*new_environp) {
204 new_environp++;
207 strings=g_new0 (gchar *, count + 1); /* +1 -> last one is NULL */
209 /* Copy each environ string into 'strings' turning it
210 * into utf8 (or the requested encoding) at the same
211 * time
213 count=0;
214 for(new_environp=(gunichar2 *)new_environ; *new_environp;
215 new_environp++) {
216 strings[count]=mono_unicode_to_external (new_environp);
217 count++;
218 while(*new_environp) {
219 new_environp++;
223 env=_wapi_handle_scratch_store_string_array (strings);
225 g_strfreev (strings);
226 } else {
227 /* Use the existing environment */
228 env=_wapi_handle_scratch_store_string_array (environ);
231 /* We can't put off locating the executable any longer :-( */
232 if(cmd!=NULL) {
233 gchar *unquoted;
234 if(g_ascii_isalpha (cmd[0]) && (cmd[1]==':')) {
235 /* Strip off the drive letter. I can't
236 * believe that CP/M holdover is still
237 * visible...
239 g_memmove (cmd, cmd+2, strlen (cmd)-2);
240 cmd[strlen (cmd)-2]='\0';
243 unquoted = g_shell_unquote (cmd, NULL);
244 if(unquoted[0]=='/') {
245 /* Assume full path given */
246 prog=g_strdup (unquoted);
248 /* Executable existing ? */
249 if(access (prog, X_OK)!=0) {
250 #ifdef DEBUG
251 g_message (G_GNUC_PRETTY_FUNCTION ": Couldn't find executable %s", prog);
252 #endif
253 g_free (prog);
254 g_free (unquoted);
255 SetLastError (ERROR_FILE_NOT_FOUND);
256 goto cleanup;
258 } else {
259 /* Search for file named by cmd in the current
260 * directory
262 char *curdir=g_get_current_dir ();
264 prog=g_strdup_printf ("%s/%s", curdir, unquoted);
265 g_free (unquoted);
266 g_free (curdir);
269 args_after_prog=args;
270 } else {
271 gchar *token=NULL;
272 char quote;
274 /* Dig out the first token from args, taking quotation
275 * marks into account
278 /* First, strip off all leading whitespace */
279 args=g_strchug (args);
281 /* args_after_prog points to the contents of args
282 * after token has been set (otherwise argv[0] is
283 * duplicated)
285 args_after_prog=args;
287 /* Assume the opening quote will always be the first
288 * character
290 if(args[0]=='\"' || args [0] == '\'') {
291 quote = args [0];
292 for(i=1; args[i]!='\0' && args[i]!=quote; i++);
293 if(g_ascii_isspace (args[i+1])) {
294 /* We found the first token */
295 token=g_strndup (args+1, i-1);
296 args_after_prog=args+i;
297 } else {
298 /* Quotation mark appeared in the
299 * middle of the token. Just give the
300 * whole first token, quotes and all,
301 * to exec.
306 if(token==NULL) {
307 /* No quote mark, or malformed */
308 for(i=0; args[i]!='\0'; i++) {
309 if(g_ascii_isspace (args[i])) {
310 token=g_strndup (args, i);
311 args_after_prog=args+i+1;
312 break;
317 if(token==NULL && args[0]!='\0') {
318 /* Must be just one token in the string */
319 token=g_strdup (args);
320 args_after_prog=NULL;
323 if(token==NULL) {
324 /* Give up */
325 #ifdef DEBUG
326 g_message (G_GNUC_PRETTY_FUNCTION
327 ": Couldn't find what to exec");
328 #endif
330 SetLastError(ERROR_PATH_NOT_FOUND);
331 goto cleanup;
334 /* Turn all the slashes round the right way. Only for the prg. name */
335 for(i=0; i < strlen (token); i++) {
336 if (token[i]=='\\') {
337 token[i]='/';
341 if(g_ascii_isalpha (token[0]) && (token[1]==':')) {
342 /* Strip off the drive letter. I can't
343 * believe that CP/M holdover is still
344 * visible...
346 g_memmove (token, token+2, strlen (token)-2);
347 token[strlen (token)-2]='\0';
350 if(token[0]=='/') {
351 /* Assume full path given */
352 prog=g_strdup (token);
354 /* Executable existing ? */
355 if(access (prog, X_OK)!=0) {
356 g_free (prog);
357 #ifdef DEBUG
358 g_message (G_GNUC_PRETTY_FUNCTION ": Couldn't find executable %s", token);
359 #endif
360 g_free (token);
361 SetLastError (ERROR_FILE_NOT_FOUND);
362 goto cleanup;
365 } else {
366 char *curdir=g_get_current_dir ();
368 /* FIXME: Need to record the directory
369 * containing the current process, and check
370 * that for the new executable as the first
371 * place to look
374 prog=g_strdup_printf ("%s/%s", curdir, token);
375 g_free (curdir);
377 /* I assume X_OK is the criterion to use,
378 * rather than F_OK
380 if(access (prog, X_OK)!=0) {
381 g_free (prog);
382 prog=g_find_program_in_path (token);
383 if(prog==NULL) {
384 #ifdef DEBUG
385 g_message (G_GNUC_PRETTY_FUNCTION ": Couldn't find executable %s", token);
386 #endif
388 g_free (token);
389 SetLastError (ERROR_FILE_NOT_FOUND);
390 goto cleanup;
395 g_free (token);
398 #ifdef DEBUG
399 g_message (G_GNUC_PRETTY_FUNCTION ": Exec prog [%s] args [%s]", prog,
400 args_after_prog);
401 #endif
403 if(args_after_prog!=NULL && *args_after_prog) {
404 gchar *qprog;
406 qprog = g_shell_quote (prog);
407 full_prog=g_strconcat (qprog, " ", args_after_prog, NULL);
408 g_free (qprog);
409 } else {
410 full_prog=g_shell_quote (prog);
413 stored_prog=_wapi_handle_scratch_store (full_prog, strlen (full_prog));
415 if(startup!=NULL && startup->dwFlags & STARTF_USESTDHANDLES) {
416 stdin_handle=startup->hStdInput;
417 stdout_handle=startup->hStdOutput;
418 stderr_handle=startup->hStdError;
419 } else {
420 stdin_handle=GetStdHandle (STD_INPUT_HANDLE);
421 stdout_handle=GetStdHandle (STD_OUTPUT_HANDLE);
422 stderr_handle=GetStdHandle (STD_ERROR_HANDLE);
425 ret=_wapi_handle_process_fork (stored_prog, env, stored_dir,
426 inherit_handles, create_flags,
427 stdin_handle, stdout_handle,
428 stderr_handle, &process_handle,
429 &thread_handle, &pid, &tid);
431 if(ret==TRUE && process_info!=NULL) {
432 process_info->hProcess=process_handle;
433 process_info->hThread=thread_handle;
434 process_info->dwProcessId=pid;
435 process_info->dwThreadId=tid;
436 /* Wait for possible execve failure */
437 if (WaitForSingleObjectEx (process_handle, 500, FALSE) != WAIT_TIMEOUT) {
438 _wapi_lookup_handle (GUINT_TO_POINTER (process_handle),
439 WAPI_HANDLE_PROCESS,
440 (gpointer *) &process_handle_data,
441 NULL);
443 if (process_handle_data && process_handle_data->exec_errno != 0) {
444 ret = FALSE;
445 SetLastError (ERROR_PATH_NOT_FOUND);
448 } else if (ret==FALSE) {
449 /* FIXME: work out a better error code
451 SetLastError (ERROR_PATH_NOT_FOUND);
454 cleanup:
455 if(cmd!=NULL) {
456 g_free (cmd);
458 if(full_prog!=NULL) {
459 g_free (prog);
461 if(stored_prog!=0) {
462 _wapi_handle_scratch_delete (stored_prog);
464 if(args!=NULL) {
465 g_free (args);
467 if(dir!=NULL) {
468 g_free (dir);
470 if(stored_dir!=0) {
471 _wapi_handle_scratch_delete (stored_dir);
473 if(env!=0) {
474 _wapi_handle_scratch_delete_string_array (env);
477 return(ret);
480 static void process_set_name (struct _WapiHandle_process *process_handle)
482 gchar *progname, *utf8_progname, *slash;
484 progname=g_get_prgname ();
485 utf8_progname=mono_utf8_from_external (progname);
487 #ifdef DEBUG
488 g_message (G_GNUC_PRETTY_FUNCTION ": using [%s] as prog name",
489 progname);
490 #endif
492 if(utf8_progname!=NULL) {
493 slash=strrchr (utf8_progname, '/');
494 if(slash!=NULL) {
495 process_handle->proc_name=_wapi_handle_scratch_store (slash+1, strlen (slash+1));
496 } else {
497 process_handle->proc_name=_wapi_handle_scratch_store (utf8_progname, strlen (utf8_progname));
500 g_free (utf8_progname);
504 extern void _wapi_time_t_to_filetime (time_t timeval, WapiFileTime *filetime);
506 static void process_set_current (void)
508 struct _WapiHandle_process *process_handle;
509 gboolean ok;
510 pid_t pid=getpid ();
511 char *handle_env;
513 handle_env=getenv ("_WAPI_PROCESS_HANDLE");
514 if(handle_env==NULL) {
515 #ifdef DEBUG
516 g_message (G_GNUC_PRETTY_FUNCTION
517 ": Need to create my own process handle");
518 #endif
520 current_process=_wapi_handle_new (WAPI_HANDLE_PROCESS);
521 if(current_process==_WAPI_HANDLE_INVALID) {
522 g_warning (G_GNUC_PRETTY_FUNCTION
523 ": error creating process handle");
524 return;
527 ok=_wapi_lookup_handle (current_process, WAPI_HANDLE_PROCESS,
528 (gpointer *)&process_handle, NULL);
529 if(ok==FALSE) {
530 g_warning (G_GNUC_PRETTY_FUNCTION
531 ": error looking up process handle %p",
532 current_process);
533 return;
536 process_handle->id=pid;
538 /* These seem to be the defaults on w2k */
539 process_handle->min_working_set=204800;
540 process_handle->max_working_set=1413120;
542 _wapi_time_t_to_filetime (time (NULL), &process_handle->create_time);
544 process_set_name (process_handle);
546 /* Make sure the new handle has a reference so it wont go away
547 * until this process exits
549 _wapi_handle_ref (current_process);
550 } else {
551 guchar *procname;
553 current_process=GUINT_TO_POINTER (atoi (handle_env));
555 #ifdef DEBUG
556 g_message (G_GNUC_PRETTY_FUNCTION
557 ": Found my process handle: %p", current_process);
558 #endif
560 ok=_wapi_lookup_handle (current_process, WAPI_HANDLE_PROCESS,
561 (gpointer *)&process_handle, NULL);
562 if(ok==FALSE) {
563 g_warning (G_GNUC_PRETTY_FUNCTION
564 ": error looking up process handle %p",
565 current_process);
566 return;
569 procname=_wapi_handle_scratch_lookup (process_handle->proc_name);
570 if(procname!=NULL) {
571 if(!strcmp (procname, "mono")) {
572 /* Set a better process name */
573 #ifdef DEBUG
574 g_message (G_GNUC_PRETTY_FUNCTION ": Setting better process name");
575 #endif
577 _wapi_handle_scratch_delete (process_handle->proc_name);
578 process_set_name (process_handle);
579 } else {
580 #ifdef DEBUG
581 g_message (G_GNUC_PRETTY_FUNCTION
582 ": Leaving process name: %s",
583 procname);
584 #endif
587 g_free (procname);
592 /* Returns a pseudo handle that doesn't need to be closed afterwards */
593 gpointer GetCurrentProcess (void)
595 mono_once (&process_current_once, process_set_current);
597 return((gpointer)-1);
600 guint32 GetCurrentProcessId (void)
602 struct _WapiHandle_process *current_process_handle;
603 gboolean ok;
605 mono_once (&process_current_once, process_set_current);
607 ok=_wapi_lookup_handle (current_process, WAPI_HANDLE_PROCESS,
608 (gpointer *)&current_process_handle, NULL);
609 if(ok==FALSE) {
610 g_warning (G_GNUC_PRETTY_FUNCTION
611 ": error looking up current process handle %p",
612 current_process);
613 /* No failure return is defined. PID 0 is invalid.
614 * This should only be reached when something else has
615 * gone badly wrong anyway.
617 return(0);
620 return(current_process_handle->id);
623 static gboolean process_enum (gpointer handle, gpointer user_data)
625 GPtrArray *processes=user_data;
627 /* Ignore processes that have already exited (ie they are signalled) */
628 if(_wapi_handle_issignalled (handle)==FALSE) {
629 g_ptr_array_add (processes, handle);
632 /* Return false to keep searching */
633 return(FALSE);
636 gboolean EnumProcesses (guint32 *pids, guint32 len, guint32 *needed)
638 GPtrArray *processes=g_ptr_array_new ();
639 guint32 fit, i;
641 mono_once (&process_current_once, process_set_current);
643 _wapi_search_handle (WAPI_HANDLE_PROCESS, process_enum, processes,
644 NULL, NULL);
646 fit=len/sizeof(guint32);
647 for(i=0; i<fit && i<processes->len; i++) {
648 struct _WapiHandle_process *process_handle;
649 gboolean ok;
651 ok=_wapi_lookup_handle (g_ptr_array_index (processes, i),
652 WAPI_HANDLE_PROCESS,
653 (gpointer *)&process_handle, NULL);
654 if(ok==FALSE) {
655 g_warning (G_GNUC_PRETTY_FUNCTION ": error looking up process handle %p", g_ptr_array_index (processes, i));
656 g_ptr_array_free (processes, FALSE);
657 return(FALSE);
660 pids[i]=process_handle->id;
663 g_ptr_array_free (processes, FALSE);
665 *needed=i*sizeof(guint32);
667 return(TRUE);
670 static gboolean process_open_compare (gpointer handle, gpointer user_data)
672 struct _WapiHandle_process *process_handle;
673 gboolean ok;
674 pid_t pid;
676 ok=_wapi_lookup_handle (handle, WAPI_HANDLE_PROCESS,
677 (gpointer *)&process_handle, NULL);
678 if(ok==FALSE) {
679 g_warning (G_GNUC_PRETTY_FUNCTION
680 ": error looking up process handle %p", handle);
681 return(FALSE);
684 pid=GPOINTER_TO_UINT (user_data);
686 /* It's possible to have more than one process handle with the
687 * same pid, but only the one running process can be
688 * unsignalled
690 if(process_handle->id==pid &&
691 _wapi_handle_issignalled (handle)==FALSE) {
692 return(TRUE);
693 } else {
694 return(FALSE);
698 gpointer OpenProcess (guint32 access G_GNUC_UNUSED, gboolean inherit G_GNUC_UNUSED, guint32 pid)
700 /* Find the process handle that corresponds to pid */
701 gpointer handle;
703 mono_once (&process_current_once, process_set_current);
705 handle=_wapi_search_handle (WAPI_HANDLE_PROCESS, process_open_compare,
706 GUINT_TO_POINTER (pid), NULL, NULL);
707 if(handle==0) {
708 #ifdef DEBUG
709 g_message (G_GNUC_PRETTY_FUNCTION ": Can't find pid %d", pid);
710 #endif
712 /* Set an error code */
714 return(NULL);
717 _wapi_handle_ref (handle);
719 return(handle);
722 gboolean GetExitCodeProcess (gpointer process, guint32 *code)
724 struct _WapiHandle_process *process_handle;
725 gboolean ok;
727 mono_once (&process_current_once, process_set_current);
729 if(code==NULL) {
730 return(FALSE);
733 ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
734 (gpointer *)&process_handle, NULL);
735 if(ok==FALSE) {
736 #ifdef DEBUG
737 g_message (G_GNUC_PRETTY_FUNCTION ": Can't find process %p",
738 process);
739 #endif
741 return(FALSE);
744 /* A process handle is only signalled if the process has exited */
745 if(_wapi_handle_issignalled (process)==TRUE) {
746 *code=process_handle->exitstatus;
747 } else {
748 *code=STILL_ACTIVE;
751 return(TRUE);
754 gboolean GetProcessTimes (gpointer process, WapiFileTime *create_time,
755 WapiFileTime *exit_time, WapiFileTime *kernel_time,
756 WapiFileTime *user_time)
758 struct _WapiHandle_process *process_handle;
759 gboolean ok;
761 mono_once (&process_current_once, process_set_current);
763 if(create_time==NULL || exit_time==NULL || kernel_time==NULL ||
764 user_time==NULL) {
765 /* Not sure if w32 allows NULLs here or not */
766 return(FALSE);
769 ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
770 (gpointer *)&process_handle, NULL);
771 if(ok==FALSE) {
772 #ifdef DEBUG
773 g_message (G_GNUC_PRETTY_FUNCTION ": Can't find process %p",
774 process);
775 #endif
777 return(FALSE);
780 *create_time=process_handle->create_time;
782 /* A process handle is only signalled if the process has
783 * exited. Otherwise exit_time isn't set
785 if(_wapi_handle_issignalled (process)==TRUE) {
786 *exit_time=process_handle->exit_time;
789 return(TRUE);
792 gboolean EnumProcessModules (gpointer process, gpointer *modules,
793 guint32 size, guint32 *needed)
795 /* Store modules in an array of pointers (main module as
796 * modules[0]), using the load address for each module as a
797 * token. (Use 'NULL' as an alternative for the main module
798 * so that the simple implementation can just return one item
799 * for now.) Get the info from /proc/<pid>/maps on linux,
800 * other systems will have to implement /dev/kmem reading or
801 * whatever other horrid technique is needed.
803 if(size<sizeof(gpointer)) {
804 return(FALSE);
807 #ifdef linux
808 modules[0]=NULL;
809 *needed=sizeof(gpointer);
810 #else
811 modules[0]=NULL;
812 *needed=sizeof(gpointer);
813 #endif
815 return(TRUE);
818 guint32 GetModuleBaseName (gpointer process, gpointer module,
819 gunichar2 *basename, guint32 size)
821 struct _WapiHandle_process *process_handle;
822 gboolean ok;
824 mono_once (&process_current_once, process_set_current);
826 #ifdef DEBUG
827 g_message (G_GNUC_PRETTY_FUNCTION
828 ": Getting module base name, process handle %p module %p",
829 process, module);
830 #endif
832 if(basename==NULL || size==0) {
833 return(FALSE);
836 ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
837 (gpointer *)&process_handle, NULL);
838 if(ok==FALSE) {
839 #ifdef DEBUG
840 g_message (G_GNUC_PRETTY_FUNCTION ": Can't find process %p",
841 process);
842 #endif
844 return(FALSE);
847 if(module==NULL) {
848 /* Shorthand for the main module, which has the
849 * process name recorded in the handle data
851 pid_t pid;
852 gunichar2 *procname;
853 guchar *procname_utf8;
854 glong len, bytes;
856 #ifdef DEBUG
857 g_message (G_GNUC_PRETTY_FUNCTION
858 ": Returning main module name");
859 #endif
861 pid=process_handle->id;
862 procname_utf8=_wapi_handle_scratch_lookup (process_handle->proc_name);
864 #ifdef DEBUG
865 g_message (G_GNUC_PRETTY_FUNCTION ": Process name is [%s]",
866 procname_utf8);
867 #endif
869 procname=g_utf8_to_utf16 (procname_utf8, -1, NULL, &len, NULL);
870 if(procname==NULL) {
871 /* bugger */
872 g_free (procname_utf8);
873 return(0);
876 /* Add the terminator, and convert chars to bytes */
877 bytes=(len+1)*2;
879 if(size<bytes) {
880 #ifdef DEBUG
881 g_message (G_GNUC_PRETTY_FUNCTION ": Size %d smaller than needed (%ld); truncating", size, bytes);
882 #endif
884 memcpy (basename, procname, size);
885 } else {
886 #ifdef DEBUG
887 g_message (G_GNUC_PRETTY_FUNCTION
888 ": Size %d larger than needed (%ld)",
889 size, bytes);
890 #endif
892 memcpy (basename, procname, bytes);
895 g_free (procname_utf8);
896 g_free (procname);
898 return(len);
899 } else {
900 /* Look up the address in /proc/<pid>/maps */
903 return(0);
906 gboolean GetProcessWorkingSetSize (gpointer process, size_t *min, size_t *max)
908 struct _WapiHandle_process *process_handle;
909 gboolean ok;
911 mono_once (&process_current_once, process_set_current);
913 if(min==NULL || max==NULL) {
914 /* Not sure if w32 allows NULLs here or not */
915 return(FALSE);
918 ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
919 (gpointer *)&process_handle, NULL);
920 if(ok==FALSE) {
921 #ifdef DEBUG
922 g_message (G_GNUC_PRETTY_FUNCTION ": Can't find process %p",
923 process);
924 #endif
926 return(FALSE);
929 *min=process_handle->min_working_set;
930 *max=process_handle->max_working_set;
932 return(TRUE);
935 gboolean SetProcessWorkingSetSize (gpointer process, size_t min, size_t max)
937 struct _WapiHandle_process *process_handle;
938 gboolean ok;
940 mono_once (&process_current_once, process_set_current);
942 ok=_wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
943 (gpointer *)&process_handle, NULL);
944 if(ok==FALSE) {
945 #ifdef DEBUG
946 g_message (G_GNUC_PRETTY_FUNCTION ": Can't find process %p",
947 process);
948 #endif
950 return(FALSE);
953 process_handle->min_working_set=min;
954 process_handle->max_working_set=max;
956 return(TRUE);
960 gboolean
961 TerminateProcess (gpointer process, gint32 exitCode)
963 struct _WapiHandle_process *process_handle;
964 gboolean ok;
965 gint signo;
966 gint err;
968 ok = _wapi_lookup_handle (process, WAPI_HANDLE_PROCESS,
969 (gpointer *) &process_handle, NULL);
971 if (ok == FALSE) {
972 #ifdef DEBUG
973 g_message (G_GNUC_PRETTY_FUNCTION ": Can't find process %p",
974 process);
975 #endif
976 SetLastError (ERROR_INVALID_HANDLE);
977 return FALSE;
980 signo = (exitCode == -1) ? SIGKILL : SIGTERM;
981 return _wapi_handle_process_kill (process_handle->id, signo, &err);