// -*- c++ -*- //------------------------------------------------------------------------------ // fork_test.cpp //------------------------------------------------------------------------------ // $Id: fork_test.cpp,v 1.5 2006/07/20 02:30:55 vlg Exp $ //------------------------------------------------------------------------------ // Copyright (c) 2002,2005 by Vladislav Grinchenko // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version // 2 of the License, or (at your option) any later version. //------------------------------------------------------------------------------ /*------------------------------------------------------------------------------ This is what happens in the test: main | fork / \ fork A (WAIT) for (5 times) { sleep(1); print msg } / \ / \ / \ / \ / B (KILL) fork / \ / C (WAIT) for (5 times) { sleep(2); print msg } / done Child B is killed immediately after main() exits. SIGTERM is sent to child A and C and parent process waits for them to finish. First finishes A, and then C. Process D is not in the picuture because its state flag is LEAVE_ALONE. init will become its parent and it shall be killed separately. ------------------------------------------------------------------------*/ #include #include using namespace std; #include "assa/Logger.h" #include "assa/Fork.h" using namespace ASSA; int main (int argc, char** argv) { std::cout << "= Running fork_test Test =" << std::endl; ::unlink ("fork_A.log"); ::unlink ("fork_B.log"); ::unlink ("fork_C.log"); ::unlink ("fork_D.log"); ::unlink ("fork_test.log"); #if defined (WIN32) std::cout << "= Running fork_test Test =\n" << "Spanning 3 child processes: A, B, and C\n" << "First B shall be terminated, then wait for A and C to finish.\n" << "Parent: forking A ...\n" << "Parent: forking B ...\n" << "Parent: forking C ...\n" << "Parent: forking D ...\n"; #else // Log::open_log_file ("fork_test.log", APP); Log::open_log_stdout (APP); // Just test that it works at all DL((APP,"Spanning 3 child processes: A, B, and C\n")); DL((APP,"First B shall be terminated, then wait for A and " "C to finish.\n")); DL((APP,"Parent: forking A ...\n")); LOGGER->log_resync (); Fork a (Fork::WAIT_ON_EXIT, Fork::IGNORE_STATUS); if (a.isParent()) { DL((APP,"Parent: forking B ...\n")); LOGGER->log_resync (); Fork b (Fork::KILL_ON_EXIT, Fork::IGNORE_STATUS); if (b.isParent()) { DL((APP,"Parent: forking C ...\n")); LOGGER->log_resync (); Fork c (Fork::WAIT_ON_EXIT, Fork::IGNORE_STATUS); if (c.isParent()) { DL((APP,"Parent: forking D ...\n")); LOGGER->log_resync (); Fork d (Fork::LEAVE_ALONE, Fork::IGNORE_STATUS); if ( d.isParent() ) { //zombie = d.getChildPID (); } else { // Child D Log::log_close (); Log::open_log_file ("fork_D.log", APP); DL((APP,"In child D ... sleeping 20 seconds.\n")); sleep (20); } /* Exiting will trigger ForkList destructor * that suppose to collect exiting status of children */ } else if (c.isChild()) { Log::log_close (); Log::open_log_file ("fork_C.log", APP); DL((APP,"In child C ..." " print 5 msgs with 2 sec interval.\n")); for (int i=0; i<5; i++) { sleep(2); DL((APP,"[%1d] child < C > is here\n", i+1)); } DL((APP,"child C exits!\n")); return 0; } } else if (b.isChild()) { Log::log_close (); Log::open_log_file ("fork_B.log", APP); DL((APP,"In child B - you should see it just once.\n")); sleep(12); /* * you normally won't see this message becuase * parent suppose to terminate this child with SIGTERM */ DL((APP,"child B exits!\n")); return 0; } } else if (a.isChild()) { Log::log_close (); Log::open_log_file ("fork_A.log", APP); DL((APP,"In child A ... print 5 msgs with 1 sec interval.\n")); for (int j=0; j<5; j++) { sleep(1); DL((APP,"[%d] child < A > is here\n", j+1)); } DL((APP, "child A exits!\n")); return 0; } #endif // !ifdef WIN32 return 0; }