From bf69dacefd62170262d7e1b665b000b1dca122ce Mon Sep 17 00:00:00 2001 From: Thulinma Date: Tue, 19 Mar 2013 14:41:07 +0100 Subject: [PATCH] Added automated exit handler in Util::Procs. --- lib/json.cpp | 1 - lib/procs.cpp | 99 ++++++++++++++++++++++++++++++++++----------------- lib/procs.h | 4 ++- 3 files changed, 69 insertions(+), 35 deletions(-) diff --git a/lib/json.cpp b/lib/json.cpp index 9bc421d8..68596e90 100644 --- a/lib/json.cpp +++ b/lib/json.cpp @@ -476,7 +476,6 @@ std::string & JSON::Value::toNetPacked(){ //check if this is legal if (myType != OBJECT){ fprintf(stderr, "Error: Only objects may be NetPacked!\n"); - abort(); return emptystring; } //if sneaky storage doesn't contain correct data, re-calculate it diff --git a/lib/procs.cpp b/lib/procs.cpp index 64022133..a3d77075 100644 --- a/lib/procs.cpp +++ b/lib/procs.cpp @@ -18,11 +18,73 @@ #include #include #include +#include "timing.h" std::map Util::Procs::plist; std::map Util::Procs::exitHandlers; bool Util::Procs::handler_set = false; +/// Called at exit of any program that used a Start* function. +/// Waits up to 2.5 seconds, then sends SIGINT signal to all managed processes. +/// After that waits up to 10 seconds for children to exit, then sends SIGKILL to +/// all remaining children. Waits one more second for cleanup to finish, then exits. +void Util::Procs::exit_handler(){ + int waiting = 0; + while ( !plist.empty()){ + Util::sleep(500); + if (++waiting > 5){ + break; + } + } + + if ( !plist.empty()){ + std::map listcopy = plist; + std::map::iterator it; + for (it = listcopy.begin(); it != listcopy.end(); it++){ + kill(( *it).first, SIGINT); + } + } + + waiting = 0; + while ( !plist.empty()){ + Util::sleep(500); + if (++waiting > 10){ + break; + } + } + + if ( !plist.empty()){ + std::map listcopy = plist; + std::map::iterator it; + for (it = listcopy.begin(); it != listcopy.end(); it++){ + kill(( *it).first, SIGKILL); + } + } + + waiting = 0; + while ( !plist.empty()){ + Util::sleep(100); + if (++waiting > 10){ + break; + } + } + +} + +/// Sets up exit and childsig handlers. +/// Called by every Start* function. +void Util::Procs::setHandler(){ + if ( !handler_set){ + struct sigaction new_action; + new_action.sa_handler = childsig_handler; + sigemptyset( &new_action.sa_mask); + new_action.sa_flags = 0; + sigaction(SIGCHLD, &new_action, NULL); + atexit(exit_handler); + handler_set = true; + } +} + /// Used internally to capture child signals and update plist. void Util::Procs::childsig_handler(int signum){ if (signum != SIGCHLD){ @@ -107,14 +169,7 @@ 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; - } + setHandler(); pid_t ret = fork(); if (ret == 0){ runCmd(cmd); @@ -143,14 +198,7 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){ 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; - } + setHandler(); int pfildes[2]; if (pipe(pfildes) == -1){ #if DEBUG >= 1 @@ -220,15 +268,7 @@ pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2, st 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; - } - + setHandler(); int pfildes[2]; int pfildes2[2]; if (pipe(pfildes) == -1){ @@ -346,14 +386,7 @@ pid_t Util::Procs::StartPiped(std::string name, char * argv[], int * fdin, int * } pid_t pid; int pipein[2], pipeout[2], pipeerr[2]; - 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; - } + setHandler(); if (fdin && *fdin == -1 && pipe(pipein) < 0){ #if DEBUG >= 1 std::cerr << "Pipe (in) creation failed for " << name << std::endl; diff --git a/lib/procs.h b/lib/procs.h index 6f0166e5..4a0343da 100644 --- a/lib/procs.h +++ b/lib/procs.h @@ -18,8 +18,10 @@ namespace Util { 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 exit_handler(); static void runCmd(std::string & cmd); - public: + static void setHandler(); + public: static pid_t Start(std::string name, std::string cmd); static pid_t Start(std::string name, std::string cmd, std::string cmd2); static pid_t Start(std::string name, std::string cmd, std::string cmd2, std::string cmd3);