Revert "Use a variable on the stack to not have a temporary in the call"
[ACE_TAO.git] / ACE / tests / Process_Manager_Test.cpp
blob241498941b9385bfe55f5bda0002c3bbb7fbfa38
2 //=============================================================================
3 /**
4 * @file Process_Manager_Test.cpp
6 * This program tests the various methods provided by
7 * <ACE_Process_Manager>. It illustrates both the explicit <wait>
8 * functions and the Reactor-style auto-reaping. There's an
9 * Exit_Handler class that can print out (in Debug mode) when a
10 * child has been reaped.
12 * The child processes spawned are simply this program itself, with
13 * an integer argument specifying how long to "process" (actually,
14 * the child just sleeps for the specified length of time).
16 * @author Douglas C. Schmidt <d.schmidt@vanderbilt.edu> and Dave Madden <dhm@mersenne.com>
18 //=============================================================================
20 #include "test_config.h"
21 #include "ace/SString.h"
22 #include "ace/Atomic_Op.h"
23 #include "ace/Task.h"
24 #include "ace/OS_NS_unistd.h"
25 #include "ace/OS_NS_string.h"
26 #include "ace/Process_Manager.h"
27 #include "ace/Synch_Traits.h"
28 #include "ace/Get_Opt.h"
29 #include "ace/Thread.h"
30 #include "ace/Reactor.h"
32 static u_int debug_test = 0;
33 #if defined (ACE_HAS_WIN32_PRIORITY_CLASS)
34 static u_int process_id = 0;
35 #endif
37 class Exit_Handler : public ACE_Event_Handler
39 public:
40 Exit_Handler (const char *msg): msg_ (msg) { }
42 ~Exit_Handler () override { }
44 int handle_close (ACE_HANDLE, ACE_Reactor_Mask) override
46 delete this;
47 return 0;
50 int handle_exit (ACE_Process *proc) override
52 ACE_DEBUG ((LM_DEBUG,
53 ACE_TEXT ("(%P) Exit_Handler(%C) got %d: %d\n"),
54 msg_,
55 int (proc->getpid ()),
56 int (proc->exit_code ()) ));
57 return 0;
59 private:
60 const char *msg_;
63 static void
64 usage (const ACE_TCHAR *argv0)
66 ACE_ERROR ((LM_ERROR,
67 ACE_TEXT ("usage: %s [-d] [sleep-seconds]\n"),
68 argv0));
69 ACE_OS::exit (0);
72 static pid_t
73 spawn_child (const ACE_TCHAR *argv0,
74 ACE_Process_Manager &mgr,
75 int sleep_time,
76 int my_process_id)
78 #if defined (ACE_WIN32)
79 const ACE_TCHAR *cmdline_format = ACE_TEXT("\"%s\" %s %d");
80 #elif !defined (ACE_USES_WCHAR)
81 const ACE_TCHAR *cmdline_format = ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR ACE_TEXT("%s %s %d");
82 #else
83 const ACE_TCHAR *cmdline_format = ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR ACE_TEXT("%ls %ls %d");
84 #endif
85 ACE_Process_Options opts;
87 ACE_TCHAR prio[64];
88 ACE_TCHAR cmd[16];
90 if (debug_test)
91 ACE_OS::strcpy (cmd, ACE_TEXT ("-d"));
92 else
93 cmd[0] = ACE_TEXT ('\0');
95 #if defined (ACE_HAS_WIN32_PRIORITY_CLASS)
96 if (my_process_id == 1)
98 opts.creation_flags (ABOVE_NORMAL_PRIORITY_CLASS);
99 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'above normal'"));
101 else if (my_process_id == 2)
103 opts.creation_flags (BELOW_NORMAL_PRIORITY_CLASS);
104 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'below normal'"));
106 else if (my_process_id == 3)
108 opts.creation_flags (IDLE_PRIORITY_CLASS);
109 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'idle'"));
111 else if (my_process_id == 4)
113 opts.creation_flags (HIGH_PRIORITY_CLASS);
114 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'high'"));
116 else if (my_process_id == 5)
118 opts.creation_flags (NORMAL_PRIORITY_CLASS);
119 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'normal'"));
121 else
122 prio[0] = ACE_TEXT ('\0');
124 ACE_TCHAR pd [16];
125 ACE_OS::snprintf (pd, 16, ACE_TEXT (" -p %d"), my_process_id);
126 ACE_OS::strcat (cmd, pd);
127 #else
128 ACE_UNUSED_ARG (my_process_id);
129 prio[0] = ACE_TEXT ('\0');
130 #endif
132 opts.process_name (argv0);
133 #ifndef ACE_LACKS_VA_FUNCTIONS
134 opts.command_line (cmdline_format,
135 argv0,
136 cmd,
137 sleep_time);
138 #else
139 ACE_UNUSED_ARG (cmdline_format);
140 #endif /* ACE_LACKS_VA_FUNCTIONS */
142 ACE_DEBUG ((LM_DEBUG, ACE_TEXT("Spawning <%s> <%s>\n"),
143 opts.process_name(),
144 opts.command_line_buf ()));
146 pid_t result = mgr.spawn (opts);
148 if (result != ACE_INVALID_PID)
149 ACE_DEBUG ((LM_DEBUG,
150 ACE_TEXT ("(%P) spawned child: pid %d time %d %s\n"),
151 int (result), sleep_time, prio));
152 else
153 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn failed")));
155 return result;
158 ACE_CString order;
160 ACE_Atomic_Op<ACE_SYNCH_MUTEX, int> running_tasks = 0;
162 class Process_Task : public ACE_Task<ACE_SYNCH>
164 public:
165 Process_Task (const ACE_TCHAR *argv0,
166 ACE_Process_Manager &mgr,
167 int sleep_time)
168 : argv0_ (argv0),
169 mgr_ (mgr),
170 sleep_time_ (sleep_time) { }
172 // FUZZ: disable check_for_lack_ACE_OS
173 /// FUZZ: enable check_for_lack_ACE_OS
174 int open (void*) override
176 char tmp[10];
177 order += ACE_OS::itoa (sleep_time_, tmp, 10);
178 ++running_tasks;
179 activate ();
180 return 0;
183 int svc () override
185 int result = 0;
186 ACE_exitcode exitcode;
187 pid_t my_child = spawn_child (argv0_,
188 mgr_,
189 sleep_time_,
191 result = mgr_.wait (my_child,
192 &exitcode);
193 if (result != my_child)
195 ACE_ERROR ((LM_ERROR,
196 ACE_TEXT ("(%P) Error: expected to reap child (%d); got %d\n"),
197 my_child,
198 result));
199 if (result == ACE_INVALID_PID)
200 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("error")));
201 //test_status = 1;
203 else
204 ACE_DEBUG ((LM_DEBUG,
205 ACE_TEXT ("(%P) reaped child, pid %d: %d\n"),
206 my_child,
207 exitcode));
208 char tmp[10];
209 order += ACE_OS::itoa (sleep_time_, tmp, 10);
210 return 0;
213 // FUZZ: disable check_for_lack_ACE_OS
214 /// FUZZ: enable check_for_lack_ACE_OS
215 int close (u_long) override
217 --running_tasks;
218 return 0;
221 private:
222 const ACE_TCHAR *argv0_;
223 ACE_Process_Manager &mgr_;
224 int sleep_time_;
227 #ifdef ACE_HAS_PROCESS_SPAWN
228 static int
229 command_line_test ()
231 ACE_DEBUG ((LM_DEBUG,
232 ACE_TEXT ("Testing for last character of command line\n")));
233 int result = 0;
234 const ACE_TCHAR *command = ACE_TEXT ("test Hello");
235 size_t command_len = ACE_OS::strlen (command);
236 ACE_Process_Options options (1, command_len + 1);
238 #ifndef ACE_LACKS_VA_FUNCTIONS
239 options.command_line (ACE_TEXT ("%") ACE_TEXT_PRIs, command);
240 #endif
242 ACE_TCHAR * const *procargv = options.command_line_argv ();
243 if (ACE_OS::strcmp (procargv [1], ACE_TEXT ("Hello")) != 0)
245 ACE_ERROR ((LM_ERROR,
246 ACE_TEXT ("command_line_test failed: expected \"%s\"; got \"%s\"\n"),
247 ACE_TEXT ("Hello"),
248 procargv [1]));
249 result = 1;
251 return result;
253 #endif
255 #if defined (ACE_HAS_WIN32_PRIORITY_CLASS)
256 void
257 check_process_priority (DWORD priority)
259 if ((process_id == 0) ||
260 (process_id == 1 && priority == ABOVE_NORMAL_PRIORITY_CLASS) ||
261 (process_id == 2 && priority == BELOW_NORMAL_PRIORITY_CLASS) ||
262 (process_id == 3 && priority == IDLE_PRIORITY_CLASS) ||
263 (process_id == 4 && priority == HIGH_PRIORITY_CLASS) ||
264 (process_id == 5 && priority == NORMAL_PRIORITY_CLASS) ||
265 (process_id == 7 && priority == NORMAL_PRIORITY_CLASS))
266 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Process ID (%d) and priority (%d) match\n"),
267 process_id, priority));
268 else
269 ACE_ERROR ((LM_ERROR,
270 ACE_TEXT ("Given process priority (%d) and real priority (%d) differ.\n"),
271 process_id, priority));
273 #endif
276 run_main (int argc, ACE_TCHAR *argv[])
278 #if defined (ACE_HAS_WIN32_PRIORITY_CLASS)
279 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("dp:"));
280 #else
281 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("d"));
282 #endif
283 int opt;
284 while ((opt = get_opt ()) != EOF)
286 switch (opt)
288 case 'd':
289 debug_test = 1u;
290 break;
291 #if defined (ACE_HAS_WIN32_PRIORITY_CLASS)
292 case 'p':
293 process_id = ACE_OS::atoi (get_opt.opt_arg ());
294 break;
295 #endif
299 if (get_opt.opt_ind () == argc - 1)
301 // child process: sleep & exit
302 ACE_TCHAR lognm[MAXPATHLEN];
303 int const mypid (ACE_OS::getpid ());
304 ACE_OS::snprintf (lognm, MAXPATHLEN,
305 ACE_TEXT ("Process_Manager_Test-child-%d"), mypid);
307 ACE_START_TEST (lognm);
308 int const secs = ACE_OS::atoi (argv[get_opt.opt_ind ()]);
309 ACE_OS::sleep (secs ? secs : 1);
311 ACE_TCHAR prio[64];
312 #if defined (ACE_WIN32_HAS_PRIORITY_CLASS)
313 DWORD priority = ::GetPriorityClass (::GetCurrentProcess());
315 check_process_priority(priority);
317 if (priority == ABOVE_NORMAL_PRIORITY_CLASS)
318 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'above normal'"));
319 else if (priority == BELOW_NORMAL_PRIORITY_CLASS)
320 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'below normal'"));
321 else if (priority == HIGH_PRIORITY_CLASS)
322 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'high'"));
323 else if (priority == IDLE_PRIORITY_CLASS)
324 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'idle'"));
325 else if (priority == NORMAL_PRIORITY_CLASS)
326 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'normal'"));
327 else if (priority == REALTIME_PRIORITY_CLASS)
328 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'realtime'"));
329 #else
330 prio[0] = ACE_TEXT ('\0');
331 #endif
332 if (debug_test)
333 ACE_DEBUG ((LM_DEBUG,
334 ACE_TEXT ("%T: pid %P about to exit with code %d %s\n"),
335 secs,
336 prio));
337 ACE_END_LOG;
339 return secs;
342 if (get_opt.opt_ind () != argc) // incorrect usage
343 usage (argv[0]);
345 ACE_START_TEST (ACE_TEXT ("Process_Manager_Test"));
347 int test_status = 0;
349 #ifdef ACE_HAS_PROCESS_SPAWN
351 int result = 0;
352 if ((result = command_line_test ()) != 0)
353 test_status = result;
355 // Try the explicit <ACE_Process_Manager::wait> functions
356 ACE_Process_Manager mgr;
358 mgr.register_handler (new Exit_Handler ("default"));
360 ACE_exitcode exitcode;
362 // --------------------------------------------------
363 // wait for a specific PID
364 pid_t child1 = spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
365 mgr,
368 result = mgr.wait (child1,
369 &exitcode);
371 if (result != child1)
373 ACE_ERROR ((LM_ERROR,
374 ACE_TEXT ("(%P) Error: expected to reap child1 (%d); got %d\n"),
375 child1,
376 result));
377 if (result == ACE_INVALID_PID)
378 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("error")));
379 test_status = 1;
381 else
382 ACE_DEBUG ((LM_DEBUG,
383 ACE_TEXT ("(%P) reaped child1, pid %d: %d\n"),
384 child1,
385 exitcode));
387 // --------------------------------------------------
388 // wait for a specific PID; another should finish first
389 pid_t child2 = spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
390 mgr,
393 pid_t child3 = spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
394 mgr,
397 result = mgr.wait (child3,
398 &exitcode);
400 if (result != child3)
402 ACE_ERROR ((LM_ERROR,
403 ACE_TEXT ("(%P) Error: expected to reap child3 (%d); got %d\n"),
404 child3,
405 result));
406 if (result == ACE_INVALID_PID)
407 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("error")));
408 test_status = 1;
410 else
411 ACE_DEBUG ((LM_DEBUG,
412 ACE_TEXT ("(%P) reaped child 3, pid %d: %d\n"),
413 child3,
414 exitcode));
416 // Now wait for any...should get the one that finished earlier.
418 result = mgr.wait (0, &exitcode);
420 if (result != child2)
422 ACE_ERROR ((LM_ERROR,
423 ACE_TEXT ("(%P) Error: expected to reap child2 (%d); got %d\n"),
424 child2,
425 result));
426 if (result == ACE_INVALID_PID)
427 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("error")));
428 test_status = 1;
430 else
431 ACE_DEBUG ((LM_DEBUG,
432 ACE_TEXT ("(%P) reaped child 2, pid %d: %d\n"),
433 result,
434 exitcode));
436 // --------------------------------------------------
437 // Try the timed wait functions
439 // This one shouldn't timeout:
440 pid_t child4 = spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
441 mgr,
444 result = mgr.wait (0, std::chrono::seconds (4), &exitcode);
446 if (result != child4)
448 ACE_ERROR ((LM_ERROR,
449 ACE_TEXT ("(%P) Error: expected to reap child4 (%d); got %d\n"),
450 child4,
451 result));
452 if (result == ACE_INVALID_PID)
453 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("error")));
454 test_status = 1;
456 else
457 ACE_DEBUG ((LM_DEBUG,
458 ACE_TEXT ("(%P) reaped child 4 pid %d: %d\n"),
459 result,
460 exitcode));
462 // This one should timeout:
463 pid_t child5 = spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
464 mgr,
467 result = mgr.wait (0, ACE_Time_Value (1), &exitcode);
468 if (result != 0)
470 ACE_ERROR ((LM_ERROR,
471 ACE_TEXT ("(%P) Error: expected wait to time out; got %d\n"),
472 result));
473 if (result == ACE_INVALID_PID)
474 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("error")));
475 test_status = 1;
477 else
478 ACE_DEBUG ((LM_DEBUG,
479 ACE_TEXT ("(%P) Correctly timed out wait at child 5\n")));
481 // Now wait indefinitely to clean up...
482 result = mgr.wait (0, &exitcode);
484 if (result != child5)
486 ACE_ERROR ((LM_ERROR,
487 ACE_TEXT ("Error: expected to reap child5 pid %d; got %d\n"),
488 child5,
489 result));
490 if (result == ACE_INVALID_PID)
491 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("error")));
492 test_status = 1;
494 else
495 ACE_DEBUG ((LM_DEBUG,
496 ACE_TEXT ("(%P) reaped child 5, pid %d: %d\n"),
497 result,
498 exitcode));
500 // Terminate a child process and make sure we can wait for it.
501 pid_t child6 = spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
502 mgr,
505 ACE_exitcode status6;
506 if (-1 == mgr.terminate (child6))
508 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("terminate child6")));
509 test_status = 1;
510 mgr.wait (child6, &status6); // Wait for child to exit just to clean up
512 else
514 if (-1 == mgr.wait (child6, &status6))
516 ACE_ERROR ((LM_ERROR,
517 ACE_TEXT ("(%P) wait on child6 reported ACE_INVALID_PID\n")));
518 test_status = 1;
520 else
522 // Get the results of the termination.
523 #if !defined(ACE_WIN32)
524 if (WIFSIGNALED (status6) != 0)
525 ACE_DEBUG ((LM_DEBUG,
526 ACE_TEXT ("(%P) child6 died on signal %d - correct\n"),
527 WTERMSIG (status6)));
528 else
529 ACE_ERROR ((LM_ERROR,
530 ACE_TEXT ("(%P) child6 should have died on signal, ")
531 ACE_TEXT ("but didn't; exit status %d\n"),
532 WEXITSTATUS (status6)));
533 #else
534 ACE_DEBUG
535 ((LM_DEBUG,
536 ACE_TEXT ("(%P) The process terminated with exit code %d\n"),
537 status6));
538 #endif /*ACE_WIN32*/
542 #ifdef ACE_HAS_THREADS
543 Process_Task task1 (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"), mgr, 3);
544 Process_Task task2 (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"), mgr, 2);
545 Process_Task task3 (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"), mgr, 1);
546 task1.open (0);
547 task2.open (0);
548 task3.open (0);
550 while (running_tasks!=0)
552 ACE_OS::sleep (1);
553 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P) still running tasks\n")));
556 ACE_DEBUG ((LM_DEBUG,
557 ACE_TEXT ("(%P) result: '%C'\n"),
558 order.c_str ()));
560 if (order != "321123")
562 ACE_ERROR ((LM_ERROR,
563 ACE_TEXT ("(%P) wrong order of spawns ('%C', should be '321123')\n"),
564 order.c_str ()));
565 test_status = 1;
567 #endif /* ACE_HAS_THREADS */
569 #if defined ACE_WIN32 || !defined ACE_LACKS_UNIX_SIGNALS
570 // --------------------------------------------------
571 // Finally, try the reactor stuff...
572 mgr.open (ACE_Process_Manager::DEFAULT_SIZE,
573 ACE_Reactor::instance ());
575 pid_t child7 = spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
576 mgr,
579 /* pid_t child8 = */ spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
580 mgr,
584 mgr.register_handler (new Exit_Handler ("specific"),
585 child7);
587 ACE_Time_Value how_long (10);
589 ACE_Reactor::instance ()->run_reactor_event_loop (how_long);
591 ACE_DEBUG ((LM_DEBUG,
592 ACE_TEXT ("(%P) Reactor loop done!\n") ));
594 size_t const nr_procs = mgr.managed ();
595 if (nr_procs != 0)
596 ACE_ERROR ((LM_ERROR,
597 ACE_TEXT ("(%P) %d processes left in manager\n"),
598 nr_procs));
599 #endif /* defined (ACE_WIN32) */
600 #endif // ACE_HAS_PROCESS_SPAWN
601 ACE_END_TEST;
602 return test_status;