diff --git a/NEWS b/NEWS index 0159294888..70fb2de13c 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ Release 3.9.0 * [Standalone] Automatic asset pipeline expiry headers support. * [Enterprise] Multithreading support for apps * Deleting restart.txt will no longer trigger a restart. + * The watchdog now forces all agents' process groups to exit using SIGKILL, to ensure no garbage processes are left behind. Release 3.0.17 diff --git a/ext/common/agents/HelperAgent/Main.cpp b/ext/common/agents/HelperAgent/Main.cpp index d22b594865..0a6e729fb2 100644 --- a/ext/common/agents/HelperAgent/Main.cpp +++ b/ext/common/agents/HelperAgent/Main.cpp @@ -446,6 +446,7 @@ class Server { * instance directory will be cleaned up, making this helper agent * inaccessible. */ + P_DEBUG("Watchdog seems to be killed; forcing shutdown of all subprocesses"); syscalls::killpg(getpgrp(), SIGKILL); _exit(2); // In case killpg() fails. } else { @@ -486,11 +487,11 @@ main(int argc, char *argv[]) { UPDATE_TRACE_POINT(); server.mainLoop(); } catch (const tracable_exception &e) { - P_ERROR(e.what() << "\n" << e.backtrace()); + P_ERROR("*** ERROR: " << e.what() << "\n" << e.backtrace()); return 1; } MultiLibeio::shutdown(); - P_TRACE(2, "Helper agent exited."); + P_TRACE(2, "Helper agent exiting with code 0."); return 0; } diff --git a/ext/common/agents/LoggingAgent/Main.cpp b/ext/common/agents/LoggingAgent/Main.cpp index 0f201e7d17..d7e588e5f2 100644 --- a/ext/common/agents/LoggingAgent/Main.cpp +++ b/ext/common/agents/LoggingAgent/Main.cpp @@ -283,6 +283,7 @@ main(int argc, char *argv[]) { P_DEBUG("Logging agent online, listening at " << socketAddress); ev_run(eventLoop, 0); + P_DEBUG("Logging agent exiting with code " << exitCode << "."); return exitCode; } catch (const tracable_exception &e) { P_ERROR("*** ERROR: " << e.what() << "\n" << e.backtrace()); diff --git a/ext/common/agents/Watchdog/Main.cpp b/ext/common/agents/Watchdog/Main.cpp index 831127d578..adcca524fc 100644 --- a/ext/common/agents/Watchdog/Main.cpp +++ b/ext/common/agents/Watchdog/Main.cpp @@ -1,6 +1,6 @@ /* * Phusion Passenger - http://www.modrails.com/ - * Copyright (c) 2010 Phusion + * Copyright (c) 2010-2012 Phusion * * "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui. * @@ -982,12 +982,12 @@ cleanupAgentsInBackground(vector &watchers) { // processes. P_WARN("Some Phusion Passenger agent processes did not exit " << "in time, forcefully shutting down all."); - for (it = watchers.begin(); it != watchers.end(); it++) { - (*it)->forceShutdown(); - } } else { - P_DEBUG("All Phusion Passenger agent processes have exited."); + P_DEBUG("All Phusion Passenger agent processes have exited. Forcing all subprocesses to shut down."); } + for (it = watchers.begin(); it != watchers.end(); it++) { + (*it)->forceShutdown(); + } // Now clean up the server instance directory. delete generation.get(); @@ -1126,10 +1126,11 @@ main(int argc, char *argv[]) { * the background and exit this watchdog process so that we don't block * the web server. */ + P_DEBUG("Web server exited gracefully; gracefully shutting down all agents..."); cleanupAgentsInBackground(watchers); return 0; } else { - P_DEBUG("Web server did not exit gracefully, forcing shutdown of all service processes..."); + P_DEBUG("Web server did not exit gracefully, forcing shutdown of all agents..."); forceAllAgentsShutdown(watchers); return 1; } diff --git a/ext/ruby/passenger_native_support.c b/ext/ruby/passenger_native_support.c index b6057b21d1..bb8f877d50 100644 --- a/ext/ruby/passenger_native_support.c +++ b/ext/ruby/passenger_native_support.c @@ -458,6 +458,18 @@ detach_process(VALUE self, VALUE pid) { return Qnil; } +/** + * Freeze the current process forever. On Ruby 1.9 this never unlocks the GIL. + * Useful for testing purposes. + */ +static VALUE +freeze_process(VALUE self) { + while (1) { + usleep(60 * 1000000); + } + return Qnil; +} + #if defined(HAVE_KQUEUE) || defined(IN_DOXYGEN) typedef struct { VALUE klass; @@ -852,6 +864,7 @@ Init_passenger_native_support() { rb_define_singleton_method(mNativeSupport, "writev3", f_writev3, 4); rb_define_singleton_method(mNativeSupport, "process_times", process_times, 0); rb_define_singleton_method(mNativeSupport, "detach_process", detach_process, 1); + rb_define_singleton_method(mNativeSupport, "freeze_process", freeze_process, 0); #ifdef HAVE_KQUEUE cFileSystemWatcher = rb_define_class_under(mNativeSupport,