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!!! */
140 va_start (ap, filename);
141 while (NULL != va_arg (ap, char *))
144 argv = GNUNET_malloc (sizeof (char *) * (argc + 1));
146 va_start (ap, filename);
147 while (NULL != (argv[argc] = va_arg (ap, char *)))
150 if (pipe_stdout != NULL)
151 GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE), &fd_stdout_write, sizeof (int));
153 #if HAVE_WORKING_VFORK
162 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
166 #if HAVE_WORKING_VFORK
167 /* let's hope vfork actually works; for some extreme cases (including
168 a testcase) we need 'execvp' to have run before we return, since
169 we may send a signal to the process next and we don't want it
170 to be caught by OUR signal handler (but either by the default
171 handler or the actual handler as installed by the process itself). */
173 /* let's give the child process a chance to run execvp, 1s should
174 be plenty in practice */
176 if (pipe_stdout != NULL)
177 GNUNET_DISK_pipe_close_end(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
183 if (pipe_stdout != NULL)
185 dup2(fd_stdout_write, 1);
186 close (fd_stdout_write);
189 execvp (filename, argv);
190 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
197 PROCESS_INFORMATION proc;
202 va_start (ap, filename);
203 while (NULL != (arg = va_arg (ap, char *)))
204 cmdlen = cmdlen + strlen (arg) + 3;
207 cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
208 va_start (ap, filename);
209 while (NULL != (arg = va_arg (ap, char *)))
210 idx += sprintf (idx, "\"%s\" ", arg);
213 memset (&start, 0, sizeof (start));
214 start.cb = sizeof (start);
216 len = strlen (filename);
217 if (strnicmp (filename + len - 4, ".exe", 4) == 0)
220 GNUNET_asprintf (&fn, "%s.exe", filename);
223 (fn, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
226 SetErrnoFromWinError (GetLastError ());
227 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", fn);
232 CloseHandle (proc.hProcess);
233 CloseHandle (proc.hThread);
237 return proc.dwProcessId;
247 * @param filename name of the binary
248 * @param argv NULL-terminated list of arguments to the process
249 * @return process ID of the new process, -1 on error
252 GNUNET_OS_start_process_v (const char *filename, char *const argv[])
257 #if HAVE_WORKING_VFORK
266 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
270 #if HAVE_WORKING_VFORK
271 /* let's hope vfork actually works; for some extreme cases (including
272 a testcase) we need 'execvp' to have run before we return, since
273 we may send a signal to the process next and we don't want it
274 to be caught by OUR signal handler (but either by the default
275 handler or the actual handler as installed by the process itself). */
277 /* let's give the child process a chance to run execvp, 1s should
278 be plenty in practice */
284 execvp (filename, argv);
285 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "execvp", filename);
292 PROCESS_INFORMATION proc;
298 cmdlen = cmdlen + strlen (*arg) + 3;
302 cmd = idx = GNUNET_malloc (sizeof (char) * cmdlen);
306 idx += sprintf (idx, "\"%s\" ", *arg);
310 memset (&start, 0, sizeof (start));
311 start.cb = sizeof (start);
314 (filename, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
317 SetErrnoFromWinError (GetLastError ());
318 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
321 CloseHandle (proc.hProcess);
322 CloseHandle (proc.hThread);
326 return proc.dwProcessId;
331 * Retrieve the status of a process
332 * @param proc process ID
333 * @param type status type
334 * @param code return code/signal number
335 * @return GNUNET_OK on success, GNUNET_NO if the process is still running, GNUNET_SYSERR otherwise
338 GNUNET_OS_process_status (pid_t proc, enum GNUNET_OS_ProcessStatusType *type,
345 GNUNET_assert (0 != proc);
346 ret = waitpid (proc, &status, WNOHANG);
349 *type = GNUNET_OS_PROCESS_RUNNING;
355 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid");
356 return GNUNET_SYSERR;
358 if (WIFEXITED (status))
360 *type = GNUNET_OS_PROCESS_EXITED;
361 *code = WEXITSTATUS (status);
363 else if (WIFSIGNALED (status))
365 *type = GNUNET_OS_PROCESS_SIGNALED;
366 *code = WTERMSIG (status);
368 else if (WIFSTOPPED (status))
370 *type = GNUNET_OS_PROCESS_SIGNALED;
371 *code = WSTOPSIG (status);
374 else if (WIFCONTINUED (status))
376 *type = GNUNET_OS_PROCESS_RUNNING;
382 *type = GNUNET_OS_PROCESS_UNKNOWN;
389 h = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, proc);
390 if (INVALID_HANDLE_VALUE == h)
392 SetErrnoFromWinError (GetLastError ());
393 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "OpenProcess");
394 return GNUNET_SYSERR;
397 c = GetExitCodeProcess (proc, &c);
398 if (STILL_ACTIVE == c)
400 *type = GNUNET_OS_PROCESS_RUNNING;
405 *type = GNUNET_OS_PROCESS_EXITED;
415 * @param proc process ID to wait for
416 * @return GNUNET_OK on success, GNUNET_SYSERR otherwise
419 GNUNET_OS_process_wait (pid_t proc)
422 if (proc != waitpid (proc, NULL, 0))
423 return GNUNET_SYSERR;
431 h = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, proc);
432 if (INVALID_HANDLE_VALUE == h)
434 SetErrnoFromWinError (GetLastError ());
435 return GNUNET_SYSERR;
438 if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE))
440 SetErrnoFromWinError (GetLastError ());
453 /* end of os_priority.c */