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;
223 HANDLE stdout_handle;
229 va_start (ap, filename);
230 while (NULL != (arg = va_arg (ap, char *)))
231 cmdlen = cmdlen + strlen (arg) + 3;
234 cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
235 va_start (ap, filename);
236 while (NULL != (arg = va_arg (ap, char *)))
237 idx += sprintf (idx, "\"%s\" ", arg);
240 memset (&start, 0, sizeof (start));
241 start.cb = sizeof (start);
244 if (pipe_stdin != NULL)
246 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_READ), &stdin_handle, sizeof (HANDLE));
247 start.hStdInput = stdin_handle;
250 if (pipe_stdout != NULL)
252 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE), &stdout_handle, sizeof (HANDLE));
253 start.hStdOutput = stdout_handle;
256 len = strlen (filename);
257 if (strnicmp (filename + len - 4, ".exe", 4) == 0)
260 GNUNET_asprintf (&fn, "%s.exe", filename);
263 (fn, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
266 SetErrnoFromWinError (GetLastError ());
267 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", fn);
272 CloseHandle (proc.hProcess);
273 CloseHandle (proc.hThread);
277 return proc.dwProcessId;
287 * @param filename name of the binary
288 * @param argv NULL-terminated list of arguments to the process
289 * @return process ID of the new process, -1 on error
292 GNUNET_OS_start_process_v (const char *filename, char *const argv[])
297 #if HAVE_WORKING_VFORK
306 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
310 #if HAVE_WORKING_VFORK
311 /* let's hope vfork actually works; for some extreme cases (including
312 a testcase) we need 'execvp' to have run before we return, since
313 we may send a signal to the process next and we don't want it
314 to be caught by OUR signal handler (but either by the default
315 handler or the actual handler as installed by the process itself). */
317 /* let's give the child process a chance to run execvp, 1s should
318 be plenty in practice */
324 execvp (filename, argv);
325 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
332 PROCESS_INFORMATION proc;
338 cmdlen = cmdlen + strlen (*arg) + 3;
342 cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
346 idx += sprintf (idx, "\"%s\" ", *arg);
350 memset (&start, 0, sizeof (start));
351 start.cb = sizeof (start);
354 (filename, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
357 SetErrnoFromWinError (GetLastError ());
358 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
361 CloseHandle (proc.hProcess);
362 CloseHandle (proc.hThread);
366 return proc.dwProcessId;
371 * Retrieve the status of a process
372 * @param proc process ID
373 * @param type status type
374 * @param code return code/signal number
375 * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
378 GNUNET_OS_process_status (pid_t proc, enum GNUNET_OS_ProcessStatusType *type,
385 GNUNET_assert (0 != proc);
386 ret = waitpid (proc, &status, WNOHANG);
389 *type = GNUNET_OS_PROCESS_RUNNING;
395 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
396 return GNUNET_SYSERR;
398 if (WIFEXITED (status))
400 *type = GNUNET_OS_PROCESS_EXITED;
401 *code = WEXITSTATUS (status);
403 else if (WIFSIGNALED (status))
405 *type = GNUNET_OS_PROCESS_SIGNALED;
406 *code = WTERMSIG (status);
408 else if (WIFSTOPPED (status))
410 *type = GNUNET_OS_PROCESS_SIGNALED;
411 *code = WSTOPSIG (status);
414 else if (WIFCONTINUED (status))
416 *type = GNUNET_OS_PROCESS_RUNNING;
422 *type = GNUNET_OS_PROCESS_UNKNOWN;
429 h = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, proc);
430 if (INVALID_HANDLE_VALUE == h)
432 SetErrnoFromWinError (GetLastError ());
433 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "OpenProcess");
434 return GNUNET_SYSERR;
437 c = GetExitCodeProcess (proc, &c);
438 if (STILL_ACTIVE == c)
440 *type = GNUNET_OS_PROCESS_RUNNING;
445 *type = GNUNET_OS_PROCESS_EXITED;
455 * @param proc process ID to wait for
456 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
459 GNUNET_OS_process_wait (pid_t proc)
462 if (proc != waitpid (proc, NULL, 0))
463 return GNUNET_SYSERR;
471 h = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, proc);
472 if (INVALID_HANDLE_VALUE == h)
474 SetErrnoFromWinError (GetLastError ());
475 return GNUNET_SYSERR;
478 if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
480 SetErrnoFromWinError (GetLastError ());
493 /* end of os_priority.c */