ACE+TAO-7_0_8
[ACE_TAO.git] / ACE / tests / Process_Manager_Test.cpp
blob02d89c320c4bf7feeb18aae2659b78621365876b
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)
79 #if defined (ACE_HAS_WINCE)
80 const ACE_TCHAR *cmdline_format = ACE_TEXT("%s %d");
81 #elif defined (ACE_WIN32)
82 const ACE_TCHAR *cmdline_format = ACE_TEXT("\"%s\" %s %d");
83 #elif !defined (ACE_USES_WCHAR)
84 const ACE_TCHAR *cmdline_format = ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR ACE_TEXT("%s %s %d");
85 #else
86 const ACE_TCHAR *cmdline_format = ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR ACE_TEXT("%ls %ls %d");
87 #endif
88 ACE_Process_Options opts;
90 ACE_TCHAR prio[64];
91 ACE_TCHAR cmd[16];
93 if (debug_test)
94 ACE_OS::strcpy (cmd, ACE_TEXT ("-d"));
95 else
96 cmd[0] = ACE_TEXT ('\0');
98 #if defined (ACE_HAS_WIN32_PRIORITY_CLASS)
99 if (my_process_id == 1)
101 opts.creation_flags (ABOVE_NORMAL_PRIORITY_CLASS);
102 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'above normal'"));
104 else if (my_process_id == 2)
106 opts.creation_flags (BELOW_NORMAL_PRIORITY_CLASS);
107 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'below normal'"));
109 else if (my_process_id == 3)
111 opts.creation_flags (IDLE_PRIORITY_CLASS);
112 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'idle'"));
114 else if (my_process_id == 4)
116 opts.creation_flags (HIGH_PRIORITY_CLASS);
117 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'high'"));
119 else if (my_process_id == 5)
121 opts.creation_flags (NORMAL_PRIORITY_CLASS);
122 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'normal'"));
124 else
125 prio[0] = ACE_TEXT ('\0');
127 ACE_TCHAR pd [16];
128 ACE_OS::snprintf (pd, 16, ACE_TEXT (" -p %d"), my_process_id);
129 ACE_OS::strcat (cmd, pd);
130 #else
131 ACE_UNUSED_ARG (my_process_id);
132 prio[0] = ACE_TEXT ('\0');
133 #endif
135 opts.process_name (argv0);
136 #ifndef ACE_LACKS_VA_FUNCTIONS
137 opts.command_line (cmdline_format,
138 #if !defined (ACE_HAS_WINCE)
139 argv0,
140 #endif /* !ACE_HAS_WINCE */
141 cmd,
142 sleep_time);
143 #else
144 ACE_UNUSED_ARG (cmdline_format);
145 #endif /* ACE_LACKS_VA_FUNCTIONS */
147 ACE_DEBUG ((LM_DEBUG, ACE_TEXT("Spawning <%s> <%s>\n"),
148 opts.process_name(),
149 opts.command_line_buf ()));
151 pid_t result = mgr.spawn (opts);
153 if (result != ACE_INVALID_PID)
154 ACE_DEBUG ((LM_DEBUG,
155 ACE_TEXT ("(%P) spawned child: pid %d time %d %s\n"),
156 int (result), sleep_time, prio));
157 else
158 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn failed")));
160 return result;
163 ACE_CString order;
165 ACE_Atomic_Op<ACE_SYNCH_MUTEX, int> running_tasks = 0;
167 class Process_Task : public ACE_Task<ACE_SYNCH>
169 public:
170 Process_Task (const ACE_TCHAR *argv0,
171 ACE_Process_Manager &mgr,
172 int sleep_time)
173 : argv0_ (argv0),
174 mgr_ (mgr),
175 sleep_time_ (sleep_time) { }
177 // FUZZ: disable check_for_lack_ACE_OS
178 /// FUZZ: enable check_for_lack_ACE_OS
179 int open (void*) override
181 char tmp[10];
182 order += ACE_OS::itoa (sleep_time_, tmp, 10);
183 ++running_tasks;
184 activate ();
185 return 0;
188 int svc () override
190 int result = 0;
191 ACE_exitcode exitcode;
192 pid_t my_child = spawn_child (argv0_,
193 mgr_,
194 sleep_time_,
196 result = mgr_.wait (my_child,
197 &exitcode);
198 if (result != my_child)
200 ACE_ERROR ((LM_ERROR,
201 ACE_TEXT ("(%P) Error: expected to reap child (%d); got %d\n"),
202 my_child,
203 result));
204 if (result == ACE_INVALID_PID)
205 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("error")));
206 //test_status = 1;
208 else
209 ACE_DEBUG ((LM_DEBUG,
210 ACE_TEXT ("(%P) reaped child, pid %d: %d\n"),
211 my_child,
212 exitcode));
213 char tmp[10];
214 order += ACE_OS::itoa (sleep_time_, tmp, 10);
215 return 0;
218 // FUZZ: disable check_for_lack_ACE_OS
219 /// FUZZ: enable check_for_lack_ACE_OS
220 int close (u_long) override
222 --running_tasks;
223 return 0;
226 private:
227 const ACE_TCHAR *argv0_;
228 ACE_Process_Manager &mgr_;
229 int sleep_time_;
232 #ifdef ACE_HAS_PROCESS_SPAWN
233 static int
234 command_line_test ()
236 ACE_DEBUG ((LM_DEBUG,
237 ACE_TEXT ("Testing for last character of command line\n")));
238 int result = 0;
239 const ACE_TCHAR *command = ACE_TEXT ("test Hello");
240 size_t command_len = ACE_OS::strlen (command);
241 ACE_Process_Options options (1, command_len + 1);
243 #ifndef ACE_LACKS_VA_FUNCTIONS
244 options.command_line (command);
245 #endif
247 ACE_TCHAR * const *procargv = options.command_line_argv ();
248 if (ACE_OS::strcmp (procargv [1], ACE_TEXT ("Hello")) != 0)
250 ACE_ERROR ((LM_ERROR,
251 ACE_TEXT ("command_line_test failed: expected \"%s\"; got \"%s\"\n"),
252 ACE_TEXT ("Hello"),
253 procargv [1]));
254 result = 1;
256 return result;
258 #endif
260 #if defined (ACE_HAS_WIN32_PRIORITY_CLASS)
261 void
262 check_process_priority (DWORD priority)
264 if ((process_id == 0) ||
265 (process_id == 1 && priority == ABOVE_NORMAL_PRIORITY_CLASS) ||
266 (process_id == 2 && priority == BELOW_NORMAL_PRIORITY_CLASS) ||
267 (process_id == 3 && priority == IDLE_PRIORITY_CLASS) ||
268 (process_id == 4 && priority == HIGH_PRIORITY_CLASS) ||
269 (process_id == 5 && priority == NORMAL_PRIORITY_CLASS) ||
270 (process_id == 7 && priority == NORMAL_PRIORITY_CLASS))
271 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Process ID (%d) and priority (%d) match\n"),
272 process_id, priority));
273 else
274 ACE_ERROR ((LM_ERROR,
275 ACE_TEXT ("Given process priority (%d) and real priority (%d) differ.\n"),
276 process_id, priority));
278 #endif
281 run_main (int argc, ACE_TCHAR *argv[])
283 #if defined (ACE_HAS_WIN32_PRIORITY_CLASS)
284 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("dp:"));
285 #else
286 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT ("d"));
287 #endif
288 int opt;
289 while ((opt = get_opt ()) != EOF)
291 switch (opt)
293 case 'd':
294 debug_test = 1u;
295 break;
296 #if defined (ACE_HAS_WIN32_PRIORITY_CLASS)
297 case 'p':
298 process_id = ACE_OS::atoi (get_opt.opt_arg ());
299 break;
300 #endif
304 if (get_opt.opt_ind () == argc - 1)
306 // child process: sleep & exit
307 ACE_TCHAR lognm[MAXPATHLEN];
308 int const mypid (ACE_OS::getpid ());
309 ACE_OS::snprintf (lognm, MAXPATHLEN,
310 ACE_TEXT ("Process_Manager_Test-child-%d"), mypid);
312 ACE_START_TEST (lognm);
313 int const secs = ACE_OS::atoi (argv[get_opt.opt_ind ()]);
314 ACE_OS::sleep (secs ? secs : 1);
316 ACE_TCHAR prio[64];
317 #if defined (ACE_WIN32_HAS_PRIORITY_CLASS)
318 DWORD priority = ::GetPriorityClass (::GetCurrentProcess());
320 check_process_priority(priority);
322 if (priority == ABOVE_NORMAL_PRIORITY_CLASS)
323 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'above normal'"));
324 else if (priority == BELOW_NORMAL_PRIORITY_CLASS)
325 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'below normal'"));
326 else if (priority == HIGH_PRIORITY_CLASS)
327 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'high'"));
328 else if (priority == IDLE_PRIORITY_CLASS)
329 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'idle'"));
330 else if (priority == NORMAL_PRIORITY_CLASS)
331 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'normal'"));
332 else if (priority == REALTIME_PRIORITY_CLASS)
333 ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'realtime'"));
334 #else
335 prio[0] = ACE_TEXT ('\0');
336 #endif
337 if (debug_test)
338 ACE_DEBUG ((LM_DEBUG,
339 ACE_TEXT ("%T: pid %P about to exit with code %d %s\n"),
340 secs,
341 prio));
342 ACE_END_LOG;
344 return secs;
347 if (get_opt.opt_ind () != argc) // incorrect usage
348 usage (argv[0]);
350 ACE_START_TEST (ACE_TEXT ("Process_Manager_Test"));
352 int test_status = 0;
354 #ifdef ACE_HAS_PROCESS_SPAWN
356 int result = 0;
357 if ((result = command_line_test ()) != 0)
358 test_status = result;
360 // Try the explicit <ACE_Process_Manager::wait> functions
361 ACE_Process_Manager mgr;
363 mgr.register_handler (new Exit_Handler ("default"));
365 ACE_exitcode exitcode;
367 // --------------------------------------------------
368 // wait for a specific PID
369 pid_t child1 = spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
370 mgr,
373 result = mgr.wait (child1,
374 &exitcode);
376 if (result != child1)
378 ACE_ERROR ((LM_ERROR,
379 ACE_TEXT ("(%P) Error: expected to reap child1 (%d); got %d\n"),
380 child1,
381 result));
382 if (result == ACE_INVALID_PID)
383 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("error")));
384 test_status = 1;
386 else
387 ACE_DEBUG ((LM_DEBUG,
388 ACE_TEXT ("(%P) reaped child1, pid %d: %d\n"),
389 child1,
390 exitcode));
392 // --------------------------------------------------
393 // wait for a specific PID; another should finish first
394 pid_t child2 = spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
395 mgr,
398 pid_t child3 = spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
399 mgr,
402 result = mgr.wait (child3,
403 &exitcode);
405 if (result != child3)
407 ACE_ERROR ((LM_ERROR,
408 ACE_TEXT ("(%P) Error: expected to reap child3 (%d); got %d\n"),
409 child3,
410 result));
411 if (result == ACE_INVALID_PID)
412 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("error")));
413 test_status = 1;
415 else
416 ACE_DEBUG ((LM_DEBUG,
417 ACE_TEXT ("(%P) reaped child 3, pid %d: %d\n"),
418 child3,
419 exitcode));
421 // Now wait for any...should get the one that finished earlier.
423 result = mgr.wait (0, &exitcode);
425 if (result != child2)
427 ACE_ERROR ((LM_ERROR,
428 ACE_TEXT ("(%P) Error: expected to reap child2 (%d); got %d\n"),
429 child2,
430 result));
431 if (result == ACE_INVALID_PID)
432 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("error")));
433 test_status = 1;
435 else
436 ACE_DEBUG ((LM_DEBUG,
437 ACE_TEXT ("(%P) reaped child 2, pid %d: %d\n"),
438 result,
439 exitcode));
441 // --------------------------------------------------
442 // Try the timed wait functions
444 // This one shouldn't timeout:
445 pid_t child4 = spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
446 mgr,
449 result = mgr.wait (0, std::chrono::seconds (4), &exitcode);
451 if (result != child4)
453 ACE_ERROR ((LM_ERROR,
454 ACE_TEXT ("(%P) Error: expected to reap child4 (%d); got %d\n"),
455 child4,
456 result));
457 if (result == ACE_INVALID_PID)
458 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("error")));
459 test_status = 1;
461 else
462 ACE_DEBUG ((LM_DEBUG,
463 ACE_TEXT ("(%P) reaped child 4 pid %d: %d\n"),
464 result,
465 exitcode));
467 // This one should timeout:
468 pid_t child5 = spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
469 mgr,
472 result = mgr.wait (0, ACE_Time_Value (1), &exitcode);
473 if (result != 0)
475 ACE_ERROR ((LM_ERROR,
476 ACE_TEXT ("(%P) Error: expected wait to time out; got %d\n"),
477 result));
478 if (result == ACE_INVALID_PID)
479 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("error")));
480 test_status = 1;
482 else
483 ACE_DEBUG ((LM_DEBUG,
484 ACE_TEXT ("(%P) Correctly timed out wait at child 5\n")));
486 // Now wait indefinitely to clean up...
487 result = mgr.wait (0, &exitcode);
489 if (result != child5)
491 ACE_ERROR ((LM_ERROR,
492 ACE_TEXT ("Error: expected to reap child5 pid %d; got %d\n"),
493 child5,
494 result));
495 if (result == ACE_INVALID_PID)
496 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("error")));
497 test_status = 1;
499 else
500 ACE_DEBUG ((LM_DEBUG,
501 ACE_TEXT ("(%P) reaped child 5, pid %d: %d\n"),
502 result,
503 exitcode));
505 // Terminate a child process and make sure we can wait for it.
506 pid_t child6 = spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
507 mgr,
510 ACE_exitcode status6;
511 if (-1 == mgr.terminate (child6))
513 ACE_ERROR ((LM_ERROR, ACE_TEXT ("(%P) %p\n"), ACE_TEXT ("terminate child6")));
514 test_status = 1;
515 mgr.wait (child6, &status6); // Wait for child to exit just to clean up
517 else
519 if (-1 == mgr.wait (child6, &status6))
521 ACE_ERROR ((LM_ERROR,
522 ACE_TEXT ("(%P) wait on child6 reported ACE_INVALID_PID\n")));
523 test_status = 1;
525 else
527 // Get the results of the termination.
528 #if !defined(ACE_WIN32)
529 if (WIFSIGNALED (status6) != 0)
530 ACE_DEBUG ((LM_DEBUG,
531 ACE_TEXT ("(%P) child6 died on signal %d - correct\n"),
532 WTERMSIG (status6)));
533 else
534 ACE_ERROR ((LM_ERROR,
535 ACE_TEXT ("(%P) child6 should have died on signal, ")
536 ACE_TEXT ("but didn't; exit status %d\n"),
537 WEXITSTATUS (status6)));
538 #else
539 ACE_DEBUG
540 ((LM_DEBUG,
541 ACE_TEXT ("(%P) The process terminated with exit code %d\n"),
542 status6));
543 #endif /*ACE_WIN32*/
547 #ifdef ACE_HAS_THREADS
548 Process_Task task1 (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"), mgr, 3);
549 Process_Task task2 (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"), mgr, 2);
550 Process_Task task3 (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"), mgr, 1);
551 task1.open (0);
552 task2.open (0);
553 task3.open (0);
555 while (running_tasks!=0)
557 ACE_OS::sleep (1);
558 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P) still running tasks\n")));
561 ACE_DEBUG ((LM_DEBUG,
562 ACE_TEXT ("(%P) result: '%C'\n"),
563 order.c_str ()));
565 if (order != "321123")
567 ACE_ERROR ((LM_ERROR,
568 ACE_TEXT ("(%P) wrong order of spawns ('%C', should be '321123')\n"),
569 order.c_str ()));
570 test_status = 1;
572 #endif /* ACE_HAS_THREADS */
574 #if !defined (ACE_OPENVMS) && \
575 (defined ACE_WIN32 || !defined ACE_LACKS_UNIX_SIGNALS)
576 // --------------------------------------------------
577 // Finally, try the reactor stuff...
578 mgr.open (ACE_Process_Manager::DEFAULT_SIZE,
579 ACE_Reactor::instance ());
581 pid_t child7 = spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
582 mgr,
585 /* pid_t child8 = */ spawn_child (argc > 0 ? argv[0] : ACE_TEXT ("Process_Manager_Test"),
586 mgr,
590 mgr.register_handler (new Exit_Handler ("specific"),
591 child7);
593 ACE_Time_Value how_long (10);
595 ACE_Reactor::instance ()->run_reactor_event_loop (how_long);
597 ACE_DEBUG ((LM_DEBUG,
598 ACE_TEXT ("(%P) Reactor loop done!\n") ));
600 size_t const nr_procs = mgr.managed ();
601 if (nr_procs != 0)
602 ACE_ERROR ((LM_ERROR,
603 ACE_TEXT ("(%P) %d processes left in manager\n"),
604 nr_procs));
605 #endif /* !defined (ACE_OPENVMS) */
606 #endif // ACE_HAS_PROCESS_SPAWN
607 ACE_END_TEST;
608 return test_status;