GitHub Actions: Try MSVC builds with /std:c++17 and 20
[ACE_TAO.git] / ACE / ace / Process_Manager.h
blobdbfd2b06808968cca9468fdcbeb2435708ce5f9c
1 // -*- C++ -*-
3 //=============================================================================
4 /**
5 * @file Process_Manager.h
7 * @author Douglas C. Schmidt <d.schmidt@vanderbilt.edu>
8 */
9 //=============================================================================
11 #ifndef ACE_PROCESS_MANAGER_H
12 #define ACE_PROCESS_MANAGER_H
14 #include /**/ "ace/pre.h"
16 #include /**/ "ace/ACE_export.h"
18 #if !defined (ACE_LACKS_PRAGMA_ONCE)
19 # pragma once
20 #endif /* ACE_LACKS_PRAGMA_ONCE */
22 #include "ace/Process.h"
23 #include "ace/Event_Handler.h"
24 #include "ace/Time_Value.h"
26 #if defined (ACE_HAS_THREADS)
27 # include "ace/Recursive_Thread_Mutex.h"
28 #endif /* ACE_HAS_THREADS */
30 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
32 class ACE_Reactor;
34 /**
35 * @class ACE_Process_Manager
37 * @brief Manages a group of processes.
39 * This class allows applications to control groups of processes,
40 * similar to the way ACE_Thread_Manager controls groups of
41 * threads. Naturally, it doesn't work at all on platforms, such
42 * as VxWorks or pSoS, that don't support multiple processes.
43 * There are two main ways of using ACE_Process_Manager,
44 * depending on how involved you wish to be with the termination
45 * of managed processes. If you want processes to simply
46 * go away when they're finished, register the ACE_Process_Manager with
47 * an ACE_Reactor that can handle notifications of child process exit:
48 * @code
49 * ACE_Process_Manager mgr;
50 * // ...
51 * mgr.open (100, ACE_Reactor::instance ());
52 * @endcode
53 * In this usage scenario, the ACE_Process_Manager will clean up after any
54 * processes that it spawns. (On Unix, this means executing a
55 * wait(2) to collect the exit status and avoid zombie
56 * processes; on Win32, it means closing the process and thread
57 * HANDLEs that are created when CreateProcess is called.)
59 * @note When you register a ACE_Process_Manager with a
60 * ACE_Reactor, the reactor's notification pipe is used to help reap the
61 * available process exit statuses. Therefore, you must not use a
62 * reactor whose notify pipe has been disabled. Here's the
63 * sequence of steps used to reap the exit statuses in this case:
64 * -# The ACE_Process_Manager registers a signal handler for
65 * SIGCHLD.
66 * -# The SIGCHLD handler, when invoked, uses the ACE_Reactor's
67 * notify() method to inform the ACE_Reactor to wake up.
68 * -# The ACE_Reactor calls the ACE_Process_Manager's
69 * handle_input() method; this happens synchronously, not in
70 * signal context.
71 * -# The handle_input() method collects all available exit
72 * statuses.
74 * If, on the other hand you want to wait "in line" to handle the
75 * terminated process cleanup code, call one of the wait functions
76 * whenever there might be managed processes that have exited.
78 * Note that in either case, ACE_Process_Manager allows you to
79 * register an ACE_Event_Handler to be called when a specific
80 * spawned process exits, or when any process without a specific
81 * ACE_Event_Handler exits. When a process exits, the
82 * appropriate ACE_Event_Handler's handle_input() method is called; the
83 * ACE_HANDLE passed is either the process's HANDLE (on Windows),
84 * or its pid cast to an ACE_HANDLE (on POSIX).
85 * It is also possible to call the wait() functions even when the
86 * ACE_Process_Manager is registered with a reactor.
88 * @note Be aware that the wait functions are "sloppy" on Unix,
89 * because there's no good way to wait for a subset of the
90 * children of a process. The wait functions may end up
91 * collecting the exit status of a process that's not managed by
92 * the ACE_Process_Manager whose wait() you invoked. It's best to
93 * only use a single ACE_Process_Manager, and to create all
94 * subprocesses by calling that manager's spawn() method.
96 class ACE_Export ACE_Process_Manager : protected ACE_Event_Handler
98 public:
99 friend class ACE_Process_Control;
101 enum
103 DEFAULT_SIZE = 100
107 * @name Initialization and termination methods
109 //@{
111 * Initialize an ACE_Process_Manager with a table containing up to
112 * @a size processes. This table resizes itself automatically as
113 * needed. If a @a reactor is provided, this
114 * ACE_Process_Manager uses it to notify an application when a
115 * process it controls exits. By default, however, we don't use an
116 * ACE_Reactor.
118 ACE_Process_Manager (size_t size = ACE_Process_Manager::DEFAULT_SIZE,
119 ACE_Reactor *reactor = 0);
122 * Initialize an ACE_Process_Manager with a table containing up to
123 * @a size processes. This table resizes itself automatically as
124 * needed. If a @a reactor is provided, this
125 * ACE_Process_Manager uses it to notify an application when a
126 * process it controls exits. By default, however, we don't use an
127 * ACE_Reactor.
129 int open (size_t size = ACE_Process_Manager::DEFAULT_SIZE,
130 ACE_Reactor *r = 0);
132 /// Release all resources. Do not wait for processes to exit.
133 int close (void);
135 /// Destructor releases all resources and does not wait for processes
136 /// to exit.
137 virtual ~ACE_Process_Manager (void);
139 //@}
142 * @name Singleton access and control
144 //@{
145 /// Get pointer to a process-wide ACE_Process_Manager.
146 static ACE_Process_Manager *instance (void);
148 /// Set pointer to a process-wide ACE_Process_Manager and return
149 /// existing pointer.
150 static ACE_Process_Manager *instance (ACE_Process_Manager *);
152 /// Delete the dynamically allocated singleton.
153 static void close_singleton (void);
155 /// Cleanup method, used by the ACE_Object_Manager to destroy the
156 /// singleton.
157 static void cleanup (void *instance, void *arg);
159 //@}
162 * @name Process creation methods
164 //@{
166 * Create a new process with specified @a options.
167 * Register @a event_handler to be called back when the process exits.
168 * The @a proc object's ACE_Process::unmanage() method is called when
169 * the process is removed from ACE_Process_Manager.
171 * On success, returns the process id of the child that was created.
172 * On failure, returns ACE_INVALID_PID.
174 pid_t spawn (ACE_Process *proc,
175 ACE_Process_Options &options,
176 ACE_Event_Handler *event_handler = 0);
179 * Create a new process with the specified @a options.
180 * Register @a event_handler to be called back when the process exits.
182 * On success, returns the process id of the child that was created.
183 * On failure, returns ACE_INVALID_PID.
185 pid_t spawn (ACE_Process_Options &options,
186 ACE_Event_Handler *event_handler = 0);
189 * Create @a n new processes with the same @a options.
190 * If @a child_pids is non-0 it is expected to be an array of at least
191 * @a n pid_t, which are filled in with the process IDs of the spawned
192 * processes.
193 * Register @a event_handler to be called back when each process exits.
194 * Returns 0 on success and -1 on failure.
196 int spawn_n (size_t n,
197 ACE_Process_Options &options,
198 pid_t *child_pids = 0,
199 ACE_Event_Handler *event_Handler = 0);
200 //@}
203 * @name Process synchronization operations
205 //@{
207 * Abruptly terminate a single process with id @a pid using the
208 * ACE::terminate_process() method which works on both signal-capable
209 * systems and on Windows.
211 * @note This call is potentially dangerous to use since the process
212 * being terminated may not have a chance to cleanup before it shuts down.
213 * The process's entry is also not removed from this class's process
214 * table. Calling either wait() or remove() after terminate() is
215 * advisable.
217 * @retval 0 on success and -1 on failure.
219 int terminate (pid_t pid);
222 * Sends the specified signal to the specified process.
224 * @note This only works on platforms that have signal capability. In
225 * particular, it doesn't work on Windows.
227 * @retval 0 on success and -1 on failure.
229 int terminate (pid_t pid, int sig);
232 * Block until there are no more child processes running that were
233 * spawned by this ACE_Process_Manager. Unlike the wait() method
234 * below, this method does not require a signal handler or use of
235 * ACE_OS::sigwait() because it simply blocks synchronously waiting
236 * for all the children managed by this ACE_Process_Manager to
237 * exit. Note that this does not return any status information
238 * about the success or failure of exiting child processes, although
239 * any registered exit handlers are called.
241 * @param timeout Relative time to wait for processes to terminate.
243 * @retval 0 on success; -1 on failure.
245 int wait (const ACE_Time_Value &timeout = ACE_Time_Value::max_time);
246 #if defined (ACE_HAS_CPP11)
247 /// @sa wait
248 template< class Rep, class Period >
249 int wait (const std::chrono::duration<Rep, Period>& timeout)
251 ACE_Time_Value const tv (timeout);
252 return this->wait (tv);
254 #endif
257 * Wait up to @a timeout for a single specified process to terminate.
258 * If @a pid is 0, this method waits for any of the managed processes
259 * (but see the note concerning "sloppy process cleanup on unix").
260 * If @a pid != 0, waits for that process only.
262 * @param pid Process ID
263 * @param timeout Relative time to wait for process to terminate
264 * @param status Exit status of terminated process
266 * @retval The pid of the process which exited, 0
267 * if a timeout occurred, or ACE_INVALID_PID on error.
269 pid_t wait (pid_t pid,
270 const ACE_Time_Value &timeout,
271 ACE_exitcode *status = 0);
272 #if defined (ACE_HAS_CPP11)
273 /// @sa wait
274 template< class Rep, class Period >
275 pid_t wait (pid_t pid,
276 const std::chrono::duration<Rep, Period>& timeout,
277 ACE_exitcode *status = 0)
279 ACE_Time_Value const tv (timeout);
280 return this->wait (pid, tv, status);
282 #endif
285 * Wait indefinitely for a single, specified process to terminate.
286 * If @a pid is 0, waits for any of the managed processes (but see the
287 * note concerning "sloppy process cleanup on unix").
288 * If @a pid != 0, this method waits for that process only.
290 * @retval The pid of the process which exited, or
291 * ACE_INVALID_PID on error.
293 pid_t wait (pid_t pid,
294 ACE_exitcode *status = 0);
295 //@}
298 * @name Utility methods
300 //@{
302 * Register an event handler to be called back when the specified
303 * process exits. If @a pid == ACE_INVALID_PID this handler is called
304 * when any process with no specific handler exits.
306 * @warning In multithreaded applications, there is a race condition
307 * if a process exits between the time it is spawned and when its
308 * handler is registered. To avoid this, register the handler at
309 * the time the process is spawned.
311 int register_handler (ACE_Event_Handler *event_handler,
312 pid_t pid = ACE_INVALID_PID);
315 * Remove process @a pid from the ACE_Process_Manager's internal records.
316 * This is called automatically by the wait() method if the waited process
317 * exits. This method can also be called after calling terminate() if
318 * there's no need to wait() for the terminated process.
320 int remove (pid_t pid);
322 /// Return the number of managed processes.
323 size_t managed (void) const;
326 * Sets the scheduling parameters for process identified by @a pid by
327 * passing @a params, @a pid to ACE_OS::sched_params().
329 * @retval 0 on success, -1 on failure, and ACE_INVALID_PID when the
330 * specified @a pid is not managed by this ACE_Process_Manager.
332 int set_scheduler (const ACE_Sched_Params &params, pid_t pid);
335 * Sets the scheduling parameters for all the processes managed by
336 * this ACE_Process_Manager by passing @a params to
337 * ACE_OS::sched_params().
339 * @retval 0 on success, -1 on failure.
341 int set_scheduler_all (const ACE_Sched_Params &params);
343 /// Dump the state of an object.
344 void dump (void) const;
346 /// Declare the dynamic allocation hooks.
347 ACE_ALLOC_HOOK_DECLARE;
348 //@}
350 protected:
351 // = These methods allow a <Process_Manager> to be an Event_Handler.
353 // As an Event_Handler, the <Process_Manager> automagically
354 // detects child Processes exiting and calls notify_proc_handler()
355 // and remove(). This means that you don't have to (shouldn't!)
356 // call the wait(...) methods yourself.
358 // On Unix, we can't detect individual process termination very
359 // well; the best method is to catch SIGCHLD and then call the
360 // polling wait() function to collect any available exit statuses.
361 // However, we don't want to do this from within a signal handler
362 // because of the restrictions associated. Therefore (following the
363 // lead in examples/mumble) we open a bogus handle (to ACE_DEV_NULL)
364 // and register that handle with our Reactor. Then, when our
365 // SIGCHLD handler gets invoked, we tell the Reactor that the bogus
366 // handle is readable. That will cause the handle_input() function
367 // to be called once we're out of the interrupt context, and
368 // handle_input() collects exit statuses.
370 // On Win32, we simply register ourself with the Reactor to deal
371 // with the Process handle becoming signaled. No muss, no fuss, no
372 // signal handler, and no dummy handle.
374 #if !defined(ACE_WIN32)
375 /// Collect one (or more, on unix) process exit status.
376 virtual int handle_input (ACE_HANDLE proc);
378 /// If registered with a reactor for SIGCHLD and the reactor closes, this
379 /// will get called to notify.
380 virtual int handle_close (ACE_HANDLE handle,
381 ACE_Reactor_Mask close_mask);
383 #endif // !defined(ACE_WIN32)
386 * On Unix, this routine is called asynchronously when a SIGCHLD is
387 * received. We just tweak the reactor so that it'll call back our
388 * <handle_input> function, which allows us to handle Process exits
389 * synchronously.
391 * On Win32, this routine is called synchronously, and is passed the
392 * HANDLE of the Process that exited, so we can do all our work here
394 virtual int handle_signal (int signum,
395 siginfo_t * = 0,
396 ucontext_t * = 0);
398 private:
401 * @struct Process_Descriptor
403 * @internal This struct is for internal use only by ACE_Process_Manager.
405 * @brief Information describing each process that's controlled by an
406 * ACE_Process_Manager.
408 struct Process_Descriptor
410 /// Default ctor/dtor.
411 Process_Descriptor (void);
412 ~Process_Descriptor (void);
414 /// Describes the process itself.
415 ACE_Process *process_;
417 /// Function to call when process exits
418 ACE_Event_Handler *exit_notify_;
420 /// Dump the state of an object.
421 void dump (void) const;
423 ACE_ALLOC_HOOK_DECLARE;
426 /// Resize the pool of Process_Descriptors.
427 int resize (size_t);
429 /// Locate the index of the table slot occupied by @a process_id.
430 /// Returns -1 if @a process_id is not in the @c process_table_
431 ssize_t find_proc (pid_t process_id);
433 #if defined (ACE_WIN32)
434 /// Locate the index of the table slot occupied by @a process_handle.
435 /// Returns ~0 if @a process_handle is not in the @c process_table_
436 ssize_t find_proc (ACE_HANDLE process_handle);
437 #endif /* ACE_WIN32 */
439 /// Insert a process in the table (checks for duplicates). Omitting
440 /// the process handle won't work on Win32...
441 /// Register @a event_handler to be called back when the process exits.
442 int insert_proc (ACE_Process *process,
443 ACE_Event_Handler *event_handler = 0);
446 * Append information about a process, i.e., its <process_id> in the
447 * @c process_table_. Each entry is added at the end, growing the
448 * table if necessary.
449 * Register @a event_handler to be called back when the process exits.
451 int append_proc (ACE_Process *process,
452 ACE_Event_Handler *event_handler = 0);
454 /// Actually removes the process at index @a n from the table. This method
455 /// must be called with locks held.
456 int remove_proc (size_t n);
458 /// If there's a specific handler for the Process at index @a n in the
459 /// table, or there's a default handler, call it.
460 int notify_proc_handler (size_t n, ACE_exitcode status);
462 /// Vector that describes process state within the Process_Manager.
463 Process_Descriptor *process_table_;
465 /// Maximum number of processes we can manage (should be dynamically
466 /// allocated).
467 size_t max_process_table_size_;
469 /// Current number of processes we are managing.
470 size_t current_count_;
472 /// This event handler is used to notify when a process we control
473 /// exits.
474 ACE_Event_Handler *default_exit_handler_;
476 /// Singleton pointer.
477 static ACE_Process_Manager *instance_;
479 /// Controls whether the <Process_Manager> is deleted when we shut
480 /// down (we can only delete it safely if we created it!)
481 static bool delete_instance_;
483 #if defined (ACE_HAS_THREADS)
484 /// This lock protects access/ops on @c process_table_.
485 ACE_Recursive_Thread_Mutex lock_;
486 #endif /* ACE_HAS_THREADS */
489 ACE_END_VERSIONED_NAMESPACE_DECL
491 #if defined (__ACE_INLINE__)
492 #include "ace/Process_Manager.inl"
493 #endif /* __ACE_INLINE__ */
495 #include /**/ "ace/post.h"
496 #endif /* ACE_PROCESS_MANAGER_H */