void run_parent (bool inherit_files) { ACE_TCHAR t[] = ACE_TEXT ("ace_testXXXXXX"); // Create tempfile. This will be tested for inheritance. ACE_TCHAR tempfile[MAXPATHLEN + 1]; if (ACE::get_temp_dir (tempfile, MAXPATHLEN - sizeof (t)) == -1) ACE_ERROR ((LM_ERROR, ACE_TEXT ("Could not get temp dir\n"))); ACE_OS::strcat (tempfile, t); ACE_HANDLE file_handle = ACE_OS::mkstemp (tempfile); if (file_handle == ACE_INVALID_HANDLE) ACE_ERROR ((LM_ERROR, ACE_TEXT ("Could not get temp filename\n"))); // Build child options ACE_TString exe_sub_dir; const char *subdir_env = ACE_OS::getenv ("ACE_EXE_SUB_DIR"); if (subdir_env) { exe_sub_dir = ACE_TEXT_CHAR_TO_TCHAR (subdir_env); exe_sub_dir += ACE_DIRECTORY_SEPARATOR_STR; } ACE_Process_Options options; options.command_line (ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR ACE_TEXT ("%sProcess_Test") ACE_PLATFORM_EXE_SUFFIX ACE_TEXT (" -c -h %d -f %s"), exe_sub_dir.c_str(), (int)inherit_files, tempfile); options.handle_inheritance (inherit_files); /* ! */ // Spawn child ACE_Process child; pid_t result = child.spawn (options); if (result == -1) ACE_ERROR ((LM_ERROR, ACE_TEXT ("Parent could NOT spawn child process\n"))); else ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Parent spawned child process with pid = %d.\n"), child.getpid ())); ACE_exitcode child_status; result = child.wait (&child_status); if (result == -1) ACE_ERROR ((LM_ERROR, ACE_TEXT ("Could NOT wait on child process\n"))); else if (child_status == 0) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Child %d finished ok\n"), child.getpid ())); else ACE_ERROR ((LM_ERROR, ACE_TEXT ("Child %d finished with status %d\n"), child.getpid (), child_status)); }
int run_main (int, ACE_TCHAR *[]) { ACE_START_TEST (ACE_TEXT ("Time_Service_Test")); // Make sure that the backing store is not there. We need to make // sure because this test kills the Time Clerk and on some platforms // the Clerk is not allowed to do a graceful shutdown. By cleaning // the backing store here, we are sure that we get a fresh start and // no garbage data from a possible aborted run ACE_TCHAR backing_store[MAXPATHLEN + 1]; #if defined (ACE_DEFAULT_BACKING_STORE) // Create a temporary file. ACE_OS::strcpy (backing_store, ACE_DEFAULT_BACKING_STORE); #else /* ACE_DEFAULT_BACKING_STORE */ if (ACE::get_temp_dir (backing_store, MAXPATHLEN - 17) == -1) // -17 for ace-malloc-XXXXXX { ACE_ERROR ((LM_ERROR, ACE_TEXT ("Temporary path too long, ") ACE_TEXT ("defaulting to current directory\n"))); backing_store[0] = 0; } // Add the filename to the end ACE_OS::strcat (backing_store, ACE_TEXT ("ace-malloc-XXXXXX")); #endif /* ACE_DEFAULT_BACKING_STORE */ ACE_OS::unlink (backing_store); const ACE_TCHAR *server_cl = APPLICATION ACE_TEXT ("server.conf"); ACE_Process_Options server_options; server_options.command_line (server_cl); ACE_Process server; if (server.spawn (server_options) == -1) ACE_ERROR_RETURN ((LM_DEBUG, ACE_TEXT ("%n; %p (%s).\n"), ACE_TEXT ("Server fork failed"), server_cl), -1); else ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Server forked with pid = %d.\n"), server.getpid ())); ACE_OS::sleep (3); const ACE_TCHAR *clerk_cl = APPLICATION ACE_TEXT ("clerk.conf"); ACE_Process_Options clerk_options; clerk_options.command_line (clerk_cl); ACE_Process clerk; if (clerk.spawn (clerk_options) == -1) ACE_ERROR_RETURN ((LM_DEBUG, ACE_TEXT ("%n; %p: (%s).\n"), ACE_TEXT ("Clerk fork failed"), clerk_cl), -1); else ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Clerk forked with pid = %d.\n"), clerk.getpid ())); ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Sleeping...\n"))); ACE_OS::sleep (10); if (clerk.terminate () == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Terminate failed for clerk.\n")), -1); if (server.terminate () == -1) ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Terminate failed for server.\n")), -1); // Because we kill the clerk process, on Win32 it may not do a // graceful shutdown and the backing store file is left behind. if (clerk.wait () != 0) ACE_OS::unlink (backing_store); ACE_END_TEST; return 0; }
pid_t ACE_Process_Manager::wait (pid_t pid, const ACE_Time_Value &timeout, ACE_exitcode *status) { ACE_TRACE ("ACE_Process_Manager::wait"); ACE_exitcode local_stat = 0; if (status == 0) status = &local_stat; *status = 0; ssize_t idx = -1; ACE_Process *proc = 0; { // fake context after which the lock is released ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); if (pid != 0) { idx = this->find_proc (pid); if (idx == -1) return ACE_INVALID_PID; else proc = process_table_[idx].process_; } // release the lock. } if (proc != 0) pid = proc->wait (timeout, status); else { ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); // Wait for any Process spawned by this Process_Manager. #if defined (ACE_WIN32) HANDLE *handles = 0; ACE_NEW_RETURN (handles, HANDLE[this->current_count_], ACE_INVALID_PID); for (size_t i = 0; i < this->current_count_; ++i) handles[i] = process_table_[i].process_->gethandle (); DWORD handle_count = static_cast<DWORD> (this->current_count_); DWORD result = ::WaitForMultipleObjects (handle_count, handles, FALSE, timeout == ACE_Time_Value::max_time ? INFINITE : timeout.msec ()); if (result == WAIT_FAILED) pid = ACE_INVALID_PID; else if (result == WAIT_TIMEOUT) pid = 0; else { // Green Hills produces a warning that result >= // WAIT_OBJECT_0 is a pointless comparison because // WAIT_OBJECT_0 is zero and DWORD is unsigned long, so this // test is skipped for Green Hills. Same for mingw. # if defined (ghs) || defined (__MINGW32__) || defined (_MSC_VER) ACE_ASSERT (result < WAIT_OBJECT_0 + this->current_count_); # else ACE_ASSERT (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + this->current_count_); # endif idx = this->find_proc (handles[result - WAIT_OBJECT_0]); if (idx != -1) { pid = process_table_[idx].process_->getpid (); result = ::GetExitCodeProcess (handles[result - WAIT_OBJECT_0], status); if (result == 0) { // <GetExitCodeProcess> failed! this->remove_proc (idx); pid = ACE_INVALID_PID; } } else { // uh oh...handle removed from process_table_, even though // we're holding a lock! delete [] handles; ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("Process removed") ACE_TEXT (" -- somebody's ignoring the lock!\n")), -1); } } delete [] handles; #else /* !defined(ACE_WIN32) */ if (timeout == ACE_Time_Value::max_time) pid = ACE_OS::waitpid (-1, status, 0); else if (timeout == ACE_Time_Value::zero) pid = ACE_OS::waitpid (-1, status, WNOHANG); else { # if defined (ACE_LACKS_UNIX_SIGNALS) pid = 0; ACE_Time_Value sleeptm (1); // 1 msec if (sleeptm > timeout) // if sleeptime > waittime sleeptm = timeout; ACE_Time_Value tmo (timeout); // Need one we can change for (ACE_Countdown_Time time_left (&tmo); tmo > ACE_Time_Value::zero ; time_left.update ()) { pid = ACE_OS::waitpid (-1, status, WNOHANG); if (pid > 0 || pid == ACE_INVALID_PID) break; // Got a child or an error - all done // pid 0, nothing is ready yet, so wait. // Do a (very) short sleep (only this thread sleeps). ACE_OS::sleep (sleeptm); } # else // Force generation of SIGCHLD, even though we don't want to // catch it - just need it to interrupt the sleep below. // If this object has a reactor set, assume it was given at // open(), and there's already a SIGCHLD action set, so no // action is needed here. ACE_Sig_Action old_action; if (this->reactor () == 0) { ACE_Sig_Action do_sigchld ((ACE_SignalHandler)sigchld_nop); do_sigchld.register_action (SIGCHLD, &old_action); } ACE_Time_Value tmo (timeout); // Need one we can change for (ACE_Countdown_Time time_left (&tmo); ; time_left.update ()) { pid = ACE_OS::waitpid (-1, status, WNOHANG); # if defined (ACE_VXWORKS) && (ACE_VXWORKS >= 0x600) if (pid > 0 || (pid == ACE_INVALID_PID && errno != EINTR)) # else if (pid > 0 || pid == ACE_INVALID_PID) # endif break; // Got a child or an error - all done // pid 0, nothing is ready yet, so wait. // Do a sleep (only this thread sleeps) til something // happens. This relies on SIGCHLD interrupting the sleep. // If SIGCHLD isn't delivered, we'll need to do something // with sigaction to force it. if (-1 == ACE_OS::sleep (tmo) && errno == EINTR) continue; // Timed out pid = 0; break; } // Restore the previous SIGCHLD action if it was changed. if (this->reactor () == 0) old_action.register_action (SIGCHLD); # endif /* !ACE_LACKS_UNIX_SIGNALS */ } #endif /* !defined (ACE_WIN32) */ } ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, this->lock_, -1)); if (pid != ACE_INVALID_PID && pid != 0) { //we always need to get our id, because we could have been moved in the table meanwhile idx = this->find_proc (pid); if (idx == -1) { // oops, reaped an unmanaged process! ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) oops, reaped unmanaged %d\n"), pid)); return pid; } else proc = process_table_[idx].process_; if (proc != 0) ACE_ASSERT (pid == proc->getpid ()); this->notify_proc_handler (idx, *status); this->remove (pid); } return pid; }
int run_main (int argc, ACE_TCHAR *argv[]) { parse_args (argc, argv); if (child_process) { ACE_APPEND_LOG (ACE_TEXT("Pipe_Test-children")); ACE_Pipe a, b, c, d, e; open_pipe (a, "a"); open_pipe (b, "b"); open_pipe (c, "c"); open_pipe (d, "d"); open_pipe (e, "e"); ACE_END_LOG; } else { ACE_START_TEST (ACE_TEXT("Pipe_Test")); ACE_INIT_LOG (ACE_TEXT("Pipe_Test-children")); # if defined (ACE_WIN32) || !defined (ACE_USES_WCHAR) const ACE_TCHAR *cmdline_fmt = ACE_TEXT ("%s -c%s"); # else const ACE_TCHAR *cmdline_fmt = ACE_TEXT ("%ls -c%ls"); # endif /* ACE_WIN32 || !ACE_USES_WCHAR */ ACE_Process_Options options; options.command_line (cmdline_fmt, argc > 0 ? argv[0] : ACE_TEXT ("Pipe_Test"), close_pipe == 0 ? ACE_TEXT (" -d") : ACE_TEXT ("")); ACE_exitcode status = 0; for (int i = 0; i < ::iterations; i++) { ACE_Process server; if (server.spawn (options) == -1) { ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn failed")), -1); } else { ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Server forked with pid = %d.\n"), server.getpid ())); } // Wait for the process we just created to exit. server.wait (&status); // Check if child exited without error. if (WIFEXITED (status) != 0 && WEXITSTATUS (status) != 0) { ACE_ERROR ((LM_ERROR, ACE_TEXT ("Child of server %d finished with error ") ACE_TEXT ("exit status %d\n"), server.getpid (), WEXITSTATUS (status))); ACE_END_TEST; ACE_OS::exit (WEXITSTATUS (status)); } ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Server %d finished\n"), server.getpid ())); } ACE_END_TEST; } return 0; }
int run_main (int argc, ACE_TCHAR *argv[]) { #if defined (ACE_LACKS_FORK) ACE_UNUSED_ARG (argc); ACE_UNUSED_ARG (argv); ACE_START_TEST (ACE_TEXT ("Process_Semaphore_Test")); ACE_ERROR ((LM_INFO, ACE_TEXT ("fork is not supported on this platform\n"))); ACE_END_TEST; #else parse_args (argc, argv); // Child process code. if (child_process) { ACE_START_TEST (ACE_TEXT ("Process_Semaphore_Test-child")); acquire_release (); ACE_END_LOG; } else { ACE_START_TEST (ACE_TEXT ("Process_Semaphore_Test")); ACE_TString exe_sub_dir; const char *subdir_env = ACE_OS::getenv ("ACE_EXE_SUB_DIR"); if (subdir_env) { exe_sub_dir = ACE_TEXT_CHAR_TO_TCHAR (subdir_env); exe_sub_dir += ACE_DIRECTORY_SEPARATOR_STR; } ACE_Process_Options options; options.command_line (ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR ACE_TEXT ("%sProcess_Semaphore_Test") ACE_PLATFORM_EXE_SUFFIX ACE_TEXT (" -c -i %d"), exe_sub_dir.c_str(), iterations); // Spawn a child process that will contend for the // lock. ACE_Process child; // Spawn the child process. int result = child.spawn (options); ACE_TEST_ASSERT (result != -1); ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Parent spawned child process with pid = %d.\n"), child.getpid ())); // start test acquire_release (); ACE_exitcode child_status; // Wait for the child processes we created to exit. ACE_TEST_ASSERT (child.wait (&child_status) != -1); if (child_status == 0) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("Child %d finished ok\n"), child.getpid ())); else ACE_ERROR ((LM_ERROR, ACE_TEXT ("Child %d finished with status %d\n"), child.getpid (), child_status)); ACE_END_TEST; } #endif /* ! ACE_LACKS_FORK */ return 0; }