Merge viewer-64

master
Ansariel 2017-08-16 20:22:58 +02:00
commit 13b6febd34
28 changed files with 897 additions and 776 deletions

View File

@ -3431,9 +3431,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>01b463520b0f253842335428901404ae</string>
<string>333a679f0a492e060b4586eaa1a38a56</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/7371/27810/viewer_manager-1.0.507360-darwin64-507360.tar.bz2</string>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/7692/29540/viewer_manager-1.0.507681-darwin64-507681.tar.bz2</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -3455,9 +3455,9 @@
<key>archive</key>
<map>
<key>hash</key>
<string>2f8626ce0448d56ecfd07e51affadcfd</string>
<string>bf4672af39013418d721327d337ba1a0</string>
<key>url</key>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/7372/27832/viewer_manager-1.0.507360-windows-507360.tar.bz2</string>
<string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/7694/29546/viewer_manager-1.0.507681-windows-507681.tar.bz2</string>
</map>
<key>name</key>
<string>windows</string>
@ -3468,7 +3468,7 @@
<key>source_type</key>
<string>hg</string>
<key>version</key>
<string>1.0.507360</string>
<string>1.0.507681</string>
</map>
<key>vlc-bin</key>
<map>

View File

@ -226,6 +226,7 @@ set(llcommon_HEADER_FILES
llstring.h
llstringtable.h
llstaticstringtable.h
llstatsaccumulator.h
llsys.h
llthread.h
llthreadlocalstorage.h

View File

@ -0,0 +1,120 @@
/**
* @file llstatsaccumulator.h
* @brief Class for accumulating statistics.
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_STATS_ACCUMULATOR_H
#define LL_STATS_ACCUMULATOR_H
#include "llsd.h"
class LLStatsAccumulator
{
public:
inline LLStatsAccumulator()
{
reset();
}
inline void push(F32 val)
{
if (mCountOfNextUpdatesToIgnore > 0)
{
mCountOfNextUpdatesToIgnore--;
return;
}
mCount++;
mSum += val;
mSumOfSquares += val * val;
if (mCount == 1 || val > mMaxValue)
{
mMaxValue = val;
}
if (mCount == 1 || val < mMinValue)
{
mMinValue = val;
}
}
inline F32 getSum() const
{
return mSum;
}
inline F32 getMean() const
{
return (mCount == 0) ? 0.f : ((F32)mSum) / mCount;
}
inline F32 getMinValue() const
{
return mMinValue;
}
inline F32 getMaxValue() const
{
return mMaxValue;
}
inline F32 getStdDev() const
{
const F32 mean = getMean();
return (mCount < 2) ? 0.f : sqrtf(llmax(0.f, mSumOfSquares / mCount - (mean * mean)));
}
inline U32 getCount() const
{
return mCount;
}
inline void reset()
{
mCount = 0;
mSum = mSumOfSquares = 0.f;
mMinValue = 0.0f;
mMaxValue = 0.0f;
mCountOfNextUpdatesToIgnore = 0;
}
inline LLSD asLLSD() const
{
LLSD data;
data["mean"] = getMean();
data["std_dev"] = getStdDev();
data["count"] = (S32)mCount;
data["min"] = getMinValue();
data["max"] = getMaxValue();
return data;
}
private:
S32 mCount;
F32 mSum;
F32 mSumOfSquares;
F32 mMinValue;
F32 mMaxValue;
U32 mCountOfNextUpdatesToIgnore;
};
#endif

View File

@ -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;
}
}
//============================================================================

View File

@ -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;
};
//============================================================================

View File

@ -34,6 +34,7 @@ set(llcorehttp_SOURCE_FILES
httpoptions.cpp
httprequest.cpp
httpresponse.cpp
httpstats.cpp
_httplibcurl.cpp
_httpopcancel.cpp
_httpoperation.cpp
@ -61,6 +62,7 @@ set(llcorehttp_HEADER_FILES
httpoptions.h
httprequest.h
httpresponse.h
httpstats.h
_httpinternal.h
_httplibcurl.h
_httpopcancel.h

View File

@ -47,6 +47,8 @@
#include "llhttpconstants.h"
#include "llproxy.h"
#include "httpstats.h"
// *DEBUG: "[curl:bugs] #1420" problem and testing.
//
// A pipelining problem, https://sourceforge.net/p/curl/bugs/1420/,
@ -245,6 +247,8 @@ void HttpOpRequest::visitNotifier(HttpRequest * request)
response->setHeaders(mReplyHeaders);
response->setRequestURL(mReqURL);
response->setRequestMethod(methodToString(mReqMethod));
if (mReplyOffset || mReplyLength)
{
// Got an explicit offset/length in response
@ -805,6 +809,7 @@ size_t HttpOpRequest::writeCallback(void * data, size_t size, size_t nmemb, void
}
const size_t req_size(size * nmemb);
const size_t write_size(op->mReplyBody->append(static_cast<char *>(data), req_size));
HTTPStats::instance().recordDataDown(write_size);
return write_size;
}
@ -833,7 +838,8 @@ size_t HttpOpRequest::readCallback(void * data, size_t size, size_t nmemb, void
const size_t do_size((std::min)(req_size, body_size - op->mCurlBodyPos));
const size_t read_size(op->mReqBody->read(op->mCurlBodyPos, static_cast<char *>(data), do_size));
op->mCurlBodyPos += read_size;
HTTPStats::instance().recordDataUp(read_size);
op->mCurlBodyPos += read_size;
return read_size;
}
@ -1145,6 +1151,25 @@ int HttpOpRequest::debugCallback(CURL * handle, curl_infotype info, char * buffe
return 0;
}
std::string HttpOpRequest::methodToString(const HttpOpRequest::EMethod &e)
{
if (e == HOR_COPY)
return "COPY";
else if (e == HOR_DELETE)
return "DELETE";
else if (e == HOR_GET)
return "GET";
else if (e == HOR_MOVE)
return "MOVE";
else if (e == HOR_PATCH)
return "PATCH";
else if (e == HOR_POST)
return "POST";
else if (e == HOR_PUT)
return "PUT";
return "UNKNOWN";
}
} // end namespace LLCore

View File

@ -87,7 +87,8 @@ public:
HOR_COPY,
HOR_MOVE
};
static std::string methodToString(const EMethod &);
virtual void stageFromRequest(HttpService *);
virtual void stageFromReady(HttpService *);
virtual void stageFromActive(HttpService *);
@ -235,6 +236,7 @@ public:
}; // end class HttpOpRequest
/// HttpOpRequestCompare isn't an operation but a uniform comparison
/// functor for STL containers that order by priority. Mainly
/// used for the ready queue container but defined here.

View File

@ -34,6 +34,7 @@
#include "_httppolicyclass.h"
#include "lltimer.h"
#include "httpstats.h"
namespace
{
@ -448,6 +449,8 @@ bool HttpPolicy::stageAfterCompletion(const HttpOpRequest::ptr_t &op)
}
op->stageFromActive(mService);
HTTPStats::instance().recordResultCode(op->mStatus.getType());
return false; // not active
}

View File

@ -38,7 +38,8 @@
#include "lltimer.h"
#include "llthread.h"
#include "llexception.h"
#include "llmemory.h"
namespace
{
@ -293,22 +294,42 @@ void HttpService::threadRun(LLCoreInt::HttpThread * thread)
ELoopSpeed loop(REQUEST_SLEEP);
while (! mExitRequested)
{
loop = processRequestQueue(loop);
try
{
loop = processRequestQueue(loop);
// Process ready queue issuing new requests as needed
ELoopSpeed new_loop = mPolicy->processReadyQueue();
loop = (std::min)(loop, new_loop);
// Process ready queue issuing new requests as needed
ELoopSpeed new_loop = mPolicy->processReadyQueue();
loop = (std::min)(loop, new_loop);
// Give libcurl some cycles
new_loop = mTransport->processTransport();
loop = (std::min)(loop, new_loop);
// Give libcurl some cycles
new_loop = mTransport->processTransport();
loop = (std::min)(loop, new_loop);
// Determine whether to spin, sleep briefly or sleep for next request
if (REQUEST_SLEEP != loop)
{
ms_sleep(HTTP_SERVICE_LOOP_SLEEP_NORMAL_MS);
}
}
// Determine whether to spin, sleep briefly or sleep for next request
if (REQUEST_SLEEP != loop)
{
ms_sleep(HTTP_SERVICE_LOOP_SLEEP_NORMAL_MS);
}
}
catch (const LLContinueError&)
{
LOG_UNHANDLED_EXCEPTION("");
}
catch (std::bad_alloc)
{
LLMemory::logMemoryInfo(TRUE);
//output possible call stacks to log file.
LLError::LLCallStacks::print();
LL_ERRS() << "Bad memory allocation in HttpService::threadRun()!" << LL_ENDL;
}
catch (...)
{
CRASH_ON_UNHANDLED_EXCEPTION("");
}
}
shutdown();
sState = STOPPED;

View File

@ -25,6 +25,8 @@
*/
#include "bufferarray.h"
#include "llexception.h"
#include "llmemory.h"
// BufferArray is a list of chunks, each a BufferArray::Block, of contiguous
@ -140,8 +142,22 @@ size_t BufferArray::append(const void * src, size_t len)
{
mBlocks.reserve(mBlocks.size() + 5);
}
Block * block = Block::alloc(BLOCK_ALLOC_SIZE);
memcpy(block->mData, c_src, copy_len);
Block * block;
try
{
block = Block::alloc(BLOCK_ALLOC_SIZE);
}
catch (std::bad_alloc)
{
LLMemory::logMemoryInfo(TRUE);
//output possible call stacks to log file.
LLError::LLCallStacks::print();
LL_WARNS() << "Bad memory allocation in thrown by Block::alloc in read!" << LL_ENDL;
break;
}
memcpy(block->mData, c_src, copy_len);
block->mUsed = copy_len;
llassert_always(block->mUsed <= block->mAlloced);
mBlocks.push_back(block);
@ -149,7 +165,7 @@ size_t BufferArray::append(const void * src, size_t len)
c_src += copy_len;
len -= copy_len;
}
return ret;
return ret - len;
}

View File

@ -37,7 +37,7 @@
#include "_httpopsetget.h"
#include "lltimer.h"
#include "httpstats.h"
namespace
{
@ -62,6 +62,8 @@ HttpRequest::HttpRequest()
mRequestQueue->addRef();
mReplyQueue.reset( new HttpReplyQueue() );
HTTPStats::instance().recordHTTPRequest();
}

View File

@ -680,7 +680,7 @@ private:
/// @}
// End Global State
// ====================================
}; // end class HttpRequest

View File

@ -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;
};

View File

@ -0,0 +1,108 @@
/**
* @file llviewerstats.cpp
* @brief LLViewerStats class implementation
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "httpstats.h"
#include "llerror.h"
namespace LLCore
{
HTTPStats::HTTPStats()
{
resetStats();
}
HTTPStats::~HTTPStats()
{
}
void HTTPStats::resetStats()
{
mResutCodes.clear();
mDataDown.reset();
mDataUp.reset();
mRequests = 0;
}
void HTTPStats::recordResultCode(S32 code)
{
std::map<S32, S32>::iterator it;
it = mResutCodes.find(code);
if (it == mResutCodes.end())
mResutCodes[code] = 1;
else
(*it).second = (*it).second + 1;
}
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 << "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;
}
LL_WARNS("HTTP Core") << out.str() << LL_ENDL;
}
}

View File

@ -0,0 +1,74 @@
/**
* @file llviewerim_peningtats.h
* @brief LLViewerStats class header file
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#ifndef LL_LLVIEWERSTATS_H
#define LL_LLVIEWERSTATS_H
#include "lltracerecording.h"
#include "lltrace.h"
#include "llstatsaccumulator.h"
#include "llsingleton.h"
#include "llsd.h"
namespace LLCore
{
class HTTPStats : public LLSingleton<HTTPStats>
{
LLSINGLETON(HTTPStats);
virtual ~HTTPStats();
public:
void resetStats();
typedef LLStatsAccumulator StatsAccumulator;
void recordDataDown(size_t bytes)
{
mDataDown.push(bytes);
}
void recordDataUp(size_t bytes)
{
mDataUp.push(bytes);
}
void recordHTTPRequest() { ++mRequests; }
void recordResultCode(S32 code);
void dumpStats();
private:
StatsAccumulator mDataDown;
StatsAccumulator mDataUp;
S32 mRequests;
std::map<S32, S32> mResutCodes;
};
}
#endif // LL_LLVIEWERSTATS_H

View File

@ -215,7 +215,8 @@ void HttpRequestTestObjectType::test<1>()
HttpRequest::destroyService();
// make sure we didn't leak any memory
ensure("Memory returned", mMemTotal == GetMemTotal());
// nat 2017-08-15 don't: requires total stasis in every other subsystem
// ensure("Memory returned", mMemTotal == GetMemTotal());
}
catch (...)
{

View File

@ -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

View File

@ -39,6 +39,7 @@
#include <curl/curl.h>
#include "llcorehttputil.h"
#include "httpstats.h"
#ifdef OPENSIM
#include "llviewernetwork.h"
@ -317,6 +318,8 @@ void LLAppCoreHttp::requestStop()
void LLAppCoreHttp::cleanup()
{
LLCore::HTTPStats::instance().dumpStats();
if (LLCORE_HTTP_HANDLE_INVALID == mStopHandle)
{
// Should have been started already...

View File

@ -1286,6 +1286,19 @@ bool LLAppViewer::init()
}
}
char* PARENT = getenv("PARENT");
if (! (PARENT && std::string(PARENT) == "SL_Launcher"))
{
// Don't directly run this executable. Please run the launcher, which
// will run the viewer itself.
// Naturally we do not consider this bulletproof. The point is to
// gently remind a user who *inadvertently* finds him/herself in this
// situation to do things the Right Way. Anyone who intentionally
// bypasses this mechanism needs no reminder that s/he's shooting
// him/herself in the foot.
LLNotificationsUtil::add("RunLauncher");
}
#if LL_WINDOWS
if (gGLManager.mGLVersion < LLFeatureManager::getInstance()->getExpectedGLVersion())
{
@ -4093,6 +4106,7 @@ void LLAppViewer::writeSystemInfo()
gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch();
gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild();
gDebugInfo["ClientInfo"]["AddressSize"] = LLVersionInfo::getAddressSize();
// <FS:ND> Add which flavor of FS generated an error
#ifdef OPENSIM

View File

@ -852,13 +852,13 @@ LLSD LLFastTimerView::analyzePerformanceLogDefault(std::istream& is)
for(stats_map_t::iterator it = time_stats.begin(); it != time_stats.end(); ++it)
{
std::string label = it->first;
ret[label]["TotalTime"] = time_stats[label].mSum;
ret[label]["TotalTime"] = time_stats[label].getSum();
ret[label]["MeanTime"] = time_stats[label].getMean();
ret[label]["MaxTime"] = time_stats[label].getMaxValue();
ret[label]["MinTime"] = time_stats[label].getMinValue();
ret[label]["StdDevTime"] = time_stats[label].getStdDev();
ret[label]["Samples"] = sample_stats[label].mSum;
ret[label]["Samples"] = sample_stats[label].getSum();
ret[label]["MaxSamples"] = sample_stats[label].getMaxValue();
ret[label]["MinSamples"] = sample_stats[label].getMinValue();
ret[label]["StdDevSamples"] = sample_stats[label].getStdDev();

View File

@ -31,6 +31,7 @@
// llcommon
#include "llevents.h"
#include "stringize.h"
#include "llsdserialize.h"
// llmessage (!)
#include "llfiltersd2xmlrpc.h" // for xml_escape_string()
@ -47,12 +48,10 @@
#include "llstartup.h"
#include "llfloaterreg.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
#include "llwindow.h"
#include "llviewerwindow.h"
#include "llprogressview.h"
#if LL_LINUX
#include "lltrans.h"
#endif
#include "llsecapi.h"
#include "llstartup.h"
#include "llmachineid.h"
@ -265,62 +264,89 @@ bool LLLoginInstance::handleLoginEvent(const LLSD& event)
void LLLoginInstance::handleLoginFailure(const LLSD& event)
{
// Login has failed.
// Figure out why and respond...
LLSD response = event["data"];
std::string reason_response = response["reason"].asString();
std::string message_response = response["message"].asString();
// For the cases of critical message or TOS agreement,
// start the TOS dialog. The dialog response will be handled
// by the LLLoginInstance::handleTOSResponse() callback.
// The callback intiates the login attempt next step, either
// to reconnect or to end the attempt in failure.
if(reason_response == "tos")
{
LL_INFOS() << "LLLoginInstance::handleLoginFailure ToS" << LL_ENDL;
// Login has failed.
// Figure out why and respond...
LLSD response = event["data"];
std::string reason_response = response["reason"].asString();
std::string message_response = response["message"].asString();
// For the cases of critical message or TOS agreement,
// start the TOS dialog. The dialog response will be handled
// by the LLLoginInstance::handleTOSResponse() callback.
// The callback intiates the login attempt next step, either
// to reconnect or to end the attempt in failure.
if(reason_response == "tos")
{
LL_INFOS() << "LLLoginInstance::handleLoginFailure ToS" << LL_ENDL;
LLSD data(LLSD::emptyMap());
data["message"] = message_response;
data["reply_pump"] = TOS_REPLY_PUMP;
if (gViewerWindow)
gViewerWindow->setShowProgress(FALSE, FALSE);
LLFloaterReg::showInstance("message_tos", data);
LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
.listen(TOS_LISTENER_NAME,
boost::bind(&LLLoginInstance::handleTOSResponse,
this, _1, "agree_to_tos"));
}
else if(reason_response == "critical")
{
LL_INFOS() << "LLLoginInstance::handleLoginFailure Crit" << LL_ENDL;
LLSD data(LLSD::emptyMap());
data["message"] = message_response;
data["reply_pump"] = TOS_REPLY_PUMP;
if (gViewerWindow)
gViewerWindow->setShowProgress(FALSE,FALSE);
LLFloaterReg::showInstance("message_tos", data);
LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
.listen(TOS_LISTENER_NAME,
boost::bind(&LLLoginInstance::handleTOSResponse,
this, _1, "agree_to_tos"));
}
else if(reason_response == "critical")
{
LL_INFOS() << "LLLoginInstance::handleLoginFailure Crit" << LL_ENDL;
LLSD data(LLSD::emptyMap());
data["message"] = message_response;
data["reply_pump"] = TOS_REPLY_PUMP;
if(response.has("error_code"))
{
data["error_code"] = response["error_code"];
}
if(response.has("certificate"))
{
data["certificate"] = response["certificate"];
}
if (gViewerWindow)
gViewerWindow->setShowProgress(FALSE, FALSE);
LLFloaterReg::showInstance("message_critical", data);
LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
.listen(TOS_LISTENER_NAME,
boost::bind(&LLLoginInstance::handleTOSResponse,
this, _1, "read_critical"));
}
else if(reason_response == "update")
{
// This shouldn't happen - the viewer manager should have forced an update;
// possibly the user ran the viewer directly and bypassed the update check
std::string required_version = response["message_args"]["VERSION"];
LL_WARNS() << "Login failed because an update to version " << required_version << " is required." << LL_ENDL;
LLSD data(LLSD::emptyMap());
data["message"] = message_response;
data["reply_pump"] = TOS_REPLY_PUMP;
if(response.has("error_code"))
{
data["error_code"] = response["error_code"];
}
if(response.has("certificate"))
{
data["certificate"] = response["certificate"];
}
if (gViewerWindow)
gViewerWindow->setShowProgress(FALSE,FALSE);
LLFloaterReg::showInstance("message_critical", data);
LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
.listen(TOS_LISTENER_NAME,
boost::bind(&LLLoginInstance::handleTOSResponse,
this, _1, "read_critical"));
}
else
{
LL_INFOS() << "LLLoginInstance::handleLoginFailure attemptComplete" << LL_ENDL;
attemptComplete();
}
if (gViewerWindow)
gViewerWindow->setShowProgress(FALSE, FALSE);
LLSD data(LLSD::emptyMap());
data["VERSION"] = required_version;
LLNotificationsUtil::add("RequiredUpdate", data, LLSD::emptyMap(), boost::bind(&LLLoginInstance::handleLoginDisallowed, this, _1, _2));
}
else if(reason_response == "key")
{
// this is a password problem or other restriction
// an appropriate message has already been displayed
attemptComplete();
}
else
{
LL_WARNS() << "Login failed for an unknown reason: " << LLSDOStreamer<LLSDNotationFormatter>(response) << LL_ENDL;
if (gViewerWindow)
gViewerWindow->setShowProgress(FALSE, FALSE);
LLNotificationsUtil::add("LoginFailedUnknown", LLSD::emptyMap(), LLSD::emptyMap(), boost::bind(&LLLoginInstance::handleLoginDisallowed, this, _1, _2));
}
}
void LLLoginInstance::handleLoginDisallowed(const LLSD& notification, const LLSD& response)
{
attemptComplete();
}
void LLLoginInstance::handleLoginSuccess(const LLSD& event)
@ -377,6 +403,7 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
return true;
}
std::string construct_start_string()
{
std::string start;

View File

@ -80,6 +80,7 @@ private:
void handleLoginSuccess(const LLSD& event);
void handleDisconnect(const LLSD& event);
void handleIndeterminate(const LLSD& event);
void handleLoginDisallowed(const LLSD& notification, const LLSD& response);
bool handleTOSResponse(bool v, const std::string& key);

View File

@ -82,6 +82,9 @@ public:
static const std::string& getBuildPlatform();
// [/SL:KB]
/// return the bit width of an address
static const S32 getAddressSize() { return ADDRESS_SIZE; }
typedef enum
{
TEST_VIEWER,

View File

@ -30,7 +30,7 @@
#include "lltextureinfo.h"
#include "lltracerecording.h"
#include "lltrace.h"
#include "llstatsaccumulator.h"
enum ESimStatID
{
@ -261,91 +261,9 @@ public:
void addToMessage(LLSD &body);
struct StatsAccumulator
{
S32 mCount;
F32 mSum;
F32 mSumOfSquares;
F32 mMinValue;
F32 mMaxValue;
U32 mCountOfNextUpdatesToIgnore;
typedef LLStatsAccumulator StatsAccumulator;
inline StatsAccumulator()
{
reset();
}
inline void push( F32 val )
{
if ( mCountOfNextUpdatesToIgnore > 0 )
{
mCountOfNextUpdatesToIgnore--;
return;
}
mCount++;
mSum += val;
mSumOfSquares += val * val;
if (mCount == 1 || val > mMaxValue)
{
mMaxValue = val;
}
if (mCount == 1 || val < mMinValue)
{
mMinValue = val;
}
}
inline F32 getMean() const
{
return (mCount == 0) ? 0.f : ((F32)mSum)/mCount;
}
inline F32 getMinValue() const
{
return mMinValue;
}
inline F32 getMaxValue() const
{
return mMaxValue;
}
inline F32 getStdDev() const
{
const F32 mean = getMean();
// <FS:CR> Fix implicit conversion double to float
//return (mCount < 2) ? 0.f : sqrt(llmax(0.f,mSumOfSquares/mCount - (mean * mean)));
return (mCount < 2) ? 0.f : sqrtf(llmax(0.f,mSumOfSquares/mCount - (mean * mean)));
}
inline U32 getCount() const
{
return mCount;
}
inline void reset()
{
mCount = 0;
mSum = mSumOfSquares = 0.f;
mMinValue = 0.0f;
mMaxValue = 0.0f;
mCountOfNextUpdatesToIgnore = 0;
}
inline LLSD asLLSD() const
{
LLSD data;
data["mean"] = getMean();
data["std_dev"] = getStdDev();
data["count"] = (S32)mCount;
data["min"] = getMinValue();
data["max"] = getMaxValue();
return data;
}
};
// Phase tracking (originally put in for avatar rezzing), tracking
// Phase tracking (originally put in for avatar rezzing), tracking
// progress of active/completed phases for activities like outfit changing.
typedef std::map<std::string,LLTimer> phase_map_t;
typedef std::map<std::string,StatsAccumulator> phase_stats_t;

View File

@ -1795,6 +1795,13 @@ Visit [_URL] for more information?
<tag>fail</tag>
</notification>
<notification
icon="alertmodal.tga"
name="RunLauncher"
type="alertmodal">
Please do not directly run the viewer executable. Update any existing shortcuts to run SL_Launcher instead.
</notification>
<notification
icon="alertmodal.tga"
name="OldGPUDriver"
@ -3942,143 +3949,12 @@ Finished download of raw terrain file to:
<notification
icon="alertmodal.tga"
name="DownloadWindowsMandatory"
name="RequiredUpdate"
type="alertmodal">
A new version of [APP_NAME] is available.
[MESSAGE]
You must download this update to use [APP_NAME].
Version [VERSION] is required for login.
This should have been updated for you but apparently was not.
Please download from https://secondlife.com/support/downloads/
<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Quit"
yestext="Download"/>
</notification>
<notification
icon="alertmodal.tga"
name="DownloadWindows"
type="alertmodal">
An updated version of [APP_NAME] is available.
[MESSAGE]
This update is not required, but we suggest you install it to improve performance and stability.
<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Continue"
yestext="Download"/>
</notification>
<notification
icon="alertmodal.tga"
name="DownloadWindowsReleaseForDownload"
type="alertmodal">
An updated version of [APP_NAME] is available.
[MESSAGE]
This update is not required, but we suggest you install it to improve performance and stability.
<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Continue"
yestext="Download"/>
</notification>
<notification
icon="alertmodal.tga"
name="DownloadLinuxMandatory"
type="alertmodal">
A new version of [APP_NAME] is available.
[MESSAGE]
You must download this update to use [APP_NAME].
<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Quit"
yestext="Download"/>
</notification>
<notification
icon="alertmodal.tga"
name="DownloadLinux"
type="alertmodal">
An updated version of [APP_NAME] is available.
[MESSAGE]
This update is not required, but we suggest you install it to improve performance and stability.
<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Continue"
yestext="Download"/>
</notification>
<notification
icon="alertmodal.tga"
name="DownloadLinuxReleaseForDownload"
type="alertmodal">
An updated version of [APP_NAME] is available.
[MESSAGE]
This update is not required, but we suggest you install it to improve performance and stability.
<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Continue"
yestext="Download"/>
</notification>
<notification
icon="alertmodal.tga"
name="DownloadMacMandatory"
type="alertmodal">
A new version of [APP_NAME] is available.
[MESSAGE]
You must download this update to use [APP_NAME].
Download to your Applications folder?
<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Quit"
yestext="Download"/>
</notification>
<notification
icon="alertmodal.tga"
name="DownloadMac"
type="alertmodal">
An updated version of [APP_NAME] is available.
[MESSAGE]
This update is not required, but we suggest you install it to improve performance and stability.
Download to your Applications folder?
<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Continue"
yestext="Download"/>
</notification>
<notification
icon="alertmodal.tga"
name="DownloadMacReleaseForDownload"
type="alertmodal">
An updated version of [APP_NAME] is available.
[MESSAGE]
This update is not required, but we suggest you install it to improve performance and stability.
Download to your Applications folder?
<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Continue"
yestext="Download"/>
</notification>
<notification
icon="alertmodal.tga"
name="FailedUpdateInstall"
type="alertmodal">
An error occurred installing the viewer update.
Please download and install the latest viewer from
http://secondlife.com/download.
<usetemplate
name="okbutton"
yestext="OK"/>
@ -4086,195 +3962,16 @@ http://secondlife.com/download.
<notification
icon="alertmodal.tga"
name="FailedRequiredUpdateInstall"
name="LoginFailedUnknown"
type="alertmodal">
We were unable to install a required update.
You will be unable to log in until [APP_NAME] has been updated.
Please download and install the latest viewer from
http://secondlife.com/download.
<tag>fail</tag>
Sorry, login failed for an unrecognized reason.
If you continue to get this message, please check the [SUPPORT_SITE].
<tag>confirm</tag>
<usetemplate
name="okbutton"
yestext="Quit"/>
</notification>
<notification
icon="alertmodal.tga"
name="UpdaterServiceNotRunning"
type="alertmodal">
There is a required update for your Second Life Installation.
You may download this update from http://www.secondlife.com/downloads
or you can install it now.
<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Quit Second Life"
yestext="Download and install now"/>
</notification>
<notification
icon="notify.tga"
name="DownloadBackgroundTip"
type="notify">
We have downloaded an update to your [APP_NAME] installation.
Version [VERSION] [[INFO_URL] Information about this update]
<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Later..."
yestext="Install now and restart [APP_NAME]"/>
</notification>
<notification
icon="alertmodal.tga"
name="DownloadBackgroundDialog"
type="alertmodal">
We have downloaded an update to your [APP_NAME] installation.
Version [VERSION] [[INFO_URL] Information about this update]
<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Later..."
yestext="Install now and restart [APP_NAME]"/>
</notification>
<notification
icon="alertmodal.tga"
name="RequiredUpdateDownloadedVerboseDialog"
type="alertmodal"
force_urls_external="true">
We have downloaded a required software update.
Version [VERSION] [[INFO_URL] Information about this update]
We must restart [APP_NAME] to install the update.
<tag>confirm</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="RequiredUpdateDownloadedDialog"
type="alertmodal"
force_urls_external="true">
We must restart [APP_NAME] to install the update.
[[INFO_URL] Information about this update]
<tag>confirm</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="notify.tga"
name="OtherChannelDownloadBackgroundTip"
type="notify">
We have downloaded an update to your [APP_NAME] installation.
Version [VERSION]
This experimental viewer has been replaced by a [NEW_CHANNEL] viewer;
see [[INFO_URL] for details about this update]
<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Later..."
yestext="Install now and restart [APP_NAME]"/>
</notification>
<notification
icon="alertmodal.tga"
name="OtherChannelDownloadBackgroundDialog"
type="alertmodal">
We have downloaded an update to your [APP_NAME] installation.
Version [VERSION]
This experimental viewer has been replaced by a [NEW_CHANNEL] viewer;
see [[INFO_URL] Information about this update]
<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Later..."
yestext="Install now and restart [APP_NAME]"/>
</notification>
<notification
icon="alertmodal.tga"
name="OtherChannelRequiredUpdateDownloadedVerboseDialog"
type="alertmodal"
force_urls_external="true">
We have downloaded a required software update.
Version [VERSION]
This experimental viewer has been replaced by a [NEW_CHANNEL] viewer;
see [[INFO_URL] Information about this update]
We must restart [APP_NAME] to install the update.
<tag>confirm</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="OtherChannelRequiredUpdateDownloadedDialog"
type="alertmodal"
force_urls_external="true">
We must restart [APP_NAME] to install the update.
This experimental viewer has been replaced by a [NEW_CHANNEL] viewer;
see [[INFO_URL] Information about this update]
<tag>confirm</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="UpdateDownloadInProgress"
type="alertmodal">
An update is available!
It's downloading in the background and we will prompt you to restart your viewer to finish installing it as soon as it's ready.
<tag>confirm</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="UpdateDownloadComplete"
type="alertmodal">
An update was downloaded. It will be installed during restart.
<tag>confirm</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="UpdateDeferred"
type="alertmodal">
An update was downloaded that you previously chose to skip or defer to the next start up.
<tag>confirm</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="UpdateViewerUpToDate"
type="alertmodal">
Your viewer is up to date!
If you can't wait to try out the latest features and fixes, check out the Alternate Viewers page. http://wiki.secondlife.com/wiki/Linden_Lab_Official:Alternate_Viewers.
<tag>confirm</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="DeedObjectToGroup"

View File

@ -40,6 +40,7 @@
// other Linden headers
#include "../test/lltut.h"
#include "llevents.h"
#include "llnotificationsutil.h"
#if defined(LL_WINDOWS)
#pragma warning(disable: 4355) // using 'this' in base-class ctor initializer expr
@ -112,6 +113,19 @@ void LLCredential::authenticatorType(std::string &idType)
{
}
LLNotificationPtr LLNotificationsUtil::add(const std::string& name,
const LLSD& substitutions,
const LLSD& payload,
boost::function<void (const LLSD&, const LLSD&)> functor)
{
return LLNotificationPtr((LLNotification*)NULL);
}
LLNotificationPtr LLNotificationsUtil::add(const std::string& name, const LLSD& args)
{
return LLNotificationPtr((LLNotification*)NULL);
}
//-----------------------------------------------------------------------------
#include "../llviewernetwork.h"
LLGridManager::~LLGridManager()

View File

@ -1346,6 +1346,18 @@ class DarwinManifest(ViewerManifest):
keychain_pwd_path = os.path.join(build_secrets_checkout,'code-signing-osx','password.txt')
keychain_pwd = open(keychain_pwd_path).read().rstrip()
# Note: As of macOS Sierra, keychains are created with names postfixed with '-db' so for example, the
# SL Viewer keychain would by default be found in ~/Library/Keychains/viewer.keychain-db instead of
# just ~/Library/Keychains/viewer.keychain in earlier versions.
#
# Because we have old OS files from previous versions of macOS on the build hosts, the configurations
# are different on each host. Some have viewer.keychain, some have viewer.keychain-db and some have both.
# As you can see in the line below, this script expects the Linden Developer cert/keys to be in viewer.keychain.
#
# To correctly sign builds you need to make sure ~/Library/Keychains/viewer.keychain exists on the host
# and that it contains the correct cert/key. If a build host is set up with a clean version of macOS Sierra (or later)
# then you will need to change this line (and the one for 'codesign' command below) to point to right place or else
# pull in the cert/key into the default viewer keychain 'viewer.keychain-db' and export it to 'viewer.keychain'
self.run_command('security unlock-keychain -p "%s" "%s/Library/Keychains/viewer.keychain"' % ( keychain_pwd, home_path ) )
signed=False
sign_attempts=3
@ -1354,6 +1366,7 @@ class DarwinManifest(ViewerManifest):
try:
sign_attempts-=1;
self.run_command(
# Note: See blurb above about names of keychains
'codesign --verbose --deep --force --keychain "%(home_path)s/Library/Keychains/viewer.keychain" --sign %(identity)r %(bundle)r' % {
'home_path' : home_path,
'identity': identity,