summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2012-03-13 14:40:46 -0400
committerNat Goodspeed <nat@lindenlab.com>2012-03-13 14:40:46 -0400
commitab7fb5944a2c5d851944fec59a86c8b7e0df77d3 (patch)
tree1dac294e8da940abafb3e390bbbad1e700caa243
parent1bdc876b790d054400240e4a4bda6d56d026cf59 (diff)
Protect LLProcess destructor when run after APR shutdown.
A static LLProcessPtr variable won't be destroyed until after procedural code has shut down APR. The trouble is that LLProcess's destructor unregisters itself from APR -- and, for an autokill LLProcess, attempts to kill the child process. All that is ill-advised after APR shutdown. Disable use of apr_pool_note_subprocess() mechanism. This should be another viable way of coping with static autokill LLProcessPtr variables: when the designated APR pool is cleaned up, APR promises to kill the child process. But whether it's an APR bug or a calling error, the present (now disabled) call in LLProcess results in OUR process, the viewer, getting SIGTERM when it asks to clean up the global APR pool.
-rw-r--r--indra/llcommon/llprocess.cpp62
1 files changed, 28 insertions, 34 deletions
diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp
index 178ec064c0..bd08c3ab51 100644
--- a/indra/llcommon/llprocess.cpp
+++ b/indra/llcommon/llprocess.cpp
@@ -47,6 +47,9 @@
#include <typeinfo>
#include <utility>
+/*****************************************************************************
+* Helpers
+*****************************************************************************/
static const char* whichfile_[] = { "stdin", "stdout", "stderr" };
static std::string empty;
static LLProcess::Status interpret_status(int status);
@@ -127,6 +130,9 @@ private:
};
static LLProcessListener sProcessListener;
+/*****************************************************************************
+* WritePipe and ReadPipe
+*****************************************************************************/
LLProcess::BasePipe::~BasePipe() {}
const LLProcess::BasePipe::size_type
// use funky syntax to call max() to avoid blighted max() macros
@@ -456,6 +462,9 @@ private:
bool mEOF;
};
+/*****************************************************************************
+* LLProcess itself
+*****************************************************************************/
/// Need an exception to avoid constructing an invalid LLProcess object, but
/// internal use only
struct LLProcessError: public std::runtime_error
@@ -669,11 +678,23 @@ LLProcess::LLProcess(const LLSDOrParams& params):
// that doesn't always work (e.g. VWR-21538).
if (params.autokill)
{
+/*==========================================================================*|
+ // NO: There may be an APR bug, not sure -- but at least on Mac, when
+ // gAPRPoolp is destroyed, OUR process receives SIGTERM! Apparently
+ // either our own PID is getting into the list of processes to kill()
+ // (unlikely), or somehow one of those PIDs is getting zeroed first,
+ // so that kill() sends SIGTERM to the whole process group -- this
+ // process included. I'd have to build and link with a debug version
+ // of APR to know for sure. It's too bad: this mechanism would be just
+ // right for dealing with static autokill LLProcessPtr variables,
+ // which aren't destroyed until after APR is no longer available.
+
// Tie the lifespan of this child process to the lifespan of our APR
// pool: on destruction of the pool, forcibly kill the process. Tell
// APR to try SIGTERM and wait 3 seconds. If that didn't work, use
// SIGKILL.
apr_pool_note_subprocess(gAPRPoolp, &mProcess, APR_KILL_AFTER_TIMEOUT);
+|*==========================================================================*/
// On Windows, associate the new child process with our Job Object.
autokill();
@@ -732,6 +753,13 @@ std::string LLProcess::basename(const std::string& path)
LLProcess::~LLProcess()
{
+ // In the Linden viewer, there's at least one static LLProcessPtr. Its
+ // destructor will be called *after* ll_cleanup_apr(). In such a case,
+ // unregistering is pointless (and fatal!) -- and kill(), which also
+ // relies on APR, is impossible.
+ if (! gAPRPoolp)
+ return;
+
// Only in state RUNNING are we registered for callback. In UNSTARTED we
// haven't yet registered. And since receiving the callback is the only
// way we detect child termination, we only change from state RUNNING at
@@ -1263,38 +1291,4 @@ static LLProcess::Status interpret_status(int status)
return result;
}
-/*==========================================================================*|
-static std::list<pid_t> sZombies;
-
-void LLProcess::orphan(void)
-{
- // Disassociate the process from this object
- if(mProcessID != 0)
- {
- // We may still need to reap the process's zombie eventually
- sZombies.push_back(mProcessID);
-
- mProcessID = 0;
- }
-}
-
-// static
-void LLProcess::reap(void)
-{
- // Attempt to real all saved process ID's.
-
- std::list<pid_t>::iterator iter = sZombies.begin();
- while(iter != sZombies.end())
- {
- if(reap_pid(*iter))
- {
- iter = sZombies.erase(iter);
- }
- else
- {
- iter++;
- }
- }
-}
-|*==========================================================================*/
#endif // Posix