diff --git a/util/proc.cpp b/util/proc.cpp new file mode 100644 index 00000000..0e891be5 --- /dev/null +++ b/util/proc.cpp @@ -0,0 +1,138 @@ +/// \file proc.cpp +/// Contains generic functions for managing processes. + +#include "proc.h" +#include +#include +#include +#include +#include +#if DEBUG >= 1 +#include +#endif + +std::map Util::Procs::plist; +bool Util::Procs::handler_set = false; + +/// Used internally to capture child signals and update plist. +void Util::Procs::childsig_handler(int signum){ + if (signum != SIGCHLD){return;} + pid_t ret = wait(0); + #if DEBUG >= 1 + std::cerr << "Process " << plist[ret] << " terminated." << std::endl; + #endif + plist.erase(ret); +} + +/// Starts a new process if the name is not already active. +/// \return 0 if process was not started, process PID otherwise. +/// \arg name Name for this process - only used internally. +/// \arg cmd Commandline for this process. +pid_t Util::Procs::Start(std::string name, std::string cmd){ + if (isActive(name)){return getPid(name);} + if (!handler_set){ + struct sigaction new_action; + new_action.sa_handler = Util::Procs::childsig_handler; + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = 0; + sigaction(SIGCHLD, &new_action, NULL); + handler_set = true; + } + pid_t ret = fork(); + if (ret == 0){ + //split cmd into arguments + //supports a maximum of 20 arguments + char * tmp = (char*)cmd.c_str(); + char * tmp2 = 0; + char * args[21]; + int i = 0; + tmp2 = strtok(tmp, " "); + args[0] = tmp2; + while (tmp2 != 0 && (i < 20)){ + tmp2 = strtok(0, " "); + ++i; + args[i] = tmp2; + } + if (i == 20){args[20] = 0;} + //execute the command + execvp(args[0], args); + #if DEBUG >= 1 + std::cerr << "Error: " << strerror(errno) << std::endl; + #endif + _exit(42); + }else{ + if (ret > 0){ + #if DEBUG >= 1 + std::cerr << "Process " << name << " started, PID " << ret << ": " << cmd << std::endl; + #endif + plist.insert(std::pair(ret, name)); + }else{ + #if DEBUG >= 1 + std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl; + #endif + return 0; + } + } + return ret; +} + +/// Stops the named process, if running. +/// \arg name (Internal) name of process to stop +void Util::Procs::Stop(std::string name){ + if (!isActive(name)){return;} + Stop(getPid(name)); +} + +/// Stops the process with this pid, if running. +/// \arg name The PID of the process to stop. +void Util::Procs::Stop(pid_t name){ + if (isActive(name)){ + kill(name, SIGTERM); + } +} + +/// (Attempts to) stop all running child processes. +void Util::Procs::StopAll(){ + std::map::iterator it; + for (it = plist.begin(); it != plist.end(); it++){ + Stop((*it).first); + } +} + +/// Returns the number of active child processes. +int Util::Procs::Count(){ + return plist.size(); +} + +/// Returns true if a process by this name is currently active. +bool Util::Procs::isActive(std::string name){ + std::map::iterator it; + for (it = plist.begin(); it != plist.end(); it++){ + if ((*it).second == name){return true;} + } + return false; +} + +/// Returns true if a process with this PID is currently active. +bool Util::Procs::isActive(pid_t name){ + return (plist.count(name) == 1); +} + +/// Gets PID for this named process, if active. +/// \return NULL if not active, process PID otherwise. +pid_t Util::Procs::getPid(std::string name){ + std::map::iterator it; + for (it = plist.begin(); it != plist.end(); it++){ + if ((*it).second == name){return (*it).first;} + } + return 0; +} + +/// Gets name for this process PID, if active. +/// \return Empty string if not active, name otherwise. +std::string Util::Procs::getName(pid_t name){ + if (plist.count(name) == 1){ + return plist[name]; + } + return ""; +} diff --git a/util/proc.h b/util/proc.h new file mode 100644 index 00000000..a2c10ec0 --- /dev/null +++ b/util/proc.h @@ -0,0 +1,28 @@ +/// \file proc.h +/// Contains generic function headers for managing processes. + +#include +#include +#include + +/// Contains utility code, not directly related to streaming media +namespace Util{ + + /// Deals with spawning, monitoring and stopping child processes + class Procs{ + private: + static std::map plist; ///< Holds active processes + static bool handler_set; ///< If true, the sigchld handler has been setup. + static void childsig_handler(int signum); + public: + static pid_t Start(std::string name, std::string cmd); + static void Stop(std::string name); + static void Stop(pid_t name); + static void StopAll(); + static int Count(); + static bool isActive(std::string name); + static bool isActive(pid_t name); + static pid_t getPid(std::string name); + static std::string getName(pid_t name); + }; +};