int ACE_TMAIN (int argc, ACE_TCHAR *argv[]) { // Estabish call backs and socket names. port1 = argc > 1 ? ACE_OS::atoi (argv[1]) : ACE_DEFAULT_SERVER_PORT; const ACE_TCHAR *remotehost = argc > 2 ? argv[2] : ACE_DEFAULT_SERVER_HOST; const u_short port2 = argc > 3 ? ACE_OS::atoi (argv[3]) : port1 + 1; // Providing the fourth command line argument indicate we don't want // to spawn a new process. On Win32, we use this to exec the new // program. if (argc > 4) run_test (port1, remotehost, port2, argv[4]); else { ACE_DEBUG ((LM_DEBUG, "(%P|%t) local port = %d, remote host = %s, remote port = %d\n", port1, remotehost, port2)); ACE_Process_Options options; options.command_line (ACE_TEXT ("%s %d %s %d %c"), argv[0], port1, remotehost, port2, 'c'); // This has no effect on NT and will spawn a process that exec // the above run_test function. options.creation_flags (ACE_Process_Options::NO_EXEC); ACE_Process new_process; switch (new_process.spawn (options)) { case -1: return -1; case 0: run_test (port1, remotehost, port2, ACE_TEXT("peer1")); break; default: run_test (port2, remotehost, port1, ACE_TEXT("peer2")); new_process.wait (); break; } } return 0; }
static double prof_ace_process (size_t iteration) { if (iteration != 0) { ACE_Process_Options popt; ACE_Process aProcess; popt.command_line (SUBPROGRAM); iteration *= MULTIPLY_FACTOR; if (do_exec_after_fork == 0) popt.creation_flags (ACE_Process_Options::NO_EXEC); ACE_Profile_Timer ptimer; ACE_Profile_Timer::ACE_Elapsed_Time et; double time = 0; pid_t result; for (size_t c = 0; c < iteration; c++) { ACE_STOP_SIGN; ptimer.start (); result = aProcess.spawn (popt); ptimer.stop (); if (result == -1) ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "process.spawn"), -1); else if (do_exec_after_fork == 0 && result == 0) ACE_OS::exit (0) ; else { ptimer.elapsed_time (et); time += et.real_time; } } return time / iteration; } else return -1.0; }
pid_t ACE_Process::spawn (ACE_Process_Options &options) { if (this->prepare (options) < 0) return ACE_INVALID_PID; // Stash the passed/duped handle sets away in this object for later // closing if needed or requested. At the same time, figure out which // ones to include in command line options if that's needed below. ACE_Handle_Set *set_p = 0; if (options.dup_handles (this->dup_handles_)) set_p = &this->dup_handles_; else if (options.passed_handles (this->handles_passed_)) set_p = &this->handles_passed_; // If we are going to end up running a new program (i.e. Win32, or // NO_EXEC option is set) then get any handles passed in the options, // and tack them onto the command line with +H <handle> options, // unless the command line runs out of space. // Note that we're using the knowledge that all the options, argvs, etc. // passed to the options are all sitting in the command_line_buf. Any // call to get the argv then splits them out. So, regardless of the // platform, tack them all onto the command line buf and take it // from there. if (set_p && !ACE_BIT_ENABLED (options.creation_flags (), ACE_Process_Options::NO_EXEC)) { int maxlen = 0; ACE_TCHAR *cmd_line_buf = options.command_line_buf (&maxlen); size_t max_len = static_cast<size_t> (maxlen); size_t curr_len = ACE_OS::strlen (cmd_line_buf); ACE_Handle_Set_Iterator h_iter (*set_p); // Because the length of the to-be-formatted +H option is not // known, and we don't have a snprintf, guess at the space // needed (20 chars), and use that as a limit. for (ACE_HANDLE h = h_iter (); h != ACE_INVALID_HANDLE && curr_len + 20 < max_len; h = h_iter ()) { #if defined (ACE_WIN32) # if defined (ACE_WIN64) curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len], ACE_TEXT (" +H %I64p"), h); # else curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len], ACE_TEXT (" +H %p"), h); # endif /* ACE_WIN64 */ #else curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len], ACE_TEXT (" +H %d"), h); #endif /* ACE_WIN32 */ } } #if defined (ACE_HAS_WINCE) // Note that WinCE does not have process name included in the command line as argv[0] // like other OS environment. Therefore, it is user's whole responsibility to call // 'ACE_Process_Options::process_name(const ACE_TCHAR *name)' to set the proper // process name (the execution file name with path if needed). BOOL fork_result = ACE_TEXT_CreateProcess (options.process_name(), options.command_line_buf(), options.get_process_attributes(), // must be NULL in CE options.get_thread_attributes(), // must be NULL in CE options.handle_inheritance(), // must be false in CE options.creation_flags(), // must be NULL in CE options.env_buf(), // environment variables, must be NULL in CE options.working_directory(), // must be NULL in CE options.startup_info(), // must be NULL in CE &this->process_info_); if (fork_result) { parent (this->getpid ()); return this->getpid (); } return ACE_INVALID_PID; #elif defined (ACE_WIN32) void* env_buf = options.env_buf (); DWORD flags = options.creation_flags (); # if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR) wchar_t* wenv_buf = 0; if (options.use_unicode_environment ()) { wenv_buf = this->convert_env_buffer (options.env_buf ()); env_buf = wenv_buf; flags |= CREATE_UNICODE_ENVIRONMENT; } # endif BOOL fork_result = ACE_TEXT_CreateProcess (0, options.command_line_buf (), options.get_process_attributes (), options.get_thread_attributes (), options.handle_inheritance (), flags, env_buf, // environment variables options.working_directory (), options.startup_info (), &this->process_info_); # if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR) if (options.use_unicode_environment ()) delete wenv_buf; # endif if (fork_result) { parent (this->getpid ()); return this->getpid (); } return ACE_INVALID_PID; #elif defined(ACE_OPENVMS) if (ACE_BIT_ENABLED (options.creation_flags (), ACE_Process_Options::NO_EXEC)) ACE_NOTSUP_RETURN (ACE_INVALID_PID); int saved_stdin = ACE_STDIN; int saved_stdout = ACE_STDOUT; int saved_stderr = ACE_STDERR; // Save STD file descriptors and redirect if (options.get_stdin () != ACE_INVALID_HANDLE) { if ((saved_stdin = ACE_OS::dup (ACE_STDIN)) == -1 && errno != EBADF) ACE_OS::exit (errno); if (ACE_OS::dup2 (options.get_stdin (), ACE_STDIN) == -1) ACE_OS::exit (errno); } if (options.get_stdout () != ACE_INVALID_HANDLE) { if ((saved_stdout = ACE_OS::dup (ACE_STDOUT)) == -1 && errno != EBADF) ACE_OS::exit (errno); if (ACE_OS::dup2 (options.get_stdout (), ACE_STDOUT) == -1) ACE_OS::exit (errno); } if (options.get_stderr () != ACE_INVALID_HANDLE) { if ((saved_stderr = ACE_OS::dup (ACE_STDERR)) == -1 && errno != EBADF) ACE_OS::exit (errno); if (ACE_OS::dup2 (options.get_stderr (), ACE_STDERR) == -1) ACE_OS::exit (errno); } if (options.working_directory () != 0) ACE_NOTSUP_RETURN (ACE_INVALID_PID); this->child_id_ = vfork(); if (this->child_id_ == 0) { ACE_OS::execvp (options.process_name (), options.command_line_argv ()); // something went wrong this->child_id_ = ACE_INVALID_PID; } // restore STD file descriptors (if necessary) if (options.get_stdin () != ACE_INVALID_HANDLE) { if (saved_stdin == -1) ACE_OS::close (ACE_STDIN); else ACE_OS::dup2 (saved_stdin, ACE_STDIN); } if (options.get_stdout () != ACE_INVALID_HANDLE) { if (saved_stdout == -1) ACE_OS::close (ACE_STDOUT); else ACE_OS::dup2 (saved_stdout, ACE_STDOUT); } if (options.get_stderr () != ACE_INVALID_HANDLE) { if (saved_stderr == -1) ACE_OS::close (ACE_STDERR); else ACE_OS::dup2 (saved_stderr, ACE_STDERR); } return this->child_id_; #elif defined (ACE_VXWORKS) && defined (__RTP__) if (ACE_BIT_ENABLED (options.creation_flags (), ACE_Process_Options::NO_EXEC)) ACE_NOTSUP_RETURN (ACE_INVALID_PID); if (options.working_directory () != 0) ACE_NOTSUP_RETURN (ACE_INVALID_PID); int saved_stdin = ACE_STDIN; int saved_stdout = ACE_STDOUT; int saved_stderr = ACE_STDERR; // Save STD file descriptors and redirect if (options.get_stdin () != ACE_INVALID_HANDLE) { if ((saved_stdin = ACE_OS::dup (ACE_STDIN)) == -1 && errno != EBADF) ACE_OS::exit (errno); if (ACE_OS::dup2 (options.get_stdin (), ACE_STDIN) == -1) ACE_OS::exit (errno); } if (options.get_stdout () != ACE_INVALID_HANDLE) { if ((saved_stdout = ACE_OS::dup (ACE_STDOUT)) == -1 && errno != EBADF) ACE_OS::exit (errno); if (ACE_OS::dup2 (options.get_stdout (), ACE_STDOUT) == -1) ACE_OS::exit (errno); } if (options.get_stderr () != ACE_INVALID_HANDLE) { if ((saved_stderr = ACE_OS::dup (ACE_STDERR)) == -1 && errno != EBADF) ACE_OS::exit (errno); if (ACE_OS::dup2 (options.get_stderr (), ACE_STDERR) == -1) ACE_OS::exit (errno); } // Wide-char builds need narrow-char strings for commandline and // environment variables. # if defined (ACE_USES_WCHAR) wchar_t * const *wargv = options.command_line_argv (); size_t vcount, i; for (vcount = 0; wargv[vcount] != 0; ++vcount) ; char **procargv = new char *[vcount + 1]; // Need 0 at the end procargv[vcount] = 0; for (i = 0; i < vcount; ++i) procargv[i] = ACE_Wide_To_Ascii::convert (wargv[i]); char **procenv = 0; if (options.inherit_environment ()) { wargv = options.env_argv (); for (vcount = 0; wargv[vcount] != 0; ++vcount) ; procenv = new char *[vcount + 1]; // Need 0 at the end procenv[vcount] = 0; for (i = 0; i < vcount; ++i) procenv[i] = ACE_Wide_To_Ascii::convert (wargv[i]); } # else const char **procargv = const_cast<const char**> (options.command_line_argv ()); const char **procenv = const_cast<const char**> (options.env_argv ()); # endif /* ACE_USES_WCHAR */ this->child_id_ = ::rtpSpawn (procargv[0], procargv, procenv, 200, // priority 0x10000, // uStackSize 0, // options VX_FP_TASK); // taskOptions int my_errno_ = errno; if (this->child_id_ == ERROR) { // something went wrong this->child_id_ = ACE_INVALID_PID; } # if defined (ACE_USES_WCHAR) if (procenv) delete procenv; # endif /* ACE_USES_WCHAR */ // restore STD file descriptors (if necessary) if (options.get_stdin () != ACE_INVALID_HANDLE) { if (saved_stdin == -1) ACE_OS::close (ACE_STDIN); else ACE_OS::dup2 (saved_stdin, ACE_STDIN); } if (options.get_stdout () != ACE_INVALID_HANDLE) { if (saved_stdout == -1) ACE_OS::close (ACE_STDOUT); else ACE_OS::dup2 (saved_stdout, ACE_STDOUT); } if (options.get_stderr () != ACE_INVALID_HANDLE) { if (saved_stderr == -1) ACE_OS::close (ACE_STDERR); else ACE_OS::dup2 (saved_stderr, ACE_STDERR); } if (this->child_id_ == ACE_INVALID_PID) { errno = my_errno_; } return this->child_id_; #else /* ACE_WIN32 */ // Fork the new process. this->child_id_ = ACE::fork (options.process_name (), options.avoid_zombies ()); if (this->child_id_ == 0) { # if !defined (ACE_LACKS_SETPGID) // If we're the child and the options specified a non-default // process group, try to set our pgid to it. This allows the // <ACE_Process_Manager> to wait for processes by their // process-group. if (options.getgroup () != ACE_INVALID_PID && ACE_OS::setpgid (0, options.getgroup ()) < 0) { #if !defined (ACE_HAS_THREADS) // We can't emit this log message because ACE_ERROR(), etc. // will invoke async signal unsafe functions, which results // in undefined behavior in threaded programs. ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p.\n"), ACE_TEXT ("ACE_Process::spawn: setpgid failed."))); #endif } # endif /* ACE_LACKS_SETPGID */ # if !defined (ACE_LACKS_SETREGID) if (options.getrgid () != (uid_t) -1 || options.getegid () != (uid_t) -1) if (ACE_OS::setregid (options.getrgid (), options.getegid ()) == -1) { #if !defined (ACE_HAS_THREADS) // We can't emit this log message because ACE_ERROR(), etc. // will invoke async signal unsafe functions, which results // in undefined behavior in threaded programs. ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p.\n"), ACE_TEXT ("ACE_Process::spawn: setregid failed."))); #endif } # endif /* ACE_LACKS_SETREGID */ # if !defined (ACE_LACKS_SETREUID) // Set user and group id's. if (options.getruid () != (uid_t) -1 || options.geteuid () != (uid_t) -1) if (ACE_OS::setreuid (options.getruid (), options.geteuid ()) == -1) { #if !defined (ACE_HAS_THREADS) // We can't emit this log message because ACE_ERROR(), etc. // will invoke async signal unsafe functions, which results // in undefined behavior in threaded programs. ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p.\n"), ACE_TEXT ("ACE_Process::spawn: setreuid failed."))); #endif } # endif /* ACE_LACKS_SETREUID */ this->child (ACE_OS::getppid ()); } else if (this->child_id_ != -1) this->parent (this->child_id_); // If we're not supposed to exec, return the process id. if (ACE_BIT_ENABLED (options.creation_flags (), ACE_Process_Options::NO_EXEC)) return this->child_id_; switch (this->child_id_) { case -1: // Error. return ACE_INVALID_PID; case 0: // Child process...exec the { if (options.get_stdin () != ACE_INVALID_HANDLE && ACE_OS::dup2 (options.get_stdin (), ACE_STDIN) == -1) ACE_OS::exit (errno); else if (options.get_stdout () != ACE_INVALID_HANDLE && ACE_OS::dup2 (options.get_stdout (), ACE_STDOUT) == -1) ACE_OS::exit (errno); else if (options.get_stderr () != ACE_INVALID_HANDLE && ACE_OS::dup2 (options.get_stderr (), ACE_STDERR) == -1) ACE_OS::exit (errno); // close down unneeded descriptors ACE_OS::close (options.get_stdin ()); ACE_OS::close (options.get_stdout ()); ACE_OS::close (options.get_stderr ()); if (!options.handle_inheritance ()) { // Set close-on-exec for all FDs except standard handles for (int i = ACE::max_handles () - 1; i >= 0; i--) { if (i == ACE_STDIN || i == ACE_STDOUT || i == ACE_STDERR) continue; ACE_OS::fcntl (i, F_SETFD, FD_CLOEXEC); } } // If we must, set the working directory for the child // process. if (options.working_directory () != 0) ACE_OS::chdir (options.working_directory ()); // Should check for error here! // Child process executes the command. int result = 0; // Wide-char builds not on Windows need narrow-char strings for // exec() and environment variables. Don't need to worry about // releasing any of the converted string memory since this // process will either exec() or exit() shortly. # if defined (ACE_USES_WCHAR) ACE_Wide_To_Ascii n_procname (options.process_name ()); const char *procname = n_procname.char_rep (); wchar_t * const *wargv = options.command_line_argv (); size_t vcount, i; for (vcount = 0; wargv[vcount] != 0; ++vcount) ; char **procargv = new char *[vcount + 1]; // Need 0 at the end procargv[vcount] = 0; for (i = 0; i < vcount; ++i) procargv[i] = ACE_Wide_To_Ascii::convert (wargv[i]); wargv = options.env_argv (); for (vcount = 0; wargv[vcount] != 0; ++vcount) ; char **procenv = new char *[vcount + 1]; // Need 0 at the end procenv[vcount] = 0; for (i = 0; i < vcount; ++i) procenv[i] = ACE_Wide_To_Ascii::convert (wargv[i]); # else const char *procname = options.process_name (); char *const *procargv = options.command_line_argv (); char *const *procenv = options.env_argv (); # endif /* ACE_USES_WCHAR */ if (options.inherit_environment ()) { // Add the new environment variables to the environment // context of the context before doing an <execvp>. for (size_t i = 0; procenv[i] != 0; i++) if (ACE_OS::putenv (procenv[i]) != 0) return ACE_INVALID_PID; // Now the forked process has both inherited variables and // the user's supplied variables. result = ACE_OS::execvp (procname, procargv); } else { result = ACE_OS::execve (procname, procargv, procenv); } if (result == -1) { // If the execv fails, this child needs to exit. // Exit with the errno so that the calling process can // catch this and figure out what went wrong. ACE_OS::_exit (errno); } // ... otherwise, this is never reached. return 0; } default: // Server process. The fork succeeded. return this->child_id_; } #endif /* ACE_WIN32 */ }
int Service_Monitor::svc(void) { ACE_OS::printf("(%u) Service_Monitor starting up...\n", ACE_OS::thr_self()); int use_svm_ini = 0; // Get_Opt ACE_Get_Opt cmd(this->argc_, this->argv_); cmd.long_option(ACE_TEXT("svm"), ACE_Get_Opt::NO_ARG); cmd.long_option(ACE_TEXT("svc"), ACE_Get_Opt::NO_ARG); int ch; while( (ch = cmd()) != EOF ) { switch(ch) { case 0: if ( ACE_OS::strcasecmp(cmd.last_option(), "svm") == 0 ) use_svm_ini = 1; break; } } // load monitors ( use_svm_ini )?this->load("svm.ini"):this->import_svc_ini("svc.ini"); Service_Control sc(0, 0); sc.load("svc.ini"); ACE_Process_Manager* pm = ACE_Process_Manager::instance(); size_t n_count = 0; while( !stop_.value() ) { { ACE_GUARD_RETURN(ACE_Thread_Mutex, guard, this->lock_, -1); for(MONITORS::iterator it = monitors_.begin(); it != monitors_.end(); ++it) { if ( it->second > 0 && n_count % it->second == 0 ) { const char* service = it->first.c_str(); int rc = 0; //+ get pid first. if connected, don't call start() int plock = sc.plock(service); // pid_t p_id = sc.pid(service); if ( !plock ) // if ( p_id < 0 ) { std::string cmd("."); cmd += ACE_DIRECTORY_SEPARATOR_CHAR; cmd += "svc "; cmd += service; cmd += " start"; /* //?? better to wake up service by system() ACE_OS::system(cmd.c_str()); //*/ ACE_Process_Options opt; opt.command_line(cmd.c_str()); #ifdef ACE_WIN32 opt.creation_flags(CREATE_NO_WINDOW); #endif ///* pid_t start_pid = pm->spawn(opt); if ( start_pid != ACE_INVALID_PID ) pm->wait(start_pid); //*/ // log: service is starting again char buf[256]; int n_buf = ACE_OS::snprintf(buf, 255, "[%s] is starting again!\n", service); SVM_LOG->log(buf, n_buf); //ACE_OS::printf("%s", buf); //@ /* Service_Control::SERVICES::const_iterator iter = sc.find(service); if ( iter != sc.end() ) { rc = sc.start(service, iter->second.c_str()); const char* time_to_wait = 0; pid_t start_pid = sc.wait_for_start(service, time_to_wait); // log: service is starting again //+ log restart event here!! char buf[256]; int n_buf = ACE_OS::snprintf(buf, 255, "[%s] is starting again!\n", service); SVM_LOG->log(buf, n_buf); //SVM_LOGGER()->log(buf, n_buf, &ACE_OS::gettimeofday()); } else { rc = -1; //+ log: service is not found // don't log?? ACE_OS::printf("%d\t[%s]\tservice command is not found!\n", rc, service); //@ } //*/ } else { //+ log: service is already running // don't log?? ACE_OS::printf("+%d\t[%s]\tservice is still running!\n", rc, service); //@ } } } } ++n_count; ACE_Time_Value sleep_tv; sleep_tv.set(0.1); for(int i=0; i<10; ++i) { if ( stop_.value() ) break; ACE_OS::sleep(sleep_tv); } } //pm->wait(); ACE_OS::printf("(%u) Service_Monitor shutting down...\n", ACE_OS::thr_self()); return 0; }
static pid_t spawn_child (const ACE_TCHAR *argv0, ACE_Process_Manager &mgr, int sleep_time, int my_process_id) { #if defined (ACE_HAS_WINCE) const ACE_TCHAR *cmdline_format = ACE_TEXT("%s %d"); #elif defined (ACE_WIN32) const ACE_TCHAR *cmdline_format = ACE_TEXT("\"%s\" %s %d"); #elif !defined (ACE_USES_WCHAR) const ACE_TCHAR *cmdline_format = ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR ACE_TEXT("%s %s %d"); #else const ACE_TCHAR *cmdline_format = ACE_TEXT (".") ACE_DIRECTORY_SEPARATOR_STR ACE_TEXT("%ls %ls %d"); #endif ACE_Process_Options opts; ACE_TCHAR prio[64]; ACE_TCHAR cmd[16]; if (debug_test) ACE_OS::strcpy (cmd, ACE_TEXT ("-d")); else cmd[0] = ACE_TEXT ('\0'); #if defined (ACE_HAS_WIN32_PRIORITY_CLASS) if (my_process_id == 1) { opts.creation_flags (ABOVE_NORMAL_PRIORITY_CLASS); ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'above normal'")); } else if (my_process_id == 2) { opts.creation_flags (BELOW_NORMAL_PRIORITY_CLASS); ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'below normal'")); } else if (my_process_id == 3) { opts.creation_flags (IDLE_PRIORITY_CLASS); ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'idle'")); } else if (my_process_id == 4) { opts.creation_flags (HIGH_PRIORITY_CLASS); ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'high'")); } else if (my_process_id == 5) { opts.creation_flags (NORMAL_PRIORITY_CLASS); ACE_OS::snprintf (prio, 64, ACE_TEXT ("and priority 'normal'")); } else prio[0] = ACE_TEXT ('\0'); ACE_TCHAR pd [16]; ACE_OS::snprintf (pd, 16, ACE_TEXT (" -p %d"), my_process_id); ACE_OS::strcat (cmd, pd); #else ACE_UNUSED_ARG (my_process_id); prio[0] = ACE_TEXT ('\0'); #endif opts.process_name (argv0); #ifndef ACE_LACKS_VA_FUNCTIONS opts.command_line (cmdline_format, #if !defined (ACE_HAS_WINCE) argv0, #endif /* !ACE_HAS_WINCE */ cmd, sleep_time); #else ACE_UNUSED_ARG (cmdline_format); #endif /* ACE_LACKS_VA_FUNCTIONS */ ACE_DEBUG ((LM_DEBUG, ACE_TEXT("Spawning <%s> <%s>\n"), opts.process_name(), opts.command_line_buf ())); pid_t result = mgr.spawn (opts); if (result != ACE_INVALID_PID) ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P) spawned child: pid %d time %d %s\n"), int (result), sleep_time, prio)); else ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("spawn failed"))); return result; }