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!!! */
142 va_start (ap, filename);
143 while (NULL != va_arg (ap, char *))
146 argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
148 va_start (ap, filename);
149 while (NULL != (argv[argc] = va_arg (ap, char *)))
152 if (pipe_stdout != NULL)
154 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE), &fd_stdout_write, sizeof (int));
155 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_READ), &fd_stdout_read, sizeof (int));
157 if (pipe_stdin != NULL)
159 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_READ), &fd_stdin_read, sizeof (int));
160 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_WRITE), &fd_stdin_write, sizeof (int));
163 #if HAVE_WORKING_VFORK
172 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
177 #if HAVE_WORKING_VFORK
178 /* let's hope vfork actually works; for some extreme cases (including
179 a testcase) we need 'execvp' to have run before we return, since
180 we may send a signal to the process next and we don't want it
181 to be caught by OUR signal handler (but either by the default
182 handler or the actual handler as installed by the process itself). */
184 /* let's give the child process a chance to run execvp, 1s should
185 be plenty in practice */
186 if (pipe_stdout != NULL)
187 GNUNET_DISK_pipe_close_end(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
188 if (pipe_stdin != NULL)
189 GNUNET_DISK_pipe_close_end(pipe_stdin, GNUNET_DISK_PIPE_END_READ);
197 if (pipe_stdout != NULL)
199 dup2(fd_stdout_write, 1);
200 close (fd_stdout_write);
201 close (fd_stdout_read);
204 if (pipe_stdin != NULL)
207 dup2(fd_stdin_read, 0);
208 close (fd_stdin_read);
209 close (fd_stdin_write);
212 execvp (filename, argv);
213 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
220 PROCESS_INFORMATION proc;
225 va_start (ap, filename);
226 while (NULL != (arg = va_arg (ap, char *)))
227 cmdlen = cmdlen + strlen (arg) + 3;
230 cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
231 va_start (ap, filename);
232 while (NULL != (arg = va_arg (ap, char *)))
233 idx += sprintf (idx, "\"%s\" ", arg);
236 memset (&start, 0, sizeof (start));
237 start.cb = sizeof (start);
239 len = strlen (filename);
240 if (strnicmp (filename + len - 4, ".exe", 4) == 0)
243 GNUNET_asprintf (&fn, "%s.exe", filename);
246 (fn, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
249 SetErrnoFromWinError (GetLastError ());
250 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", fn);
255 CloseHandle (proc.hProcess);
256 CloseHandle (proc.hThread);
260 return proc.dwProcessId;
270 * @param filename name of the binary
271 * @param argv NULL-terminated list of arguments to the process
272 * @return process ID of the new process, -1 on error
275 GNUNET_OS_start_process_v (const char *filename, char *const argv[])
280 #if HAVE_WORKING_VFORK
289 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
293 #if HAVE_WORKING_VFORK
294 /* let's hope vfork actually works; for some extreme cases (including
295 a testcase) we need 'execvp' to have run before we return, since
296 we may send a signal to the process next and we don't want it
297 to be caught by OUR signal handler (but either by the default
298 handler or the actual handler as installed by the process itself). */
300 /* let's give the child process a chance to run execvp, 1s should
301 be plenty in practice */
307 execvp (filename, argv);
308 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
315 PROCESS_INFORMATION proc;
321 cmdlen = cmdlen + strlen (*arg) + 3;
325 cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
329 idx += sprintf (idx, "\"%s\" ", *arg);
333 memset (&start, 0, sizeof (start));
334 start.cb = sizeof (start);
337 (filename, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
340 SetErrnoFromWinError (GetLastError ());
341 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
344 CloseHandle (proc.hProcess);
345 CloseHandle (proc.hThread);
349 return proc.dwProcessId;
354 * Retrieve the status of a process
355 * @param proc process ID
356 * @param type status type
357 * @param code return code/signal number
358 * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
361 GNUNET_OS_process_status (pid_t proc, enum GNUNET_OS_ProcessStatusType *type,
368 GNUNET_assert (0 != proc);
369 ret = waitpid (proc, &status, WNOHANG);
372 *type = GNUNET_OS_PROCESS_RUNNING;
378 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
379 return GNUNET_SYSERR;
381 if (WIFEXITED (status))
383 *type = GNUNET_OS_PROCESS_EXITED;
384 *code = WEXITSTATUS (status);
386 else if (WIFSIGNALED (status))
388 *type = GNUNET_OS_PROCESS_SIGNALED;
389 *code = WTERMSIG (status);
391 else if (WIFSTOPPED (status))
393 *type = GNUNET_OS_PROCESS_SIGNALED;
394 *code = WSTOPSIG (status);
397 else if (WIFCONTINUED (status))
399 *type = GNUNET_OS_PROCESS_RUNNING;
405 *type = GNUNET_OS_PROCESS_UNKNOWN;
412 h = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, proc);
413 if (INVALID_HANDLE_VALUE == h)
415 SetErrnoFromWinError (GetLastError ());
416 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "OpenProcess");
417 return GNUNET_SYSERR;
420 c = GetExitCodeProcess (proc, &c);
421 if (STILL_ACTIVE == c)
423 *type = GNUNET_OS_PROCESS_RUNNING;
428 *type = GNUNET_OS_PROCESS_EXITED;
438 * @param proc process ID to wait for
439 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
442 GNUNET_OS_process_wait (pid_t proc)
445 if (proc != waitpid (proc, NULL, 0))
446 return GNUNET_SYSERR;
454 h = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, proc);
455 if (INVALID_HANDLE_VALUE == h)
457 SetErrnoFromWinError (GetLastError ());
458 return GNUNET_SYSERR;
461 if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
463 SetErrnoFromWinError (GetLastError ());
476 /* end of os_priority.c */