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 pipe_stdin pipe to use to send input to child process (or NULL)
123 * @param pipe_stdout pipe to use to get output from child process (or NULL)
124 * @param filename name of the binary
125 * @param ... NULL-terminated list of arguments to the process
126 * @return process ID of the new process, -1 on error
129 GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
130 struct GNUNET_DISK_PipeHandle *pipe_stdout,
131 const char *filename, ...)
133 /* FIXME: Make this work on windows!!! */
146 va_start (ap, filename);
147 while (NULL != va_arg (ap, char *))
150 argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
152 va_start (ap, filename);
153 while (NULL != (argv[argc] = va_arg (ap, char *)))
156 if (pipe_stdout != NULL)
158 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE), &fd_stdout_write, sizeof (int));
159 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_READ), &fd_stdout_read, sizeof (int));
161 if (pipe_stdin != NULL)
163 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_READ), &fd_stdin_read, sizeof (int));
164 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_WRITE), &fd_stdin_write, sizeof (int));
167 #if HAVE_WORKING_VFORK
176 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
181 #if HAVE_WORKING_VFORK
182 /* let's hope vfork actually works; for some extreme cases (including
183 a testcase) we need 'execvp' to have run before we return, since
184 we may send a signal to the process next and we don't want it
185 to be caught by OUR signal handler (but either by the default
186 handler or the actual handler as installed by the process itself). */
188 /* let's give the child process a chance to run execvp, 1s should
189 be plenty in practice */
190 if (pipe_stdout != NULL)
191 GNUNET_DISK_pipe_close_end(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
192 if (pipe_stdin != NULL)
193 GNUNET_DISK_pipe_close_end(pipe_stdin, GNUNET_DISK_PIPE_END_READ);
201 if (pipe_stdout != NULL)
203 dup2(fd_stdout_write, 1);
204 close (fd_stdout_write);
205 close (fd_stdout_read);
208 if (pipe_stdin != NULL)
211 dup2(fd_stdin_read, 0);
212 close (fd_stdin_read);
213 close (fd_stdin_write);
216 execvp (filename, argv);
217 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
224 PROCESS_INFORMATION proc;
227 HANDLE stdout_handle;
233 va_start (ap, filename);
234 while (NULL != (arg = va_arg (ap, char *)))
235 cmdlen = cmdlen + strlen (arg) + 3;
238 cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
239 va_start (ap, filename);
240 while (NULL != (arg = va_arg (ap, char *)))
241 idx += sprintf (idx, "\"%s\" ", arg);
244 memset (&start, 0, sizeof (start));
245 start.cb = sizeof (start);
248 if ((pipe_stdin != NULL) || (pipe_stdout != NULL))
249 start.dwFlags |= STARTF_USESTDHANDLES;
251 if (pipe_stdin != NULL)
253 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_READ), &stdin_handle, sizeof (HANDLE));
254 start.hStdInput = stdin_handle;
257 if (pipe_stdout != NULL)
259 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE), &stdout_handle, sizeof (HANDLE));
260 start.hStdOutput = stdout_handle;
263 len = strlen (filename);
264 if (strnicmp (filename + len - 4, ".exe", 4) == 0)
267 GNUNET_asprintf (&fn, "%s.exe", filename);
270 (fn, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
273 SetErrnoFromWinError (GetLastError ());
274 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", fn);
279 CloseHandle (proc.hProcess);
280 CloseHandle (proc.hThread);
284 return proc.dwProcessId;
294 * @param filename name of the binary
295 * @param argv NULL-terminated list of arguments to the process
296 * @return process ID of the new process, -1 on error
299 GNUNET_OS_start_process_v (const char *filename, char *const argv[])
304 #if HAVE_WORKING_VFORK
313 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
317 #if HAVE_WORKING_VFORK
318 /* let's hope vfork actually works; for some extreme cases (including
319 a testcase) we need 'execvp' to have run before we return, since
320 we may send a signal to the process next and we don't want it
321 to be caught by OUR signal handler (but either by the default
322 handler or the actual handler as installed by the process itself). */
324 /* let's give the child process a chance to run execvp, 1s should
325 be plenty in practice */
331 execvp (filename, argv);
332 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
339 PROCESS_INFORMATION proc;
345 cmdlen = cmdlen + strlen (*arg) + 3;
349 cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
353 idx += sprintf (idx, "\"%s\" ", *arg);
357 memset (&start, 0, sizeof (start));
358 start.cb = sizeof (start);
361 (filename, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
364 SetErrnoFromWinError (GetLastError ());
365 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
368 CloseHandle (proc.hProcess);
369 CloseHandle (proc.hThread);
373 return proc.dwProcessId;
378 * Retrieve the status of a process
379 * @param proc process ID
380 * @param type status type
381 * @param code return code/signal number
382 * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
385 GNUNET_OS_process_status (pid_t proc, enum GNUNET_OS_ProcessStatusType *type,
392 GNUNET_assert (0 != proc);
393 ret = waitpid (proc, &status, WNOHANG);
396 *type = GNUNET_OS_PROCESS_RUNNING;
402 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
403 return GNUNET_SYSERR;
405 if (WIFEXITED (status))
407 *type = GNUNET_OS_PROCESS_EXITED;
408 *code = WEXITSTATUS (status);
410 else if (WIFSIGNALED (status))
412 *type = GNUNET_OS_PROCESS_SIGNALED;
413 *code = WTERMSIG (status);
415 else if (WIFSTOPPED (status))
417 *type = GNUNET_OS_PROCESS_SIGNALED;
418 *code = WSTOPSIG (status);
421 else if (WIFCONTINUED (status))
423 *type = GNUNET_OS_PROCESS_RUNNING;
429 *type = GNUNET_OS_PROCESS_UNKNOWN;
436 h = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, proc);
437 if (INVALID_HANDLE_VALUE == h)
439 SetErrnoFromWinError (GetLastError ());
440 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "OpenProcess");
441 return GNUNET_SYSERR;
444 c = GetExitCodeProcess (proc, &c);
445 if (STILL_ACTIVE == c)
447 *type = GNUNET_OS_PROCESS_RUNNING;
452 *type = GNUNET_OS_PROCESS_EXITED;
462 * @param proc process ID to wait for
463 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
466 GNUNET_OS_process_wait (pid_t proc)
469 if (proc != waitpid (proc, NULL, 0))
470 return GNUNET_SYSERR;
478 h = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, proc);
479 if (INVALID_HANDLE_VALUE == h)
481 SetErrnoFromWinError (GetLastError ());
482 return GNUNET_SYSERR;
485 if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
487 SetErrnoFromWinError (GetLastError ());
500 /* end of os_priority.c */