MAINT-7634: Logging and instrumentation canges to narrow down viewer crashes.
parent
57d5744f2c
commit
1038633526
|
|
@ -34,6 +34,7 @@
|
|||
#include "lltimer.h"
|
||||
#include "lltrace.h"
|
||||
#include "lltracethreadrecorder.h"
|
||||
#include "llexception.h"
|
||||
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
#include <sched.h>
|
||||
|
|
@ -46,28 +47,28 @@ const DWORD MS_VC_EXCEPTION=0x406D1388;
|
|||
#pragma pack(push,8)
|
||||
typedef struct tagTHREADNAME_INFO
|
||||
{
|
||||
DWORD dwType; // Must be 0x1000.
|
||||
LPCSTR szName; // Pointer to name (in user addr space).
|
||||
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||
DWORD dwType; // Must be 0x1000.
|
||||
LPCSTR szName; // Pointer to name (in user addr space).
|
||||
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||
} THREADNAME_INFO;
|
||||
#pragma pack(pop)
|
||||
|
||||
void set_thread_name( DWORD dwThreadID, const char* threadName)
|
||||
{
|
||||
THREADNAME_INFO info;
|
||||
info.dwType = 0x1000;
|
||||
info.szName = threadName;
|
||||
info.dwThreadID = dwThreadID;
|
||||
info.dwFlags = 0;
|
||||
THREADNAME_INFO info;
|
||||
info.dwType = 0x1000;
|
||||
info.szName = threadName;
|
||||
info.dwThreadID = dwThreadID;
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try
|
||||
{
|
||||
::RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR*)&info );
|
||||
}
|
||||
__except(EXCEPTION_CONTINUE_EXECUTION)
|
||||
{
|
||||
}
|
||||
__try
|
||||
{
|
||||
::RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR*)&info );
|
||||
}
|
||||
__except(EXCEPTION_CONTINUE_EXECUTION)
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -99,17 +100,17 @@ U32 LLThread::sIDIter = 0;
|
|||
|
||||
LL_COMMON_API void assert_main_thread()
|
||||
{
|
||||
static U32 s_thread_id = LLThread::currentID();
|
||||
if (LLThread::currentID() != s_thread_id)
|
||||
{
|
||||
LL_WARNS() << "Illegal execution from thread id " << (S32) LLThread::currentID()
|
||||
<< " outside main thread " << (S32) s_thread_id << LL_ENDL;
|
||||
}
|
||||
static U32 s_thread_id = LLThread::currentID();
|
||||
if (LLThread::currentID() != s_thread_id)
|
||||
{
|
||||
LL_WARNS() << "Illegal execution from thread id " << (S32) LLThread::currentID()
|
||||
<< " outside main thread " << (S32) s_thread_id << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
void LLThread::registerThreadID()
|
||||
{
|
||||
sThreadID = ++sIDIter;
|
||||
sThreadID = ++sIDIter;
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -117,157 +118,203 @@ void LLThread::registerThreadID()
|
|||
//
|
||||
void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap)
|
||||
{
|
||||
LLThread *threadp = (LLThread *)datap;
|
||||
LLThread *threadp = (LLThread *)datap;
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
set_thread_name(-1, threadp->mName.c_str());
|
||||
set_thread_name(-1, threadp->mName.c_str());
|
||||
#endif
|
||||
|
||||
// for now, hard code all LLThreads to report to single master thread recorder, which is known to be running on main thread
|
||||
threadp->mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder());
|
||||
// for now, hard code all LLThreads to report to single master thread recorder, which is known to be running on main thread
|
||||
threadp->mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder());
|
||||
|
||||
sThreadID = threadp->mID;
|
||||
sThreadID = threadp->mID;
|
||||
|
||||
// Run the user supplied function
|
||||
threadp->run();
|
||||
try
|
||||
{
|
||||
// Run the user supplied function
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
threadp->run();
|
||||
}
|
||||
catch (const LLContinueError &e)
|
||||
{
|
||||
LL_WARNS("THREAD") << "ContinueException on thread '" << threadp->mName <<
|
||||
"' reentering run(). Error what is: '" << e.what() << "'" << LL_ENDL;
|
||||
//output possible call stacks to log file.
|
||||
LLError::LLCallStacks::print();
|
||||
|
||||
//LL_INFOS() << "LLThread::staticRun() Exiting: " << threadp->mName << LL_ENDL;
|
||||
|
||||
delete threadp->mRecorder;
|
||||
threadp->mRecorder = NULL;
|
||||
|
||||
// We're done with the run function, this thread is done executing now.
|
||||
//NB: we are using this flag to sync across threads...we really need memory barriers here
|
||||
threadp->mStatus = STOPPED;
|
||||
LOG_UNHANDLED_EXCEPTION("LLThread");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
return NULL;
|
||||
} while (true);
|
||||
|
||||
//LL_INFOS() << "LLThread::staticRun() Exiting: " << threadp->mName << LL_ENDL;
|
||||
|
||||
// We're done with the run function, this thread is done executing now.
|
||||
//NB: we are using this flag to sync across threads...we really need memory barriers here
|
||||
threadp->mStatus = STOPPED;
|
||||
}
|
||||
catch (std::bad_alloc)
|
||||
{
|
||||
threadp->mStatus = CRASHED;
|
||||
LLMemory::logMemoryInfo(TRUE);
|
||||
|
||||
//output possible call stacks to log file.
|
||||
LLError::LLCallStacks::print();
|
||||
|
||||
LL_ERRS("THREAD") << "Bad memory allocation in LLThread::staticRun() named '" << threadp->mName << "'!" << LL_ENDL;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
threadp->mStatus = CRASHED;
|
||||
CRASH_ON_UNHANDLED_EXCEPTION("LLThread");
|
||||
}
|
||||
|
||||
delete threadp->mRecorder;
|
||||
threadp->mRecorder = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
|
||||
mPaused(FALSE),
|
||||
mName(name),
|
||||
mAPRThreadp(NULL),
|
||||
mStatus(STOPPED),
|
||||
mRecorder(NULL)
|
||||
mPaused(FALSE),
|
||||
mName(name),
|
||||
mAPRThreadp(NULL),
|
||||
mStatus(STOPPED),
|
||||
mRecorder(NULL)
|
||||
{
|
||||
|
||||
mID = ++sIDIter;
|
||||
mID = ++sIDIter;
|
||||
|
||||
// Thread creation probably CAN be paranoid about APR being initialized, if necessary
|
||||
if (poolp)
|
||||
{
|
||||
mIsLocalPool = FALSE;
|
||||
mAPRPoolp = poolp;
|
||||
}
|
||||
else
|
||||
{
|
||||
mIsLocalPool = TRUE;
|
||||
apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
|
||||
}
|
||||
mRunCondition = new LLCondition(mAPRPoolp);
|
||||
mDataLock = new LLMutex(mAPRPoolp);
|
||||
mLocalAPRFilePoolp = NULL ;
|
||||
// Thread creation probably CAN be paranoid about APR being initialized, if necessary
|
||||
if (poolp)
|
||||
{
|
||||
mIsLocalPool = FALSE;
|
||||
mAPRPoolp = poolp;
|
||||
}
|
||||
else
|
||||
{
|
||||
mIsLocalPool = TRUE;
|
||||
apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
|
||||
}
|
||||
mRunCondition = new LLCondition(mAPRPoolp);
|
||||
mDataLock = new LLMutex(mAPRPoolp);
|
||||
mLocalAPRFilePoolp = NULL ;
|
||||
}
|
||||
|
||||
|
||||
LLThread::~LLThread()
|
||||
{
|
||||
shutdown();
|
||||
shutdown();
|
||||
|
||||
if(mLocalAPRFilePoolp)
|
||||
{
|
||||
delete mLocalAPRFilePoolp ;
|
||||
mLocalAPRFilePoolp = NULL ;
|
||||
}
|
||||
if (isCrashed())
|
||||
{
|
||||
LL_WARNS("THREAD") << "Destroying crashed thread named '" << mName << "'" << LL_ENDL;
|
||||
}
|
||||
|
||||
if(mLocalAPRFilePoolp)
|
||||
{
|
||||
delete mLocalAPRFilePoolp ;
|
||||
mLocalAPRFilePoolp = NULL ;
|
||||
}
|
||||
}
|
||||
|
||||
void LLThread::shutdown()
|
||||
{
|
||||
// Warning! If you somehow call the thread destructor from itself,
|
||||
// the thread will die in an unclean fashion!
|
||||
if (mAPRThreadp)
|
||||
{
|
||||
if (!isStopped())
|
||||
{
|
||||
// The thread isn't already stopped
|
||||
// First, set the flag that indicates that we're ready to die
|
||||
setQuitting();
|
||||
if (isCrashed())
|
||||
{
|
||||
LL_WARNS("THREAD") << "Shutting down crashed thread named '" << mName << "'" << LL_ENDL;
|
||||
}
|
||||
|
||||
//LL_INFOS() << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << LL_ENDL;
|
||||
// Now wait a bit for the thread to exit
|
||||
// It's unclear whether I should even bother doing this - this destructor
|
||||
// should never get called unless we're already stopped, really...
|
||||
S32 counter = 0;
|
||||
const S32 MAX_WAIT = 600;
|
||||
while (counter < MAX_WAIT)
|
||||
{
|
||||
if (isStopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Sleep for a tenth of a second
|
||||
ms_sleep(100);
|
||||
yield();
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
// Warning! If you somehow call the thread destructor from itself,
|
||||
// the thread will die in an unclean fashion!
|
||||
if (mAPRThreadp)
|
||||
{
|
||||
if (!isStopped())
|
||||
{
|
||||
// The thread isn't already stopped
|
||||
// First, set the flag that indicates that we're ready to die
|
||||
setQuitting();
|
||||
|
||||
if (!isStopped())
|
||||
{
|
||||
// This thread just wouldn't stop, even though we gave it time
|
||||
//LL_WARNS() << "LLThread::~LLThread() exiting thread before clean exit!" << LL_ENDL;
|
||||
// Put a stake in its heart.
|
||||
delete mRecorder;
|
||||
//LL_INFOS() << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << LL_ENDL;
|
||||
// Now wait a bit for the thread to exit
|
||||
// It's unclear whether I should even bother doing this - this destructor
|
||||
// should never get called unless we're already stopped, really...
|
||||
S32 counter = 0;
|
||||
const S32 MAX_WAIT = 600;
|
||||
while (counter < MAX_WAIT)
|
||||
{
|
||||
if (isStopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Sleep for a tenth of a second
|
||||
ms_sleep(100);
|
||||
yield();
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
apr_thread_exit(mAPRThreadp, -1);
|
||||
return;
|
||||
}
|
||||
mAPRThreadp = NULL;
|
||||
}
|
||||
if (!isStopped())
|
||||
{
|
||||
// This thread just wouldn't stop, even though we gave it time
|
||||
//LL_WARNS() << "LLThread::~LLThread() exiting thread before clean exit!" << LL_ENDL;
|
||||
// Put a stake in its heart.
|
||||
delete mRecorder;
|
||||
|
||||
delete mRunCondition;
|
||||
mRunCondition = NULL;
|
||||
apr_thread_exit(mAPRThreadp, -1);
|
||||
return;
|
||||
}
|
||||
mAPRThreadp = NULL;
|
||||
}
|
||||
|
||||
delete mDataLock;
|
||||
mDataLock = NULL;
|
||||
|
||||
if (mIsLocalPool && mAPRPoolp)
|
||||
{
|
||||
apr_pool_destroy(mAPRPoolp);
|
||||
mAPRPoolp = 0;
|
||||
}
|
||||
delete mRunCondition;
|
||||
mRunCondition = NULL;
|
||||
|
||||
if (mRecorder)
|
||||
{
|
||||
// missed chance to properly shut down recorder (needs to be done in thread context)
|
||||
// probably due to abnormal thread termination
|
||||
// so just leak it and remove it from parent
|
||||
LLTrace::get_master_thread_recorder()->removeChildRecorder(mRecorder);
|
||||
}
|
||||
delete mDataLock;
|
||||
mDataLock = NULL;
|
||||
|
||||
if (mIsLocalPool && mAPRPoolp)
|
||||
{
|
||||
apr_pool_destroy(mAPRPoolp);
|
||||
mAPRPoolp = 0;
|
||||
}
|
||||
|
||||
if (mRecorder)
|
||||
{
|
||||
// missed chance to properly shut down recorder (needs to be done in thread context)
|
||||
// probably due to abnormal thread termination
|
||||
// so just leak it and remove it from parent
|
||||
LLTrace::get_master_thread_recorder()->removeChildRecorder(mRecorder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLThread::start()
|
||||
{
|
||||
llassert(isStopped());
|
||||
|
||||
// Set thread state to running
|
||||
mStatus = RUNNING;
|
||||
llassert(isStopped());
|
||||
|
||||
// Set thread state to running
|
||||
mStatus = RUNNING;
|
||||
|
||||
apr_status_t status =
|
||||
apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);
|
||||
|
||||
if(status == APR_SUCCESS)
|
||||
{
|
||||
// We won't bother joining
|
||||
apr_thread_detach(mAPRThreadp);
|
||||
}
|
||||
else
|
||||
{
|
||||
mStatus = STOPPED;
|
||||
LL_WARNS() << "failed to start thread " << mName << LL_ENDL;
|
||||
ll_apr_warn_status(status);
|
||||
}
|
||||
apr_status_t status =
|
||||
apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);
|
||||
|
||||
if(status == APR_SUCCESS)
|
||||
{
|
||||
// We won't bother joining
|
||||
apr_thread_detach(mAPRThreadp);
|
||||
}
|
||||
else
|
||||
{
|
||||
mStatus = STOPPED;
|
||||
LL_WARNS() << "failed to start thread " << mName << LL_ENDL;
|
||||
ll_apr_warn_status(status);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -278,28 +325,28 @@ void LLThread::start()
|
|||
// The thread will pause when (and if) it calls checkPause()
|
||||
void LLThread::pause()
|
||||
{
|
||||
if (!mPaused)
|
||||
{
|
||||
// this will cause the thread to stop execution as soon as checkPause() is called
|
||||
mPaused = 1; // Does not need to be atomic since this is only set/unset from the main thread
|
||||
}
|
||||
if (!mPaused)
|
||||
{
|
||||
// this will cause the thread to stop execution as soon as checkPause() is called
|
||||
mPaused = 1; // Does not need to be atomic since this is only set/unset from the main thread
|
||||
}
|
||||
}
|
||||
|
||||
void LLThread::unpause()
|
||||
{
|
||||
if (mPaused)
|
||||
{
|
||||
mPaused = 0;
|
||||
}
|
||||
if (mPaused)
|
||||
{
|
||||
mPaused = 0;
|
||||
}
|
||||
|
||||
wake(); // wake up the thread if necessary
|
||||
wake(); // wake up the thread if necessary
|
||||
}
|
||||
|
||||
// virtual predicate function -- returns true if the thread should wake up, false if it should sleep.
|
||||
bool LLThread::runCondition(void)
|
||||
{
|
||||
// by default, always run. Handling of pause/unpause is done regardless of this function's result.
|
||||
return true;
|
||||
// by default, always run. Handling of pause/unpause is done regardless of this function's result.
|
||||
return true;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
|
@ -307,65 +354,65 @@ bool LLThread::runCondition(void)
|
|||
// Stop thread execution if requested until unpaused.
|
||||
void LLThread::checkPause()
|
||||
{
|
||||
mDataLock->lock();
|
||||
mDataLock->lock();
|
||||
|
||||
// This is in a while loop because the pthread API allows for spurious wakeups.
|
||||
while(shouldSleep())
|
||||
{
|
||||
mDataLock->unlock();
|
||||
mRunCondition->wait(); // unlocks mRunCondition
|
||||
mDataLock->lock();
|
||||
// mRunCondition is locked when the thread wakes up
|
||||
}
|
||||
|
||||
mDataLock->unlock();
|
||||
// This is in a while loop because the pthread API allows for spurious wakeups.
|
||||
while(shouldSleep())
|
||||
{
|
||||
mDataLock->unlock();
|
||||
mRunCondition->wait(); // unlocks mRunCondition
|
||||
mDataLock->lock();
|
||||
// mRunCondition is locked when the thread wakes up
|
||||
}
|
||||
|
||||
mDataLock->unlock();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
void LLThread::setQuitting()
|
||||
{
|
||||
mDataLock->lock();
|
||||
if (mStatus == RUNNING)
|
||||
{
|
||||
mStatus = QUITTING;
|
||||
}
|
||||
mDataLock->unlock();
|
||||
wake();
|
||||
mDataLock->lock();
|
||||
if (mStatus == RUNNING)
|
||||
{
|
||||
mStatus = QUITTING;
|
||||
}
|
||||
mDataLock->unlock();
|
||||
wake();
|
||||
}
|
||||
|
||||
// static
|
||||
U32 LLThread::currentID()
|
||||
{
|
||||
return sThreadID;
|
||||
return sThreadID;
|
||||
}
|
||||
|
||||
// static
|
||||
void LLThread::yield()
|
||||
{
|
||||
#if LL_LINUX || LL_SOLARIS
|
||||
sched_yield(); // annoyingly, apr_thread_yield is a noop on linux...
|
||||
sched_yield(); // annoyingly, apr_thread_yield is a noop on linux...
|
||||
#else
|
||||
apr_thread_yield();
|
||||
apr_thread_yield();
|
||||
#endif
|
||||
}
|
||||
|
||||
void LLThread::wake()
|
||||
{
|
||||
mDataLock->lock();
|
||||
if(!shouldSleep())
|
||||
{
|
||||
mRunCondition->signal();
|
||||
}
|
||||
mDataLock->unlock();
|
||||
mDataLock->lock();
|
||||
if(!shouldSleep())
|
||||
{
|
||||
mRunCondition->signal();
|
||||
}
|
||||
mDataLock->unlock();
|
||||
}
|
||||
|
||||
void LLThread::wakeLocked()
|
||||
{
|
||||
if(!shouldSleep())
|
||||
{
|
||||
mRunCondition->signal();
|
||||
}
|
||||
if(!shouldSleep())
|
||||
{
|
||||
mRunCondition->signal();
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
|
@ -378,38 +425,38 @@ LLMutex* LLThreadSafeRefCount::sMutex = 0;
|
|||
//static
|
||||
void LLThreadSafeRefCount::initThreadSafeRefCount()
|
||||
{
|
||||
if (!sMutex)
|
||||
{
|
||||
sMutex = new LLMutex(0);
|
||||
}
|
||||
if (!sMutex)
|
||||
{
|
||||
sMutex = new LLMutex(0);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void LLThreadSafeRefCount::cleanupThreadSafeRefCount()
|
||||
{
|
||||
delete sMutex;
|
||||
sMutex = NULL;
|
||||
delete sMutex;
|
||||
sMutex = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
LLThreadSafeRefCount::LLThreadSafeRefCount() :
|
||||
mRef(0)
|
||||
mRef(0)
|
||||
{
|
||||
}
|
||||
|
||||
LLThreadSafeRefCount::LLThreadSafeRefCount(const LLThreadSafeRefCount& src)
|
||||
{
|
||||
mRef = 0;
|
||||
mRef = 0;
|
||||
}
|
||||
|
||||
LLThreadSafeRefCount::~LLThreadSafeRefCount()
|
||||
{
|
||||
if (mRef != 0)
|
||||
{
|
||||
LL_ERRS() << "deleting non-zero reference" << LL_ENDL;
|
||||
}
|
||||
if (mRef != 0)
|
||||
{
|
||||
LL_ERRS() << "deleting non-zero reference" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
|
|
|||
|
|
@ -38,118 +38,120 @@ LL_COMMON_API void assert_main_thread();
|
|||
|
||||
namespace LLTrace
|
||||
{
|
||||
class ThreadRecorder;
|
||||
class ThreadRecorder;
|
||||
}
|
||||
|
||||
class LL_COMMON_API LLThread
|
||||
{
|
||||
private:
|
||||
friend class LLMutex;
|
||||
static U32 sIDIter;
|
||||
friend class LLMutex;
|
||||
static U32 sIDIter;
|
||||
|
||||
public:
|
||||
typedef enum e_thread_status
|
||||
{
|
||||
STOPPED = 0, // The thread is not running. Not started, or has exited its run function
|
||||
RUNNING = 1, // The thread is currently running
|
||||
QUITTING= 2 // Someone wants this thread to quit
|
||||
} EThreadStatus;
|
||||
typedef enum e_thread_status
|
||||
{
|
||||
STOPPED = 0, // The thread is not running. Not started, or has exited its run function
|
||||
RUNNING = 1, // The thread is currently running
|
||||
QUITTING= 2, // Someone wants this thread to quit
|
||||
CRASHED = -1 // An uncaught exception was thrown by the thread
|
||||
} EThreadStatus;
|
||||
|
||||
LLThread(const std::string& name, apr_pool_t *poolp = NULL);
|
||||
virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state.
|
||||
virtual void shutdown(); // stops the thread
|
||||
|
||||
bool isQuitting() const { return (QUITTING == mStatus); }
|
||||
bool isStopped() const { return (STOPPED == mStatus); }
|
||||
|
||||
static U32 currentID(); // Return ID of current thread
|
||||
static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure.
|
||||
|
||||
LLThread(const std::string& name, apr_pool_t *poolp = NULL);
|
||||
virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state.
|
||||
virtual void shutdown(); // stops the thread
|
||||
|
||||
bool isQuitting() const { return (QUITTING == mStatus); }
|
||||
bool isStopped() const { return (STOPPED == mStatus) || (CRASHED == mStatus); }
|
||||
bool isCrashed() const { return (CRASHED == mStatus); }
|
||||
|
||||
static U32 currentID(); // Return ID of current thread
|
||||
static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure.
|
||||
|
||||
public:
|
||||
// PAUSE / RESUME functionality. See source code for important usage notes.
|
||||
// Called from MAIN THREAD.
|
||||
void pause();
|
||||
void unpause();
|
||||
bool isPaused() { return isStopped() || mPaused == TRUE; }
|
||||
|
||||
// Cause the thread to wake up and check its condition
|
||||
void wake();
|
||||
// PAUSE / RESUME functionality. See source code for important usage notes.
|
||||
// Called from MAIN THREAD.
|
||||
void pause();
|
||||
void unpause();
|
||||
bool isPaused() { return isStopped() || mPaused == TRUE; }
|
||||
|
||||
// Cause the thread to wake up and check its condition
|
||||
void wake();
|
||||
|
||||
// Same as above, but to be used when the condition is already locked.
|
||||
void wakeLocked();
|
||||
// Same as above, but to be used when the condition is already locked.
|
||||
void wakeLocked();
|
||||
|
||||
// Called from run() (CHILD THREAD). Pause the thread if requested until unpaused.
|
||||
void checkPause();
|
||||
// Called from run() (CHILD THREAD). Pause the thread if requested until unpaused.
|
||||
void checkPause();
|
||||
|
||||
// this kicks off the apr thread
|
||||
void start(void);
|
||||
// this kicks off the apr thread
|
||||
void start(void);
|
||||
|
||||
apr_pool_t *getAPRPool() { return mAPRPoolp; }
|
||||
LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
|
||||
apr_pool_t *getAPRPool() { return mAPRPoolp; }
|
||||
LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
|
||||
|
||||
U32 getID() const { return mID; }
|
||||
U32 getID() const { return mID; }
|
||||
|
||||
// Called by threads *not* created via LLThread to register some
|
||||
// internal state used by LLMutex. You must call this once early
|
||||
// in the running thread to prevent collisions with the main thread.
|
||||
static void registerThreadID();
|
||||
|
||||
// Called by threads *not* created via LLThread to register some
|
||||
// internal state used by LLMutex. You must call this once early
|
||||
// in the running thread to prevent collisions with the main thread.
|
||||
static void registerThreadID();
|
||||
|
||||
private:
|
||||
BOOL mPaused;
|
||||
|
||||
// static function passed to APR thread creation routine
|
||||
static void *APR_THREAD_FUNC staticRun(struct apr_thread_t *apr_threadp, void *datap);
|
||||
BOOL mPaused;
|
||||
|
||||
// static function passed to APR thread creation routine
|
||||
static void *APR_THREAD_FUNC staticRun(struct apr_thread_t *apr_threadp, void *datap);
|
||||
|
||||
protected:
|
||||
std::string mName;
|
||||
class LLCondition* mRunCondition;
|
||||
LLMutex* mDataLock;
|
||||
std::string mName;
|
||||
class LLCondition* mRunCondition;
|
||||
LLMutex* mDataLock;
|
||||
|
||||
apr_thread_t *mAPRThreadp;
|
||||
apr_pool_t *mAPRPoolp;
|
||||
BOOL mIsLocalPool;
|
||||
EThreadStatus mStatus;
|
||||
U32 mID;
|
||||
LLTrace::ThreadRecorder* mRecorder;
|
||||
apr_thread_t *mAPRThreadp;
|
||||
apr_pool_t *mAPRPoolp;
|
||||
BOOL mIsLocalPool;
|
||||
EThreadStatus mStatus;
|
||||
U32 mID;
|
||||
LLTrace::ThreadRecorder* mRecorder;
|
||||
|
||||
//a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used.
|
||||
//Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes.
|
||||
// otherwise it will cause severe memory leaking!!! --bao
|
||||
LLVolatileAPRPool *mLocalAPRFilePoolp ;
|
||||
//a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used.
|
||||
//Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes.
|
||||
// otherwise it will cause severe memory leaking!!! --bao
|
||||
LLVolatileAPRPool *mLocalAPRFilePoolp ;
|
||||
|
||||
void setQuitting();
|
||||
|
||||
// virtual function overridden by subclass -- this will be called when the thread runs
|
||||
virtual void run(void) = 0;
|
||||
|
||||
// virtual predicate function -- returns true if the thread should wake up, false if it should sleep.
|
||||
virtual bool runCondition(void);
|
||||
void setQuitting();
|
||||
|
||||
// virtual function overridden by subclass -- this will be called when the thread runs
|
||||
virtual void run(void) = 0;
|
||||
|
||||
// virtual predicate function -- returns true if the thread should wake up, false if it should sleep.
|
||||
virtual bool runCondition(void);
|
||||
|
||||
// Lock/Unlock Run Condition -- use around modification of any variable used in runCondition()
|
||||
inline void lockData();
|
||||
inline void unlockData();
|
||||
|
||||
// This is the predicate that decides whether the thread should sleep.
|
||||
// It should only be called with mDataLock locked, since the virtual runCondition() function may need to access
|
||||
// data structures that are thread-unsafe.
|
||||
bool shouldSleep(void) { return (mStatus == RUNNING) && (isPaused() || (!runCondition())); }
|
||||
// Lock/Unlock Run Condition -- use around modification of any variable used in runCondition()
|
||||
inline void lockData();
|
||||
inline void unlockData();
|
||||
|
||||
// This is the predicate that decides whether the thread should sleep.
|
||||
// It should only be called with mDataLock locked, since the virtual runCondition() function may need to access
|
||||
// data structures that are thread-unsafe.
|
||||
bool shouldSleep(void) { return (mStatus == RUNNING) && (isPaused() || (!runCondition())); }
|
||||
|
||||
// To avoid spurious signals (and the associated context switches) when the condition may or may not have changed, you can do the following:
|
||||
// mDataLock->lock();
|
||||
// if(!shouldSleep())
|
||||
// mRunCondition->signal();
|
||||
// mDataLock->unlock();
|
||||
// To avoid spurious signals (and the associated context switches) when the condition may or may not have changed, you can do the following:
|
||||
// mDataLock->lock();
|
||||
// if(!shouldSleep())
|
||||
// mRunCondition->signal();
|
||||
// mDataLock->unlock();
|
||||
};
|
||||
|
||||
|
||||
void LLThread::lockData()
|
||||
{
|
||||
mDataLock->lock();
|
||||
mDataLock->lock();
|
||||
}
|
||||
|
||||
void LLThread::unlockData()
|
||||
{
|
||||
mDataLock->unlock();
|
||||
mDataLock->unlock();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -160,9 +162,9 @@ void LLThread::unlockData()
|
|||
class LL_COMMON_API LLResponder : public LLThreadSafeRefCount
|
||||
{
|
||||
protected:
|
||||
virtual ~LLResponder();
|
||||
virtual ~LLResponder();
|
||||
public:
|
||||
virtual void completed(bool success) = 0;
|
||||
virtual void completed(bool success) = 0;
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
|
|
|
|||
|
|
@ -247,6 +247,25 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
|
|||
response->setHeaders(mReplyHeaders);
|
||||
response->setRequestURL(mReqURL);
|
||||
|
||||
std::string method("UNKNOWN");
|
||||
|
||||
if (mReqMethod == HOR_COPY)
|
||||
method = "COPY";
|
||||
else if (mReqMethod == HOR_DELETE)
|
||||
method = "DELETE";
|
||||
else if (mReqMethod == HOR_GET)
|
||||
method = "GET";
|
||||
else if (mReqMethod == HOR_MOVE)
|
||||
method = "MOVE";
|
||||
else if (mReqMethod == HOR_PATCH)
|
||||
method = "PATCH";
|
||||
else if (mReqMethod == HOR_POST)
|
||||
method = "POST";
|
||||
else if (mReqMethod == HOR_PUT)
|
||||
method = "PUT";
|
||||
|
||||
response->setRequestMethod(method);
|
||||
|
||||
if (mReplyOffset || mReplyLength)
|
||||
{
|
||||
// Got an explicit offset/length in response
|
||||
|
|
|
|||
|
|
@ -450,7 +450,7 @@ bool HttpPolicy::stageAfterCompletion(const HttpOpRequest::ptr_t &op)
|
|||
|
||||
op->stageFromActive(mService);
|
||||
|
||||
HTTPStats::instance().recordResultCode(op->mStatus.getStatus());
|
||||
HTTPStats::instance().recordResultCode(op->mStatus.getType());
|
||||
return false; // not active
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ namespace LLCore
|
|||
// ====================================
|
||||
// HttpRequest Implementation
|
||||
// ====================================
|
||||
HttpRequest::Statistics HttpRequest::mStatistics;
|
||||
|
||||
|
||||
HttpRequest::HttpRequest()
|
||||
|
|
@ -64,11 +63,7 @@ HttpRequest::HttpRequest()
|
|||
|
||||
mReplyQueue.reset( new HttpReplyQueue() );
|
||||
|
||||
++mStatistics.mCurrentRequests;
|
||||
++mStatistics.mTotalRequests;
|
||||
|
||||
|
||||
LL_WARNS("HTTPRequest") << "New HttpRequest created (outstanding: " << mStatistics.mCurrentRequests << " total: " << mStatistics.mTotalRequests << ")" << LL_ENDL;
|
||||
HTTPStats::instance().recordHTTPRequest();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -81,9 +76,6 @@ HttpRequest::~HttpRequest()
|
|||
}
|
||||
|
||||
mReplyQueue.reset();
|
||||
--mStatistics.mCurrentRequests;
|
||||
|
||||
LL_WARNS("HTTPRequest") << "HttpRequest destroyed (outstanding: " << mStatistics.mCurrentRequests << " total: " << mStatistics.mTotalRequests << ")" << LL_ENDL;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -681,19 +681,6 @@ private:
|
|||
// End Global State
|
||||
// ====================================
|
||||
|
||||
struct Statistics
|
||||
{
|
||||
Statistics():
|
||||
mTotalRequests(0),
|
||||
mCurrentRequests(0)
|
||||
{}
|
||||
|
||||
S32 mTotalRequests;
|
||||
S32 mCurrentRequests;
|
||||
};
|
||||
|
||||
static Statistics mStatistics;
|
||||
|
||||
}; // end class HttpRequest
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -204,6 +204,15 @@ public:
|
|||
return mRequestUrl;
|
||||
}
|
||||
|
||||
void setRequestMethod(const std::string &method)
|
||||
{
|
||||
mRequestMethod = method;
|
||||
}
|
||||
|
||||
const std::string &getRequestMethod() const
|
||||
{
|
||||
return mRequestMethod;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Response data here
|
||||
|
|
@ -217,6 +226,7 @@ protected:
|
|||
unsigned int mRetries;
|
||||
unsigned int m503Retries;
|
||||
std::string mRequestUrl;
|
||||
std::string mRequestMethod;
|
||||
|
||||
TransferStats::ptr_t mStats;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ void HTTPStats::resetStats()
|
|||
mResutCodes.clear();
|
||||
mDataDown.reset();
|
||||
mDataUp.reset();
|
||||
mRequests = 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -60,16 +61,41 @@ void HTTPStats::recordResultCode(S32 code)
|
|||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string byte_count_converter(F32 bytes)
|
||||
{
|
||||
static const char unit_suffix[] = { 'B', 'K', 'M', 'G' };
|
||||
|
||||
F32 value = bytes;
|
||||
int suffix = 0;
|
||||
|
||||
while ((value > 1024.0) && (suffix < 3))
|
||||
{
|
||||
value /= 1024.0;
|
||||
++suffix;
|
||||
}
|
||||
|
||||
std::stringstream out;
|
||||
|
||||
out << std::setprecision(4) << value << unit_suffix[suffix];
|
||||
|
||||
return out.str();
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPStats::dumpStats()
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
out << "HTTPCore Stats" << std::endl;
|
||||
out << "Bytes Sent: " << mDataUp.getSum() << std::endl;
|
||||
out << "Bytes Recv: " << mDataDown.getSum() << std::endl;
|
||||
out << "HTTP DATA SUMMARY" << std::endl;
|
||||
out << "HTTP Transfer counts:" << std::endl;
|
||||
out << "Data Sent: " << byte_count_converter(mDataUp.getSum()) << " (" << mDataUp.getSum() << ")" << std::endl;
|
||||
out << "Data Recv: " << byte_count_converter(mDataDown.getSum()) << " (" << mDataDown.getSum() << ")" << std::endl;
|
||||
out << "Total requests: " << mRequests << "(request objects created)" << std::endl;
|
||||
out << std::endl;
|
||||
out << "Result Codes:" << std::endl << "--- -----" << std::endl;
|
||||
|
||||
|
||||
for (std::map<S32, S32>::iterator it = mResutCodes.begin(); it != mResutCodes.end(); ++it)
|
||||
{
|
||||
out << (*it).first << " " << (*it).second << std::endl;
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ namespace LLCore
|
|||
mDataUp.push(bytes);
|
||||
}
|
||||
|
||||
void recordHTTPRequest() { ++mRequests; }
|
||||
|
||||
void recordResultCode(S32 code);
|
||||
|
||||
void dumpStats();
|
||||
|
|
@ -62,6 +64,8 @@ namespace LLCore
|
|||
StatsAccumulator mDataDown;
|
||||
StatsAccumulator mDataUp;
|
||||
|
||||
S32 mRequests;
|
||||
|
||||
std::map<S32, S32> mResutCodes;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ void logMessageSuccess(std::string logAuth, std::string url, std::string message
|
|||
|
||||
void logMessageFail(std::string logAuth, std::string url, std::string message)
|
||||
{
|
||||
LL_WARNS() << logAuth << " Failure '" << message << "' for " << url << LL_ENDL;
|
||||
LL_WARNS("CoreHTTP") << logAuth << " Failure '" << message << "' for " << url << LL_ENDL;
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
|
|
@ -279,12 +279,10 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons
|
|||
result = LLSD::emptyMap();
|
||||
LLCore::HttpStatus::type_enum_t errType = status.getType();
|
||||
|
||||
LL_WARNS()
|
||||
<< "\n--------------------------------------------------------------------------\n"
|
||||
<< " Error[" << status.toTerseString() << "] cannot access url '" << response->getRequestURL()
|
||||
<< "' because " << status.toString()
|
||||
<< "\n--------------------------------------------------------------------------"
|
||||
<< LL_ENDL;
|
||||
LL_WARNS("CoreHTTP")
|
||||
<< " Error[" << status.toTerseString() << "] cannot "<< response->getRequestMethod()
|
||||
<< " to url '" << response->getRequestURL()
|
||||
<< "' because " << status.toString() << LL_ENDL;
|
||||
if ((errType >= 400) && (errType < 500))
|
||||
{
|
||||
LLSD body = this->parseBody(response, parseSuccess);
|
||||
|
|
@ -299,7 +297,6 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons
|
|||
result = body;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -323,7 +320,7 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons
|
|||
if (getBoolSetting(HTTP_LOGBODY_KEY))
|
||||
{
|
||||
// commenting out, but keeping since this can be useful for debugging
|
||||
LL_WARNS() << "Returned body=" << std::endl << httpStatus["error_body"].asString() << LL_ENDL;
|
||||
LL_WARNS("CoreHTTP") << "Returned body=" << std::endl << httpStatus["error_body"].asString() << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -423,7 +420,7 @@ LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore:
|
|||
if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType))
|
||||
{
|
||||
std::string thebody = LLCoreHttpUtil::responseToString(response);
|
||||
LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] "
|
||||
LL_WARNS("CoreHTTP") << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] "
|
||||
<< " body: " << thebody << LL_ENDL;
|
||||
|
||||
// Replace the status with a new one indicating the failure.
|
||||
|
|
@ -442,7 +439,7 @@ LLSD HttpCoroLLSDHandler::handleSuccess(LLCore::HttpResponse * response, LLCore:
|
|||
if (contentType && (HTTP_CONTENT_LLSD_XML == *contentType))
|
||||
{
|
||||
std::string thebody = LLCoreHttpUtil::responseToString(response);
|
||||
LL_WARNS() << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] "
|
||||
LL_WARNS("CoreHTTP") << "Failed to deserialize . " << response->getRequestURL() << " [status:" << response->getStatus().toString() << "] "
|
||||
<< " body: " << thebody << LL_ENDL;
|
||||
|
||||
// Replace the status with a new one indicating the failure.
|
||||
|
|
@ -1210,7 +1207,7 @@ LLSD HttpCoroutineAdapter::buildImmediateErrorResult(const LLCore::HttpRequest::
|
|||
const std::string &url)
|
||||
{
|
||||
LLCore::HttpStatus status = request->getStatus();
|
||||
LL_WARNS() << "Error posting to " << url << " Status=" << status.getStatus() <<
|
||||
LL_WARNS("CoreHTTP") << "Error posting to " << url << " Status=" << status.getStatus() <<
|
||||
" message = " << status.getMessage() << LL_ENDL;
|
||||
|
||||
// Mimic the status results returned from an http error that we had
|
||||
|
|
|
|||
Loading…
Reference in New Issue