2 This file is part of GNUnet
3 (C) 2002, 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file util/os_priority.c
23 * @brief Methods to set process priority
28 #include "gnunet_common.h"
29 #include "gnunet_os_lib.h"
33 * Set process priority
35 * @param proc id of the process
36 * @param prio priority value
37 * @return GNUNET_OK on success, GNUNET_SYSERR on error
40 GNUNET_OS_set_process_priority (pid_t proc,
41 enum GNUNET_SCHEDULER_Priority prio)
45 GNUNET_assert (prio < GNUNET_SCHEDULER_PRIORITY_COUNT);
46 if (prio == GNUNET_SCHEDULER_PRIORITY_KEEP)
48 /* convert to MINGW/Unix values */
51 case GNUNET_SCHEDULER_PRIORITY_DEFAULT:
53 rprio = NORMAL_PRIORITY_CLASS;
58 case GNUNET_SCHEDULER_PRIORITY_HIGH:
60 rprio = ABOVE_NORMAL_PRIORITY_CLASS;
65 case GNUNET_SCHEDULER_PRIORITY_BACKGROUND:
67 rprio = BELOW_NORMAL_PRIORITY_CLASS;
72 case GNUNET_SCHEDULER_PRIORITY_UI:
73 case GNUNET_SCHEDULER_PRIORITY_URGENT:
75 rprio = HIGH_PRIORITY_CLASS;
80 case GNUNET_SCHEDULER_PRIORITY_IDLE:
82 rprio = IDLE_PRIORITY_CLASS;
91 /* Set process priority */
93 SetPriorityClass (GetCurrentProcess (), rprio);
95 if (proc == getpid ())
98 if ((-1 == nice (rprio)) && (errno != 0))
100 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING |
101 GNUNET_ERROR_TYPE_BULK, "nice");
102 return GNUNET_SYSERR;
107 if (0 != setpriority (PRIO_PROCESS, proc, rprio))
110 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING |
111 GNUNET_ERROR_TYPE_BULK, "setpriority");
112 return GNUNET_SYSERR;
122 * @param filename name of the binary
123 * @param ... NULL-terminated list of arguments to the process
124 * @return process ID of the new process, -1 on error
127 GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, const char *filename, ...)
129 /* FIXME: Make this work on windows!!! */
130 /* FIXME: Make this work with stdin as well as stdout! */
141 va_start (ap, filename);
142 while (NULL != va_arg (ap, char *))
145 argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
147 va_start (ap, filename);
148 while (NULL != (argv[argc] = va_arg (ap, char *)))
151 if (pipe_stdout != NULL)
152 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE), &fd_stdout_write, sizeof (int));
153 if (pipe_stdin != NULL)
154 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_READ), &fd_stdin_read, sizeof (int));
156 #if HAVE_WORKING_VFORK
165 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
169 #if HAVE_WORKING_VFORK
170 /* let's hope vfork actually works; for some extreme cases (including
171 a testcase) we need 'execvp' to have run before we return, since
172 we may send a signal to the process next and we don't want it
173 to be caught by OUR signal handler (but either by the default
174 handler or the actual handler as installed by the process itself). */
176 /* let's give the child process a chance to run execvp, 1s should
177 be plenty in practice */
179 if (pipe_stdout != NULL)
180 GNUNET_DISK_pipe_close_end(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
181 if (pipe_stdin != NULL)
182 GNUNET_DISK_pipe_close_end(pipe_stdin, GNUNET_DISK_PIPE_END_READ);
189 if (pipe_stdout != NULL)
191 dup2(fd_stdout_write, 1);
192 close (fd_stdout_write);
195 if (pipe_stdout != NULL)
197 dup2(fd_stdin_read, 0);
198 close (fd_stdin_read);
201 execvp (filename, argv);
202 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
209 PROCESS_INFORMATION proc;
214 va_start (ap, filename);
215 while (NULL != (arg = va_arg (ap, char *)))
216 cmdlen = cmdlen + strlen (arg) + 3;
219 cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
220 va_start (ap, filename);
221 while (NULL != (arg = va_arg (ap, char *)))
222 idx += sprintf (idx, "\"%s\" ", arg);
225 memset (&start, 0, sizeof (start));
226 start.cb = sizeof (start);
228 len = strlen (filename);
229 if (strnicmp (filename + len - 4, ".exe", 4) == 0)
232 GNUNET_asprintf (&fn, "%s.exe", filename);
235 (fn, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
238 SetErrnoFromWinError (GetLastError ());
239 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", fn);
244 CloseHandle (proc.hProcess);
245 CloseHandle (proc.hThread);
249 return proc.dwProcessId;
259 * @param filename name of the binary
260 * @param argv NULL-terminated list of arguments to the process
261 * @return process ID of the new process, -1 on error
264 GNUNET_OS_start_process_v (const char *filename, char *const argv[])
269 #if HAVE_WORKING_VFORK
278 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
282 #if HAVE_WORKING_VFORK
283 /* let's hope vfork actually works; for some extreme cases (including
284 a testcase) we need 'execvp' to have run before we return, since
285 we may send a signal to the process next and we don't want it
286 to be caught by OUR signal handler (but either by the default
287 handler or the actual handler as installed by the process itself). */
289 /* let's give the child process a chance to run execvp, 1s should
290 be plenty in practice */
296 execvp (filename, argv);
297 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
304 PROCESS_INFORMATION proc;
310 cmdlen = cmdlen + strlen (*arg) + 3;
314 cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
318 idx += sprintf (idx, "\"%s\" ", *arg);
322 memset (&start, 0, sizeof (start));
323 start.cb = sizeof (start);
326 (filename, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
329 SetErrnoFromWinError (GetLastError ());
330 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
333 CloseHandle (proc.hProcess);
334 CloseHandle (proc.hThread);
338 return proc.dwProcessId;
343 * Retrieve the status of a process
344 * @param proc process ID
345 * @param type status type
346 * @param code return code/signal number
347 * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
350 GNUNET_OS_process_status (pid_t proc, enum GNUNET_OS_ProcessStatusType *type,
357 GNUNET_assert (0 != proc);
358 ret = waitpid (proc, &status, WNOHANG);
361 *type = GNUNET_OS_PROCESS_RUNNING;
367 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
368 return GNUNET_SYSERR;
370 if (WIFEXITED (status))
372 *type = GNUNET_OS_PROCESS_EXITED;
373 *code = WEXITSTATUS (status);
375 else if (WIFSIGNALED (status))
377 *type = GNUNET_OS_PROCESS_SIGNALED;
378 *code = WTERMSIG (status);
380 else if (WIFSTOPPED (status))
382 *type = GNUNET_OS_PROCESS_SIGNALED;
383 *code = WSTOPSIG (status);
386 else if (WIFCONTINUED (status))
388 *type = GNUNET_OS_PROCESS_RUNNING;
394 *type = GNUNET_OS_PROCESS_UNKNOWN;
401 h = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, proc);
402 if (INVALID_HANDLE_VALUE == h)
404 SetErrnoFromWinError (GetLastError ());
405 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "OpenProcess");
406 return GNUNET_SYSERR;
409 c = GetExitCodeProcess (proc, &c);
410 if (STILL_ACTIVE == c)
412 *type = GNUNET_OS_PROCESS_RUNNING;
417 *type = GNUNET_OS_PROCESS_EXITED;
427 * @param proc process ID to wait for
428 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
431 GNUNET_OS_process_wait (pid_t proc)
434 if (proc != waitpid (proc, NULL, 0))
435 return GNUNET_SYSERR;
443 h = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, proc);
444 if (INVALID_HANDLE_VALUE == h)
446 SetErrnoFromWinError (GetLastError ());
447 return GNUNET_SYSERR;
450 if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
452 SetErrnoFromWinError (GetLastError ());
465 /* end of os_priority.c */