diff --git a/lib/procs.cpp b/lib/procs.cpp index 78ac3b25..65782810 100644 --- a/lib/procs.cpp +++ b/lib/procs.cpp @@ -20,12 +20,29 @@ #include std::map Util::Procs::plist; +std::map Util::Procs::exitHandlers; 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); + int status; + pid_t ret = waitpid(-1, &status, WNOHANG); + if (ret == 0){//ignore, would block otherwise + return; + }else if(ret < 0){ +#if DEBUG >= 3 + std::cerr << "SIGCHLD received, but no child died"; +#endif + return; + } + int exitcode; + if (WIFEXITED(status)){ + exitcode = WEXITSTATUS(status); + }else if (WIFSIGNALED(status)){ + exitcode = -WTERMSIG(status); + }else{/* not possible */return;} + #if DEBUG >= 1 std::string pname = plist[ret]; #endif @@ -34,9 +51,19 @@ void Util::Procs::childsig_handler(int signum){ if (isActive(pname)){ Stop(pname); }else{ + //can this ever happen? std::cerr << "Process " << pname << " fully terminated." << std::endl; } #endif + + TerminationNotifier tn = exitHandlers[ret]; + exitHandlers.erase(ret); + if (tn){ +#if DEBUG >= 2 + std::cerr << "Calling termination handler for " << pname << std::endl; +#endif + tn(ret, exitcode); + } } /// Attempts to run the command cmd. @@ -358,3 +385,13 @@ std::string Util::Procs::getName(pid_t name){ } return ""; } + +/// Registers one notifier function for when a process indentified by PID terminates. +/// \return true if the notifier could be registered, false otherwise. +bool Util::Procs::SetTerminationNotifier(pid_t pid, TerminationNotifier notifier){ + if (plist.find(pid) != plist.end()){ + exitHandlers[pid] = notifier; + return true; + } + return false; +} diff --git a/lib/procs.h b/lib/procs.h index ceabca3d..f3061261 100644 --- a/lib/procs.h +++ b/lib/procs.h @@ -9,10 +9,13 @@ /// Contains utility code, not directly related to streaming media namespace Util{ + typedef void (*TerminationNotifier)(pid_t pid, int exitCode); + /// Deals with spawning, monitoring and stopping child processes class Procs{ private: static std::map plist; ///< Holds active processes + static std::map exitHandlers; ///< termination function, if any static bool handler_set; ///< If true, the sigchld handler has been setup. static void childsig_handler(int signum); static void runCmd(std::string & cmd); @@ -28,6 +31,7 @@ namespace Util{ static bool isActive(pid_t name); static pid_t getPid(std::string name); static std::string getName(pid_t name); + static bool SetTerminationNotifier(pid_t pid, TerminationNotifier notifier); }; };