Merge branch 'future'

This commit is contained in:
TighMacFanatic
2011-09-24 22:36:40 -04:00
1001 changed files with 46799 additions and 16555 deletions

View File

@@ -31,10 +31,10 @@ if (WINDOWS)
# Don't build DLLs.
set(BUILD_SHARED_LIBS OFF)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd"
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /arch:SSE2"
CACHE STRING "C++ compiler debug options" FORCE)
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
"${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP"
"${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP /arch:SSE2"
CACHE STRING "C++ compiler release-with-debug options" FORCE)
set(CMAKE_CXX_FLAGS_RELEASE
"${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP /arch:SSE /fp:fast"
@@ -295,6 +295,7 @@ endif (STANDALONE)
if(1 EQUAL 1)
add_definitions(-DOPENSIM_RULES=1)
add_definitions(-DMESH_ENABLED=1)
endif(1 EQUAL 1)
if(SERVER)

View File

@@ -19,3 +19,8 @@ set(LLCOMMON_INCLUDE_DIRS
)
set(LLCOMMON_LIBRARIES llcommon)
set(LLCOMMON_LINK_SHARED ON CACHE BOOL "Build the llcommon target as a shared library.")
if(LLCOMMON_LINK_SHARED)
add_definitions(-DLL_COMMON_LINK_SHARED=1)
endif(LLCOMMON_LINK_SHARED)

View File

@@ -2,9 +2,9 @@
include(Prebuilt)
if (NOT STANDALONE)
use_prebuilt_binary(GL)
use_prebuilt_binary(glext)
# possible glh_linear should have its own .cmake file instead
#use_prebuilt_binary(glh_linear)
# actually... not any longer, it's now in git -SG
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
endif (NOT STANDALONE)

View File

@@ -89,7 +89,7 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro
//********************************
LLAPRFile infile ;
infile.open(in_fname,LL_APR_RB, LLAPRFile::global);
infile.open(in_fname,LL_APR_RB);
//********************************
if (!infile.getFileHandle())
{
@@ -240,7 +240,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname
S32 data_left = 0;
LLAPRFile infile ;
infile.open(in_fname,LL_APR_RB, LLAPRFile::global);
infile.open(in_fname,LL_APR_RB);
if (!infile.getFileHandle())
{
llwarns << "Couldn't open temporary ogg file for writing: " << in_fname
@@ -249,7 +249,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname
}
LLAPRFile outfile ;
outfile.open(out_fname,LL_APR_WPB, LLAPRFile::global);
outfile.open(out_fname,LL_APR_WPB);
if (!outfile.getFileHandle())
{
llwarns << "Couldn't open upload sound file for reading: " << in_fname

View File

@@ -225,8 +225,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
//--------------------------------------------------------------------
std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName);
LLAPRFile infile ;
infile.open(path, LL_APR_R, LLAPRFile::global);
LLAPRFile infile(path, LL_APR_R);
apr_file_t *fp = infile.getFileHandle();
if (!fp)
return E_ST_NO_XLT_FILE;

View File

@@ -45,7 +45,7 @@
LLStringTable LLCharacter::sVisualParamNames(1024);
std::vector< LLCharacter* > LLCharacter::sInstances;
BOOL LLCharacter::sAllowInstancesChange = TRUE ;
//-----------------------------------------------------------------------------
// LLCharacter()
@@ -59,8 +59,10 @@ LLCharacter::LLCharacter()
mSkeletonSerialNum( 0 ),
mInAppearance( false )
{
mMotionController.setCharacter( this );
llassert_always(sAllowInstancesChange) ;
sInstances.push_back(this);
mMotionController.setCharacter( this );
mPauseRequest = new LLPauseRequestHandle();
}
@@ -77,11 +79,22 @@ LLCharacter::~LLCharacter()
{
delete param;
}
std::vector<LLCharacter*>::iterator iter = std::find(sInstances.begin(), sInstances.end(), this);
if (iter != sInstances.end())
U32 i ;
U32 size = sInstances.size() ;
for(i = 0 ; i < size ; i++)
{
sInstances.erase(iter);
if(sInstances[i] == this)
{
break ;
}
}
llassert_always(i < size) ;
llassert_always(sAllowInstancesChange) ;
sInstances[i] = sInstances[size - 1] ;
sInstances.pop_back() ;
}

View File

@@ -42,7 +42,7 @@
#include "llmotioncontroller.h"
#include "llvisualparam.h"
#include "string_table.h"
#include "llmemory.h"
#include "llpointer.h"
#include "llthread.h"
class LLPolyMesh;
@@ -279,6 +279,7 @@ public:
void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; }
static std::vector< LLCharacter* > sInstances;
static BOOL sAllowInstancesChange ; //debug use
protected:
LLMotionController mMotionController;

View File

@@ -56,6 +56,9 @@ LLJoint::LLJoint()
mUpdateXform = TRUE;
mJointNum = -1;
touch();
#if MESH_ENABLED
mResetAfterRestoreOldXform = false;
#endif //MESH_ENABLED
}
@@ -239,6 +242,43 @@ void LLJoint::setPosition( const LLVector3& pos )
}
}
#if MESH_ENABLED
//--------------------------------------------------------------------
// setPosition()
//--------------------------------------------------------------------
void LLJoint::setDefaultFromCurrentXform( void )
{
mDefaultXform = mXform;
touch(MATRIX_DIRTY | POSITION_DIRTY);
}
//--------------------------------------------------------------------
// storeCurrentXform()
//--------------------------------------------------------------------
void LLJoint::storeCurrentXform( const LLVector3& pos )
{
mOldXform = mXform;
mResetAfterRestoreOldXform = true;
setPosition( pos );
}
//--------------------------------------------------------------------
// restoreOldXform()
//--------------------------------------------------------------------
void LLJoint::restoreOldXform( void )
{
mResetAfterRestoreOldXform = false;
mXform = mOldXform;
}
//--------------------------------------------------------------------
// restoreOldXform()
//--------------------------------------------------------------------
void LLJoint::restoreToDefaultXform( void )
{
mXform = mDefaultXform;
setPosition( mXform.getPosition() );
}
#endif //MESH_ENABLED
//--------------------------------------------------------------------
// getWorldPosition()

View File

@@ -86,10 +86,19 @@ protected:
// explicit transformation members
LLXformMatrix mXform;
#if MESH_ENABLED
LLXformMatrix mOldXform;
LLXformMatrix mDefaultXform;
LLUUID mId;
#endif //MESH_ENABLED
public:
U32 mDirtyFlags;
BOOL mUpdateXform;
#if MESH_ENABLED
BOOL mResetAfterRestoreOldXform;
#endif //MESH_ENABLED
// describes the skin binding pose
LLVector3 mSkinOffset;
@@ -179,6 +188,24 @@ public:
S32 getJointNum() const { return mJointNum; }
void setJointNum(S32 joint_num) { mJointNum = joint_num; }
#if MESH_ENABLED
void restoreOldXform( void );
void restoreToDefaultXform( void );
void setDefaultFromCurrentXform( void );
void storeCurrentXform( const LLVector3& pos );
//Accessor for the joint id
LLUUID getId( void ) { return mId; }
//Setter for the joints id
void setId( const LLUUID& id ) { mId = id;}
//If the old transform flag has been set, then the reset logic in avatar needs to be aware(test) of it
const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; }
//Setter for joint reset flag
void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; }
#endif //MESH_ENABLED
// <edit>
std::string exportString(U32 tabs = 0);
// </edit>

View File

@@ -37,7 +37,7 @@
// Header Files
//-----------------------------------------------------------------------------
#include "lljoint.h"
#include "llmemory.h"
#include "llrefcount.h"
//-----------------------------------------------------------------------------
// class LLJointState

View File

@@ -838,7 +838,11 @@ void LLKeyframeMotion::initializeConstraint(JointConstraint* constraint)
S32 joint_num;
LLVector3 source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[0]);
if ( !cur_joint )
{
return;
}
F32 source_pos_offset = dist_vec(source_pos, cur_joint->getWorldPosition());
constraint->mTotalLength = constraint->mJointLengths[0] = dist_vec(cur_joint->getParent()->getWorldPosition(), source_pos);
@@ -889,6 +893,10 @@ void LLKeyframeMotion::activateConstraint(JointConstraint* constraint)
for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
{
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
if ( !cur_joint )
{
return;
}
constraint->mPositions[joint_num] = (cur_joint->getWorldPosition() - mPelvisp->getWorldPosition()) * ~mPelvisp->getWorldRotation();
}
@@ -949,6 +957,10 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
}
LLJoint* root_joint = getJoint(shared_data->mJointStateIndices[shared_data->mChainLength]);
if (! root_joint)
{
return;
}
LLVector3 root_pos = root_joint->getWorldPosition();
// LLQuaternion root_rot =
root_joint->getParent()->getWorldRotation();
@@ -960,6 +972,11 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
{
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
if (!cur_joint)
{
return;
}
if (joint_mask[cur_joint->getJointNum()] >= (0xff >> (7 - getPriority())))
{
// skip constraint
@@ -1050,7 +1067,14 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
if (shared_data->mChainLength)
{
LLQuaternion end_rot = getJoint(shared_data->mJointStateIndices[0])->getWorldRotation();
LLJoint* end_joint = getJoint(shared_data->mJointStateIndices[0]);
if (!end_joint)
{
return;
}
LLQuaternion end_rot = end_joint->getWorldRotation();
// slam start and end of chain to the proper positions (rest of chain stays put)
positions[0] = lerp(keyframe_source_pos, target_pos, weight);
@@ -1059,7 +1083,14 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
// grab keyframe-specified positions of joints
for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
{
LLVector3 kinematic_position = getJoint(shared_data->mJointStateIndices[joint_num])->getWorldPosition() +
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
if (!cur_joint)
{
return;
}
LLVector3 kinematic_position = cur_joint->getWorldPosition() +
(source_to_target * constraint->mJointLengthFractions[joint_num]);
// convert intermediate joint positions to world coordinates
@@ -1105,7 +1136,17 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
for (joint_num = shared_data->mChainLength; joint_num > 0; joint_num--)
{
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
if (!cur_joint)
{
return;
}
LLJoint* child_joint = getJoint(shared_data->mJointStateIndices[joint_num - 1]);
if (!child_joint)
{
return;
}
LLQuaternion parent_rot = cur_joint->getParent()->getWorldRotation();
LLQuaternion cur_rot = cur_joint->getWorldRotation();
@@ -1139,7 +1180,6 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
cur_joint->setRotation(target_rot);
}
LLJoint* end_joint = getJoint(shared_data->mJointStateIndices[0]);
LLQuaternion end_local_rot = end_rot * ~end_joint->getParent()->getWorldRotation();
if (weight == 1.f)
@@ -1162,12 +1202,18 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
constraint->mPositions[joint_num] = new_pos;
}
constraint->mFixupDistanceRMS *= 1.f / (constraint->mTotalLength * (F32)(shared_data->mChainLength - 1));
constraint->mFixupDistanceRMS = fsqrtf(constraint->mFixupDistanceRMS);
constraint->mFixupDistanceRMS = (F32) sqrt(constraint->mFixupDistanceRMS);
//reset old joint rots
for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
{
getJoint(shared_data->mJointStateIndices[joint_num])->setRotation(old_rots[joint_num]);
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
if (!cur_joint)
{
return;
}
cur_joint->setRotation(old_rots[joint_num]);
}
}
// simple positional constraint (pelvis only)
@@ -1816,7 +1862,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
constraintp->mJointStateIndices[i] = -1;
for (U32 j = 0; j < mJointMotionList->getNumJointMotions(); j++)
{
if(getJoint(j) == joint)
LLJoint* constraint_joint = getJoint(j);
if ( !constraint_joint )
{
llwarns << "Invalid joint " << j << llendl;
return FALSE;
}
if(constraint_joint == joint)
{
constraintp->mJointStateIndices[i] = (S32)j;
break;

View File

@@ -357,8 +357,7 @@ BOOL LLKeyframeMotionParam::loadMotions()
// open the file
//-------------------------------------------------------------------------
S32 fileSize = 0;
LLAPRFile infile ;
infile.open(path, LL_APR_R, LLAPRFile::global, &fileSize);
LLAPRFile infile(path, LL_APR_R, &fileSize);
apr_file_t* fp = infile.getFileHandle() ;
if (!fp || fileSize == 0)
{

View File

@@ -89,6 +89,7 @@ LLJointState *LLPose::getNextJointState()
//-----------------------------------------------------------------------------
BOOL LLPose::addJointState(const LLPointer<LLJointState>& jointState)
{
llassert_always(jointState.notNull());
if (mJointMap.find(jointState->getJoint()->getName()) == mJointMap.end())
{
mJointMap[jointState->getJoint()->getName()] = jointState;
@@ -161,6 +162,7 @@ void LLPose::setWeight(F32 weight)
// <edit>
// there was a crash here
// </edit>
llassert_always(iter->second.notNull());
iter->second->setWeight(weight);
}
mWeight = weight;

View File

@@ -40,6 +40,8 @@
#include "lljointstate.h"
#include "lljoint.h"
#include "llmap.h"
#include "llpointer.h"
#include <map>
#include <string>

View File

@@ -210,8 +210,7 @@ LLFSMState* LLStateDiagram::getState(U32 state_id)
BOOL LLStateDiagram::saveDotFile(const std::string& filename)
{
LLAPRFile outfile ;
outfile.open(filename, LL_APR_W, LLAPRFile::global);
LLAPRFile outfile(filename, LL_APR_W);
apr_file_t* dot_file = outfile.getFileHandle() ;
if (!dot_file)

View File

@@ -15,11 +15,11 @@ include_directories(
)
set(llcommon_SOURCE_FILES
aiaprpool.cpp
imageids.cpp
indra_constants.cpp
llapp.cpp
llapr.cpp
llaprpool.cpp
llassettype.cpp
llavatarname.cpp
llbase32.cpp
@@ -39,6 +39,7 @@ set(llcommon_SOURCE_FILES
llfile.cpp
llfindlocale.cpp
llfixedbuffer.cpp
llfoldertype.cpp
llformat.cpp
llframetimer.cpp
llheartbeat.cpp
@@ -57,12 +58,15 @@ set(llcommon_SOURCE_FILES
llprocessor.cpp
llqueuedthread.cpp
llrand.cpp
llrefcount.cpp
llrun.cpp
llscopedvolatileaprpool.h
llsd.cpp
llsdserialize.cpp
llsdserialize_xml.cpp
llsdutil.cpp
llsecondlifeurls.cpp
llsingleton.cpp
llstat.cpp
llstacktrace.cpp
llstreamtools.cpp
@@ -70,6 +74,7 @@ set(llcommon_SOURCE_FILES
llstringtable.cpp
llsys.cpp
llthread.cpp
llthreadsafequeue.cpp
lltimer.cpp
lluri.cpp
lluuid.cpp
@@ -84,7 +89,6 @@ set(llcommon_SOURCE_FILES
set(llcommon_HEADER_FILES
CMakeLists.txt
aiaprpool.h
aithreadsafe.h
bitpack.h
ctype_workaround.h
@@ -93,10 +97,12 @@ set(llcommon_HEADER_FILES
indra_constants.h
linden_common.h
linked_lists.h
llaccountingcost.h
llagentconstants.h
llavatarname.h
llapp.h
llapr.h
llaprpool.h
llassettype.h
llassoclist.h
llavatarconstants.h
@@ -133,6 +139,7 @@ set(llcommon_HEADER_FILES
llfile.h
llfindlocale.h
llfixedbuffer.h
llfoldertype.h
llformat.h
llframetimer.h
llhash.h
@@ -157,6 +164,7 @@ set(llcommon_HEADER_FILES
llmortician.h
llnametable.h
lloptioninterface.h
llpointer.h
llpreprocessor.h
llpriqueuemap.h
llprocesslauncher.h
@@ -165,14 +173,17 @@ set(llcommon_HEADER_FILES
llptrskipmap.h
llqueuedthread.h
llrand.h
llrefcount.h
llrun.h
llscopedvolatileaprpool.h
llrefcount.h
llsafehandle.h
llsd.h
llsdserialize.h
llsdserialize_xml.h
llsdutil.h
llsecondlifeurls.h
llsimplehash.h
llsingleton.h
llskiplist.h
llskipmap.h
llstack.h
@@ -186,7 +197,9 @@ set(llcommon_HEADER_FILES
llstringtable.h
llsys.h
llthread.h
llthreadsafequeue.h
lltimer.h
lltreeiterators.h
lluri.h
lluuid.h
lluuidhashmap.h
@@ -203,6 +216,7 @@ set(llcommon_HEADER_FILES
stdenums.h
stdtypes.h
string_table.h
stringize.h
timer.h
timing.h
u64.h
@@ -222,6 +236,7 @@ target_link_libraries(
${EXPAT_LIBRARIES}
${ZLIB_LIBRARIES}
${WINDOWS_LIBRARIES}
${BOOST_REGEX_LIBRARY}
${CWDEBUG_LIBRARIES}
${CORESERVICES_LIBRARY}
)

View File

@@ -175,7 +175,7 @@ protected:
// For use by AIThreadSafeDC
AIThreadSafe(void) { }
AIThreadSafe(AIAPRPool& parent) : mRWLock(parent) { }
AIThreadSafe(LLAPRPool& parent) : mRWLock(parent) { }
public:
// Only for use by AITHREADSAFE, see below.
@@ -406,7 +406,7 @@ protected:
friend struct AIRegisteredStateMachinesList;
// For use by AIThreadSafeSimpleDC and AIRegisteredStateMachinesList.
AIThreadSafeSimple(void) { }
AIThreadSafeSimple(AIAPRPool& parent) : mMutex(parent) { }
AIThreadSafeSimple(LLAPRPool& parent) : mMutex(parent) { }
public:
// Only for use by AITHREADSAFESIMPLE, see below.
@@ -471,7 +471,7 @@ public:
protected:
// For use by AIThreadSafeSimpleDCRootPool
AIThreadSafeSimpleDC(AIAPRPool& parent) : AIThreadSafeSimple<T>(parent) { new (AIThreadSafeSimple<T>::ptr()) T; }
AIThreadSafeSimpleDC(LLAPRPool& parent) : AIThreadSafeSimple<T>(parent) { new (AIThreadSafeSimple<T>::ptr()) T; }
};
// Helper class for AIThreadSafeSimpleDCRootPool to assure initialization of
@@ -479,7 +479,7 @@ protected:
class AIThreadSafeSimpleDCRootPool_pbase
{
protected:
AIAPRRootPool mRootPool;
LLAPRRootPool mRootPool;
private:
template<typename T> friend class AIThreadSafeSimpleDCRootPool;
@@ -489,7 +489,7 @@ private:
/**
* @brief A wrapper class for objects that need to be accessed by more than one thread.
*
* The same as AIThreadSafeSimpleDC except that this class creates its own AIAPRRootPool
* The same as AIThreadSafeSimpleDC except that this class creates its own LLAPRRootPool
* for the internally used mutexes and condition, instead of using the current threads
* root pool. The advantage of this is that it can be used for objects that need to
* be accessed from the destructors of global objects (after main). The disadvantage

View File

@@ -324,6 +324,14 @@ const F32 CHAT_SHOUT_RADIUS = 100.f;
const F32 CHAT_MAX_RADIUS = CHAT_SHOUT_RADIUS;
const F32 CHAT_MAX_RADIUS_BY_TWO = CHAT_MAX_RADIUS / 2.f;
// squared editions of the above for distance checks
const F32 CHAT_WHISPER_RADIUS_SQUARED = CHAT_WHISPER_RADIUS * CHAT_WHISPER_RADIUS;
const F32 CHAT_NORMAL_RADIUS_SQUARED = CHAT_NORMAL_RADIUS * CHAT_NORMAL_RADIUS;
const F32 CHAT_SHOUT_RADIUS_SQUARED = CHAT_SHOUT_RADIUS * CHAT_SHOUT_RADIUS;
const F32 CHAT_MAX_RADIUS_SQUARED = CHAT_SHOUT_RADIUS_SQUARED;
const F32 CHAT_MAX_RADIUS_BY_TWO_SQUARED = CHAT_MAX_RADIUS_BY_TWO * CHAT_MAX_RADIUS_BY_TWO;
// this times above gives barely audible radius
const F32 CHAT_BARELY_AUDIBLE_FACTOR = 2.0f;

View File

@@ -0,0 +1,86 @@
/**
* @file llaccountingcost.h
* @
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2011, 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_ACCOUNTINGQUOTA_H
#define LL_ACCOUNTINGQUOTA_H
struct ParcelQuota
{
ParcelQuota( F32 ownerRenderCost, F32 ownerPhysicsCost, F32 ownerNetworkCost, F32 ownerSimulationCost,
F32 groupRenderCost, F32 groupPhysicsCost, F32 groupNetworkCost, F32 groupSimulationCost,
F32 otherRenderCost, F32 otherPhysicsCost, F32 otherNetworkCost, F32 otherSimulationCost,
F32 tempRenderCost, F32 tempPhysicsCost, F32 tempNetworkCost, F32 tempSimulationCost,
F32 selectedRenderCost, F32 selectedPhysicsCost, F32 selectedNetworkCost, F32 selectedSimulationCost,
F32 parcelCapacity )
: mOwnerRenderCost( ownerRenderCost ), mOwnerPhysicsCost( ownerPhysicsCost )
, mOwnerNetworkCost( ownerNetworkCost ), mOwnerSimulationCost( ownerSimulationCost )
, mGroupRenderCost( groupRenderCost ), mGroupPhysicsCost( groupPhysicsCost )
, mGroupNetworkCost( groupNetworkCost ), mGroupSimulationCost( groupSimulationCost )
, mOtherRenderCost( otherRenderCost ), mOtherPhysicsCost( otherPhysicsCost )
, mOtherNetworkCost( otherNetworkCost ), mOtherSimulationCost( otherSimulationCost )
, mTempRenderCost( tempRenderCost ), mTempPhysicsCost( tempPhysicsCost )
, mTempNetworkCost( tempNetworkCost ), mTempSimulationCost( tempSimulationCost )
, mSelectedRenderCost( tempRenderCost ), mSelectedPhysicsCost( tempPhysicsCost )
, mSelectedNetworkCost( tempNetworkCost ), mSelectedSimulationCost( selectedSimulationCost )
, mParcelCapacity( parcelCapacity )
{
}
ParcelQuota(){}
F32 mOwnerRenderCost, mOwnerPhysicsCost, mOwnerNetworkCost, mOwnerSimulationCost;
F32 mGroupRenderCost, mGroupPhysicsCost, mGroupNetworkCost, mGroupSimulationCost;
F32 mOtherRenderCost, mOtherPhysicsCost, mOtherNetworkCost, mOtherSimulationCost;
F32 mTempRenderCost, mTempPhysicsCost, mTempNetworkCost, mTempSimulationCost;
F32 mSelectedRenderCost, mSelectedPhysicsCost, mSelectedNetworkCost, mSelectedSimulationCost;
F32 mParcelCapacity;
};
//SelectionQuota atm does not require a id
struct SelectionCost
{
SelectionCost( /*LLTransactionID transactionId, */ F32 physicsCost, F32 networkCost, F32 simulationCost )
//: mTransactionId( transactionId)
: mPhysicsCost( physicsCost )
, mNetworkCost( networkCost )
, mSimulationCost( simulationCost )
{
}
SelectionCost()
: mPhysicsCost( 0.0f )
, mNetworkCost( 0.0f )
, mSimulationCost( 0.0f )
{}
F32 mPhysicsCost, mNetworkCost, mSimulationCost;
//LLTransactionID mTransactionId;
};
typedef enum { Roots = 0 , Prims } eSelectionType;
#endif

View File

@@ -288,10 +288,13 @@ void LLApp::startErrorThread()
// Start the error handling thread, which is responsible for taking action
// when the app goes into the APP_STATUS_ERROR state
//
llinfos << "Starting error thread" << llendl;
mThreadErrorp = new LLErrorThread();
mThreadErrorp->setUserData((void *) this);
mThreadErrorp->start();
if(!mThreadErrorp)
{
llinfos << "Starting error thread" << llendl;
mThreadErrorp = new LLErrorThread();
mThreadErrorp->setUserData((void *) this);
mThreadErrorp->start();
}
}
void LLApp::setErrorHandler(LLAppErrorHandler handler)

View File

@@ -102,12 +102,12 @@ LLAPRFile::LLAPRFile()
{
}
LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type)
LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, S32* sizep, access_t access_type)
: mFile(NULL),
mVolatileFilePoolp(NULL),
mRegularFilePoolp(NULL)
{
open(filename, flags, access_type);
open(filename, flags, access_type, sizep);
}
LLAPRFile::~LLAPRFile()
@@ -147,18 +147,19 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
apr_status_t status;
{
apr_pool_t* apr_file_open_pool;
if (access_type == local)
// This is a temporary variable for a pool that is passed directly to apr_file_open below.
if (access_type == short_lived)
{
// Use a "volatile" thread-local pool.
mVolatileFilePoolp = &AIThreadLocalData::tldata().mVolatileAPRPool;
mVolatileFilePoolp = &LLThreadLocalData::tldata().mVolatileAPRPool;
// Access the pool and increment it's reference count.
// The reference count of AIVolatileAPRPool objects will be decremented
// The reference count of LLVolatileAPRPool objects will be decremented
// again in LLAPRFile::close by calling mVolatileFilePoolp->clearVolatileAPRPool().
apr_file_open_pool = mVolatileFilePoolp->getVolatileAPRPool();
}
else
{
mRegularFilePoolp = new AIAPRPool(AIThreadLocalData::tldata().mRootPool);
mRegularFilePoolp = new LLAPRPool(LLThreadLocalData::tldata().mRootPool);
apr_file_open_pool = (*mRegularFilePoolp)();
}
status = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_file_open_pool);
@@ -191,6 +192,10 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
return status;
}
apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool)
{
return open(filename, flags, use_global_pool ? LLAPRFile::long_lived : LLAPRFile::short_lived);
}
// File I/O
S32 LLAPRFile::read(void *buf, S32 nbytes)
{

View File

@@ -48,8 +48,8 @@
#include "apr_atomic.h"
#include "llstring.h"
class AIAPRPool;
class AIVolatileAPRPool;
class LLAPRPool;
class LLVolatileAPRPool;
/**
* @class LLScopedLock
@@ -140,20 +140,21 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable
// make this non copyable since a copy closes the file
private:
apr_file_t* mFile ;
AIVolatileAPRPool* mVolatileFilePoolp; // (Thread local) APR pool currently in use.
AIAPRPool* mRegularFilePoolp; // ...or a regular pool.
LLVolatileAPRPool* mVolatileFilePoolp; // (Thread local) APR pool currently in use.
LLAPRPool* mRegularFilePoolp; // ...or a regular pool.
public:
enum access_t {
global, // Use a global pool for long-lived file accesses. This should really only happen from the main thread.
local // Use a thread-local volatile pool for short file accesses.
long_lived, // Use a global pool for long-lived file accesses.
short_lived // Use a volatile pool for short-lived file accesses.
};
LLAPRFile() ;
LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type);
LLAPRFile(const std::string& filename, apr_int32_t flags, S32* sizep = NULL, access_t access_type = short_lived);
~LLAPRFile() ;
apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type, S32* sizep = NULL);
apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type = short_lived, S32* sizep = NULL);
apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use global pool.
apr_status_t close() ;
// Returns actual offset, -1 if seek fails

View File

@@ -1,5 +1,5 @@
/**
* @file aiaprpool.cpp
* @file LLAPRPool.cpp
*
* Copyright (c) 2010, Aleric Inglewood.
*
@@ -36,18 +36,18 @@
#include "linden_common.h"
#include "llerror.h"
#include "aiaprpool.h"
#include "llaprpool.h"
#include "llthread.h"
// Create a subpool from parent.
void AIAPRPool::create(AIAPRPool& parent)
void LLAPRPool::create(LLAPRPool& parent)
{
llassert(!mPool); // Must be non-initialized.
mParent = &parent;
if (!mParent) // Using the default parameter?
{
// By default use the root pool of the current thread.
mParent = &AIThreadLocalData::tldata().mRootPool;
mParent = &LLThreadLocalData::tldata().mRootPool;
}
llassert(mParent->mPool); // Parent must be initialized.
#if APR_HAS_THREADS
@@ -72,7 +72,7 @@ void AIAPRPool::create(AIAPRPool& parent)
}
// Destroy the (sub)pool, if any.
void AIAPRPool::destroy(void)
void LLAPRPool::destroy(void)
{
// Only do anything if we are not already (being) destroyed.
if (mPool)
@@ -92,12 +92,12 @@ void AIAPRPool::destroy(void)
}
}
bool AIAPRPool::parent_is_being_destructed(void)
bool LLAPRPool::parent_is_being_destructed(void)
{
return mParent && (!mParent->mPool || mParent->parent_is_being_destructed());
}
AIAPRInitialization::AIAPRInitialization(void)
LLAPRInitialization::LLAPRInitialization(void)
{
static bool apr_initialized = false;
@@ -109,13 +109,13 @@ AIAPRInitialization::AIAPRInitialization(void)
apr_initialized = true;
}
bool AIAPRRootPool::sCountInitialized = false;
apr_uint32_t volatile AIAPRRootPool::sCount;
bool LLAPRRootPool::sCountInitialized = false;
apr_uint32_t volatile LLAPRRootPool::sCount;
extern apr_thread_mutex_t* gLogMutexp;
extern apr_thread_mutex_t* gCallStacksLogMutexp;
apr_thread_mutex_t* gLogMutexp;
apr_thread_mutex_t* gCallStacksLogMutexp;
AIAPRRootPool::AIAPRRootPool(void) : AIAPRInitialization(), AIAPRPool(0)
LLAPRRootPool::LLAPRRootPool(void) : LLAPRInitialization(), LLAPRPool(0)
{
// sCountInitialized don't need locking because when we get here there is still only a single thread.
if (!sCountInitialized)
@@ -130,14 +130,14 @@ AIAPRRootPool::AIAPRRootPool(void) : AIAPRInitialization(), AIAPRPool(0)
sCountInitialized = true;
// Initialize thread-local APR pool support.
// Because this recursively calls AIAPRRootPool::AIAPRRootPool(void)
// Because this recursively calls LLAPRRootPool::LLAPRRootPool(void)
// it must be done last, so that sCount is already initialized.
AIThreadLocalData::init();
LLThreadLocalData::init();
}
apr_atomic_inc32(&sCount);
}
AIAPRRootPool::~AIAPRRootPool()
LLAPRRootPool::~LLAPRRootPool()
{
if (!apr_atomic_dec32(&sCount))
{
@@ -161,21 +161,21 @@ AIAPRRootPool::~AIAPRRootPool()
gCallStacksLogMutexp = NULL;
}
// Must destroy ALL, and therefore this last AIAPRRootPool, before terminating APR.
static_cast<AIAPRRootPool*>(this)->destroy();
// Must destroy ALL, and therefore this last LLAPRRootPool, before terminating APR.
static_cast<LLAPRRootPool*>(this)->destroy();
apr_terminate();
}
}
//static
AIAPRRootPool& AIAPRRootPool::get(void)
LLAPRRootPool& LLAPRRootPool::get(void)
{
static AIAPRRootPool global_APRpool(0); // This is what used to be gAPRPoolp.
static LLAPRRootPool global_APRpool(0); // This is what used to be gAPRPoolp.
return global_APRpool;
}
void AIVolatileAPRPool::clearVolatileAPRPool()
void LLVolatileAPRPool::clearVolatileAPRPool()
{
llassert_always(mNumActiveRef > 0);
if (--mNumActiveRef == 0)

View File

@@ -1,6 +1,6 @@
/**
* @file aiaprpool.h
* @brief Implementation of AIAPRPool.
* @file LLAPRPool.h
* @brief Implementation of LLAPRPool.
*
* Copyright (c) 2010, Aleric Inglewood.
*
@@ -34,11 +34,15 @@
* of subpools by threads other than the parent pool owner.
*/
#ifndef AIAPRPOOL_H
#define AIAPRPOOL_H
#ifndef LL_LLAPRPOOL_H
#define LL_LLAPRPOOL_H
#ifdef LL_WINDOWS
#pragma warning(push)
#pragma warning(disable:4996)
#include <winsock2.h>
#include <ws2tcpip.h> // Needed before including apr_portable.h
#pragma warning(pop)
#endif
#include "apr_portable.h"
@@ -53,27 +57,27 @@ extern void ll_init_apr();
* Usage of this class should be restricted to passing it to libapr-1 function calls that need it.
*
*/
class LL_COMMON_API AIAPRPool
class LL_COMMON_API LLAPRPool
{
protected:
apr_pool_t* mPool; //!< Pointer to the underlaying pool. NULL if not initialized.
AIAPRPool* mParent; //!< Pointer to the parent pool, if any. Only valid when mPool is non-zero.
LLAPRPool* mParent; //!< Pointer to the parent pool, if any. Only valid when mPool is non-zero.
apr_os_thread_t mOwner; //!< The thread that owns this memory pool. Only valid when mPool is non-zero.
public:
//! Construct an uninitialized (destructed) pool.
AIAPRPool(void) : mPool(NULL) { }
LLAPRPool(void) : mPool(NULL) { }
//! Construct a subpool from an existing pool.
// This is not a copy-constructor, this class doesn't have one!
AIAPRPool(AIAPRPool& parent) : mPool(NULL) { create(parent); }
LLAPRPool(LLAPRPool& parent) : mPool(NULL) { create(parent); }
//! Destruct the memory pool (free all of it's subpools and allocated memory).
~AIAPRPool() { destroy(); }
~LLAPRPool() { destroy(); }
protected:
// Create a pool that is allocated from the Operating System. Only used by AIAPRRootPool.
AIAPRPool(int) : mPool(NULL), mParent(NULL), mOwner(apr_os_thread_current())
// Create a pool that is allocated from the Operating System. Only used by LLAPRRootPool.
LLAPRPool(int) : mPool(NULL), mParent(NULL), mOwner(apr_os_thread_current())
{
apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, NULL);
llassert_always(apr_pool_create_status == APR_SUCCESS);
@@ -84,15 +88,15 @@ protected:
public:
//! Create a subpool from parent. May only be called for an uninitialized/destroyed pool.
// The default parameter causes the root pool of the current thread to be used.
void create(AIAPRPool& parent = *static_cast<AIAPRPool*>(NULL));
void create(LLAPRPool& parent = *static_cast<LLAPRPool*>(NULL));
//! Destroy the (sub)pool, if any.
void destroy(void);
// Use some safebool idiom (http://www.artima.com/cppsource/safebool.html) rather than operator bool.
typedef apr_pool_t* const AIAPRPool::* const bool_type;
//! Return true if the pool is initialized.
operator bool_type() const { return mPool ? &AIAPRPool::mPool : 0; }
typedef LLAPRPool* const LLAPRPool::* const bool_type;
/// Return true if the pool is initialized.
operator bool_type() const { return mPool ? &LLAPRPool::mParent : 0; }
// Painful, but we have to either provide access to this, or wrap
// every APR function call that needs a apr_pool_t* to be passed.
@@ -133,7 +137,7 @@ public:
private:
bool parent_is_being_destructed(void);
static apr_status_t s_plain_cleanup(void* userdata) { return static_cast<AIAPRPool*>(userdata)->plain_cleanup(); }
static apr_status_t s_plain_cleanup(void* userdata) { return static_cast<LLAPRPool*>(userdata)->plain_cleanup(); }
apr_status_t plain_cleanup(void)
{
@@ -148,30 +152,30 @@ private:
}
};
class AIAPRInitialization
class LLAPRInitialization
{
public:
AIAPRInitialization(void);
LLAPRInitialization(void);
};
/**
* @brief Root memory pool (allocates memory from the operating system).
*
* This class should only be used by AIThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase
* This class should only be used by LLThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase
* (and LLMutexRootPool when APR_HAS_THREADS isn't defined).
*/
class LL_COMMON_API AIAPRRootPool : public AIAPRInitialization, public AIAPRPool
class LL_COMMON_API LLAPRRootPool : public LLAPRInitialization, public LLAPRPool
{
private:
friend class AIThreadLocalData;
friend class LLThreadLocalData;
friend class AIThreadSafeSimpleDCRootPool_pbase;
#if !APR_HAS_THREADS
friend class LLMutexRootPool;
#endif
//! Construct a root memory pool.
// Should only be used by AIThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase.
AIAPRRootPool(void);
~AIAPRRootPool();
// Should only be used by LLThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase.
LLAPRRootPool(void);
~LLAPRRootPool();
private:
// Keep track of how many root pools exist and when the last one is destructed.
@@ -179,10 +183,10 @@ private:
static apr_uint32_t volatile sCount;
public:
// Return a global root pool that is independent of AIThreadLocalData.
// Return a global root pool that is independent of LLThreadLocalData.
// Normally you should not use this. Only use for early initialization
// (before main) and deinitialization (after main).
static AIAPRRootPool& get(void);
static LLAPRRootPool& get(void);
#if APR_POOL_DEBUG
void grab_ownership(void)
@@ -194,11 +198,11 @@ public:
#endif
private:
// Used for constructing the Special Global Root Pool (returned by AIAPRRootPool::get).
// Used for constructing the Special Global Root Pool (returned by LLAPRRootPool::get).
// It is the same as the default constructor but omits to increment sCount. As a result,
// we must be sure that at least one other AIAPRRootPool is created before termination
// of the application (which is the case: we create one AIAPRRootPool per thread).
AIAPRRootPool(int) : AIAPRInitialization(), AIAPRPool(0) { }
// we must be sure that at least one other LLAPRRootPool is created before termination
// of the application (which is the case: we create one LLAPRRootPool per thread).
LLAPRRootPool(int) : LLAPRInitialization(), LLAPRPool(0) { }
};
//! Volatile memory pool
@@ -210,29 +214,33 @@ private:
// the system memory to be allocated more efficiently and not
// get scattered through RAM.
//
class LL_COMMON_API AIVolatileAPRPool : protected AIAPRPool
class LL_COMMON_API LLVolatileAPRPool : protected LLAPRPool
{
public:
AIVolatileAPRPool(void) : mNumActiveRef(0), mNumTotalRef(0) { }
LLVolatileAPRPool(void) : mNumActiveRef(0), mNumTotalRef(0) { }
apr_pool_t* getVolatileAPRPool(void)
{
if (!mPool) create();
++mNumActiveRef;
++mNumTotalRef;
return AIAPRPool::operator()();
}
void clearVolatileAPRPool(void);
bool isOld(void) const { return mNumTotalRef > FULL_VOLATILE_APR_POOL; }
bool isUnused() const { return mNumActiveRef == 0; }
private:
friend class LLScopedVolatileAPRPool;
friend class LLAPRFile;
apr_pool_t* getVolatileAPRPool(void) // The use of apr_pool_t is OK here.
{
if (!mPool) create();
++mNumActiveRef;
++mNumTotalRef;
return LLAPRPool::operator()();
}
private:
S32 mNumActiveRef; // Number of active uses of the pool.
S32 mNumTotalRef; // Number of total uses of the pool since last creation.
// Maximum number of references to AIVolatileAPRPool until the pool is recreated.
// Maximum number of references to LLVolatileAPRPool until the pool is recreated.
static S32 const FULL_VOLATILE_APR_POOL = 1024;
};
#endif // AIAPRPOOL_H
#endif // LLAPRPool_H

View File

@@ -35,6 +35,7 @@
#include "llassettype.h"
#include "lldictionary.h"
#include "llmemory.h"
#include "llsingleton.h"
///----------------------------------------------------------------------------
/// Class LLAssetType
@@ -85,26 +86,29 @@ LLAssetDictionary::LLAssetDictionary()
addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", true, false, false));
addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", true, false, true));
addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", true, false, false));
addEntry(LLAssetType::AT_ROOT_CATEGORY, new AssetEntry("ROOT_CATEGORY", "root", "root", false, false, false));
//addEntry(LLAssetType::AT_ROOT_CATEGORY, new AssetEntry("ROOT_CATEGORY", "root", "root", false, false, false));
addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", true, false, false));
addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", true, false, false));
addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", true, false, false));
addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", true, true, true));
addEntry(LLAssetType::AT_TRASH, new AssetEntry("TRASH", "trash", "trash", false, false, false));
addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot", "snapshot", false, false, false));
addEntry(LLAssetType::AT_LOST_AND_FOUND, new AssetEntry("LOST_AND_FOUND", "lstndfnd", "lost and found", false, false, false));
//addEntry(LLAssetType::AT_TRASH, new AssetEntry("TRASH", "trash", "trash", false, false, false));
//addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot", "snapshot", false, false, false));
//addEntry(LLAssetType::AT_LOST_AND_FOUND, new AssetEntry("LOST_AND_FOUND", "lstndfnd", "lost and found", false, false, false));
addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", true, false, false));
addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", true, false, false));
addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", true, false, false));
addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", true, true, true));
addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", true, true, true));
addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", false, false, false));
addEntry(LLAssetType::AT_FAVORITE, new AssetEntry("FAVORITE", "favorite", "", false, false, false));
//addEntry(LLAssetType::AT_FAVORITE, new AssetEntry("FAVORITE", "favorite", "", false, false, false));
addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true));
addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true));
addEntry(LLAssetType::AT_CURRENT_OUTFIT, new AssetEntry("FOLDER_LINK", "current", "current outfit", false, false, false));
addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", false, false, false));
addEntry(LLAssetType::AT_MY_OUTFITS, new AssetEntry("MY_OUTFITS", "my_otfts", "my outfits", false, false, false));
//addEntry(LLAssetType::AT_CURRENT_OUTFIT, new AssetEntry("FOLDER_LINK", "current", "current outfit", false, false, false));
//addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", false, false, false));
//addEntry(LLAssetType::AT_MY_OUTFITS, new AssetEntry("MY_OUTFITS", "my_otfts", "my outfits", false, false, false));
#if MESH_ENABLED
addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false));
#endif //MESH_ENABLED
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false));
};
@@ -206,47 +210,7 @@ LLAssetType::EType LLAssetType::lookupHumanReadable(const std::string& readable_
return AT_NONE;
}
EDragAndDropType LLAssetType::lookupDragAndDropType( EType asset )
{
switch( asset )
{
case AT_TEXTURE: return DAD_TEXTURE;
case AT_SOUND: return DAD_SOUND;
case AT_CALLINGCARD: return DAD_CALLINGCARD;
case AT_LANDMARK: return DAD_LANDMARK;
case AT_SCRIPT: return DAD_NONE;
case AT_CLOTHING: return DAD_CLOTHING;
case AT_OBJECT: return DAD_OBJECT;
case AT_NOTECARD: return DAD_NOTECARD;
case AT_CATEGORY: return DAD_CATEGORY;
case AT_ROOT_CATEGORY: return DAD_ROOT_CATEGORY;
case AT_LSL_TEXT: return DAD_SCRIPT;
case AT_BODYPART: return DAD_BODYPART;
case AT_ANIMATION: return DAD_ANIMATION;
case AT_GESTURE: return DAD_GESTURE;
case AT_FAVORITE: return DAD_CATEGORY;
case AT_LINK: return DAD_LINK;
case AT_LINK_FOLDER: return DAD_LINK;
case AT_CURRENT_OUTFIT: return DAD_LINK;
case AT_OUTFIT: return DAD_LINK;
case AT_MY_OUTFITS: return DAD_CATEGORY;
default: return DAD_NONE;
};
}
// static. Generate a good default description
void LLAssetType::generateDescriptionFor(LLAssetType::EType type,
std::string& desc)
{
const S32 BUF_SIZE = 30;
char time_str[BUF_SIZE]; /* Flawfinder: ignore */
time_t now;
time(&now);
memset(time_str, '\0', BUF_SIZE);
strftime(time_str, BUF_SIZE - 1, "%Y-%m-%d %H:%M:%S ", localtime(&now));
desc.assign(time_str);
desc.append(LLAssetType::lookupHumanReadable(type));
}
//NOTE: LLAssetType::lookupDragAndDropType & LLAssetType::generateDescriptionFor moved to newview/llviewerassettype.h
// static
bool LLAssetType::lookupCanLink(EType asset_type)

View File

@@ -84,7 +84,7 @@ public:
// A root category is a user's root inventory category. We
// decided to expose it visually, so it seems logical to fold
// it into the asset types.
AT_ROOT_CATEGORY = 9,
//AT_ROOT_CATEGORY = 9,
// The LSL is the brand spanking new scripting language. We've
// split it into a text and bytecode representation.
@@ -101,15 +101,15 @@ public:
// This asset type is meant to only be used as a marker for a
// category preferred type. Using this, we can throw things in
// the trash before completely deleting.
AT_TRASH = 14,
//AT_TRASH = 14,
// This is a marker for a folder meant for snapshots. No
// actual assets will be snapshots, though if there were, you
// could interpret them as textures.
AT_SNAPSHOT_CATEGORY = 15,
//AT_SNAPSHOT_CATEGORY = 15,
// This is used to stuff lost&found items into
AT_LOST_AND_FOUND = 16,
//AT_LOST_AND_FOUND = 16,
// uncompressed sound
AT_SOUND_WAV = 17,
@@ -131,20 +131,26 @@ public:
// simstate file
AT_SIMSTATE = 22,
AT_FAVORITE = 23,
//AT_FAVORITE = 23,
// Inventory symbolic link
AT_LINK = 24,
// Inventory folder link
AT_LINK_FOLDER = 25,
//AT_CURRENT_OUTFIT = 46,
AT_CURRENT_OUTFIT = 46,
//AT_OUTFIT = 47,
AT_OUTFIT = 47,
//AT_MY_OUTFITS = 48,
AT_MY_OUTFITS = 48,
#if MESH_ENABLED
AT_MESH = 49,
// Mesh data in our proprietary SLM format
AT_COUNT = 50,
#endif //MESH_ENABLED
// +*********************************************+
// | TO ADD AN ELEMENT TO THIS ENUM: |
// +*********************************************+
@@ -154,8 +160,10 @@ public:
// | 4. ADD TO LLAssetType::mAssetTypeHumanNames |
// +*********************************************+
AT_COUNT = 49,
//AT_COUNT = 49,
#if !MESH_ENABLED
AT_COUNT = 26,
#endif //!MESH_ENABLED
AT_NONE = -1
};
@@ -169,12 +177,7 @@ public:
static EType lookupHumanReadable(const std::string& readable_name);
static const char* lookupHumanReadable(EType asset_type);
static EDragAndDropType lookupDragAndDropType( EType );
// Generate a good default description. You may want to add a verb
// or agent name after this depending on your application.
static void generateDescriptionFor(LLAssetType::EType type,
std::string& desc);
//NOTE: LLAssetType::lookupDragAndDropType & LLAssetType::generateDescriptionFor moved to newview/llviewerassettype.h
static EType getType(const std::string& desc_name);
static const std::string& getDesc(EType asset_type);

View File

@@ -25,10 +25,6 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
/*
Ported to Phoenix by Wolfspirit Magic.
*/
#include "linden_common.h"
#include "llavatarname.h"
@@ -52,7 +48,7 @@ LLAvatarName::LLAvatarName()
mLegacyFirstName(),
mLegacyLastName(),
mIsDisplayNameDefault(false),
mIsDummy(false),
mIsTemporaryName(false),
mExpires(F64_MAX),
mNextUpdate(0.0)
{ }
@@ -94,21 +90,16 @@ void LLAvatarName::fromLLSD(const LLSD& sd)
std::string LLAvatarName::getCompleteName(bool linefeed) const
{
std::string name;
if (!mUsername.empty())
if (mUsername.empty() || mIsDisplayNameDefault)
// If the display name feature is off
// OR this particular display name is defaulted (i.e. based on user name),
// then display only the easier to read instance of the person's name.
{
if (linefeed)
{
name = mDisplayName + "\n(" + mUsername + ")";
}
else
{
name = mDisplayName + " (" + mUsername + ")";
}
name = mDisplayName;
}
else
{
// ...display names are off, legacy name is in mDisplayName
name = mDisplayName;
name = mDisplayName + (linefeed ? "\n(" : "(") + mUsername + ")";
}
return name;
}

View File

@@ -79,7 +79,7 @@ public:
// Under error conditions, we may insert "dummy" records with
// names like "???" into caches as placeholders. These can be
// shown in UI, but are not serialized.
bool mIsDummy;
bool mIsTemporaryName;
// Names can change, so need to keep track of when name was
// last checked.

View File

@@ -56,7 +56,8 @@ typedef enum e_chat_type
CHAT_TYPE_STOP = 5,
CHAT_TYPE_DEBUG_MSG = 6,
CHAT_TYPE_REGION = 7,
CHAT_TYPE_OWNER = 8
CHAT_TYPE_OWNER = 8,
CHAT_TYPE_DIRECT = 9 // From llRegionSayTo()
} EChatType;
typedef enum e_chat_audible_level

View File

@@ -42,5 +42,6 @@ const U8 CLICK_ACTION_PAY = 3;
const U8 CLICK_ACTION_OPEN = 4;
const U8 CLICK_ACTION_PLAY = 5;
const U8 CLICK_ACTION_OPEN_MEDIA = 6;
const U8 CLICK_ACTION_ZOOM = 7;
// DO NOT CHANGE THE SEQUENCE OF THIS LIST!!
#endif

View File

@@ -38,6 +38,8 @@
#include <iosfwd>
#include <string>
#include "llpreprocessor.h"
#include "stdtypes.h"
/**

View File

@@ -56,9 +56,8 @@
#include "llsdserialize.h"
#include "llstl.h"
#include "lltimer.h"
#include "aithreadsafe.h"
extern apr_thread_mutex_t* gCallStacksLogMutexp;
#include "aithreadsafe.h"
namespace {
#if !LL_WINDOWS
@@ -881,8 +880,8 @@ You get:
*/
apr_thread_mutex_t* gLogMutexp;
apr_thread_mutex_t* gCallStacksLogMutexp;
extern apr_thread_mutex_t* gLogMutexp;
extern apr_thread_mutex_t* gCallStacksLogMutexp;
namespace {
bool checkLevelMap(const LevelMap& map, const std::string& key,

View File

@@ -44,63 +44,40 @@
//
//////////////////////////////////////////////////////////////////////////////
//std::list<LLEventTimer*> LLEventTimer::sActiveList;
LLEventTimer::LLEventTimer(F32 period)
: mEventTimer()
{
mPeriod = period;
//sActiveList.push_back(this);
}
LLEventTimer::LLEventTimer(const LLDate& time)
: mEventTimer()
{
mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch());
//sActiveList.push_back(this);
}
LLEventTimer::~LLEventTimer()
LLEventTimer::~LLEventTimer()
{
//sActiveList.remove(this);
}
//static
void LLEventTimer::updateClass()
{
std::list<LLEventTimer*> completed_timers;
/*{
for (std::list<LLEventTimer*>::iterator iter = sActiveList.begin(); iter != sActiveList.end(); )
{
LLEventTimer* timer = *iter++;
F32 et = timer->mEventTimer.getElapsedTimeF32();
if (timer->mEventTimer.getStarted() && et > timer->mPeriod) {
timer->mEventTimer.reset();
if ( timer->tick() )
{
completed_timers.push_back( timer );
}
}
}
}*/
for (instance_iter iter = beginInstances(); iter != endInstances(); )
{
LLInstanceTrackerScopedGuard guard;
for (instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); )
{
LLEventTimer& timer = *iter++;
F32 et = timer.mEventTimer.getElapsedTimeF32();
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
timer.mEventTimer.reset();
if ( timer.tick() )
{
completed_timers.push_back( &timer );
}
LLEventTimer& timer = *iter++;
F32 et = timer.mEventTimer.getElapsedTimeF32();
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
timer.mEventTimer.reset();
if ( timer.tick() )
{
completed_timers.push_back( &timer );
}
}
}
if ( completed_timers.size() > 0 )
{
for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();

View File

@@ -56,11 +56,6 @@ public:
protected:
LLTimer mEventTimer;
F32 mPeriod;
//private:
//list of active timers
// static std::list<LLEventTimer*> sActiveList; // TODO should this be a vector
};
#endif //LL_EVENTTIMER_H

View File

@@ -72,7 +72,12 @@ public:
FTM_UPDATE_GRASS,
FTM_UPDATE_TREE,
FTM_UPDATE_AVATAR,
#if MESH_ENABLED
FTM_UPDATE_RIGGED_VOLUME,
FTM_SKIN_RIGGED,
FTM_RIGGED_OCTREE,
#endif //MESH_ENABLED
// common render components
FTM_SHADOW_GEOMETRY,
FTM_SHADOW_RENDER,
@@ -131,6 +136,12 @@ public:
FTM_STATESORT,
FTM_STATESORT_DRAWABLE,
FTM_STATESORT_POSTSORT,
#if MESH_ENABLED
FTM_MESH_UPDATE,
FTM_MESH_LOCK1,
FTM_MESH_LOCK2,
FTM_LOAD_MESH_LOD,
#endif //MESH_ENABLED
FTM_REBUILD_VBO,
FTM_REBUILD_VOLUME_VB,
FTM_REBUILD_BRIDGE_VB,

View File

@@ -0,0 +1,175 @@
/**
* @file llfoldertype.cpp
* @brief Implementatino of LLFolderType functionality.
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
*/
#include "linden_common.h"
#include "llfoldertype.h"
#include "lldictionary.h"
#include "llmemory.h"
#include "llsingleton.h"
///----------------------------------------------------------------------------
/// Class LLFolderType
///----------------------------------------------------------------------------
struct FolderEntry : public LLDictionaryEntry
{
FolderEntry(const std::string &type_name, // 8 character limit!
bool is_protected) // can the viewer change categories of this type?
:
LLDictionaryEntry(type_name),
mIsProtected(is_protected)
{
llassert(type_name.length() <= 8);
}
const bool mIsProtected;
};
class LLFolderDictionary : public LLSingleton<LLFolderDictionary>,
public LLDictionary<LLFolderType::EType, FolderEntry>
{
public:
LLFolderDictionary();
protected:
virtual LLFolderType::EType notFound() const
{
return LLFolderType::FT_NONE;
}
};
LLFolderDictionary::LLFolderDictionary()
{
// TYPE NAME PROTECTED
// |-----------|---------|
addEntry(LLFolderType::FT_TEXTURE, new FolderEntry("texture", TRUE));
addEntry(LLFolderType::FT_SOUND, new FolderEntry("sound", TRUE));
addEntry(LLFolderType::FT_CALLINGCARD, new FolderEntry("callcard", TRUE));
addEntry(LLFolderType::FT_LANDMARK, new FolderEntry("landmark", TRUE));
addEntry(LLFolderType::FT_CLOTHING, new FolderEntry("clothing", TRUE));
addEntry(LLFolderType::FT_OBJECT, new FolderEntry("object", TRUE));
addEntry(LLFolderType::FT_NOTECARD, new FolderEntry("notecard", TRUE));
addEntry(LLFolderType::FT_ROOT_INVENTORY, new FolderEntry("root_inv", TRUE));
addEntry(LLFolderType::FT_LSL_TEXT, new FolderEntry("lsltext", TRUE));
addEntry(LLFolderType::FT_BODYPART, new FolderEntry("bodypart", TRUE));
addEntry(LLFolderType::FT_TRASH, new FolderEntry("trash", TRUE));
addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new FolderEntry("snapshot", TRUE));
addEntry(LLFolderType::FT_LOST_AND_FOUND, new FolderEntry("lstndfnd", TRUE));
addEntry(LLFolderType::FT_ANIMATION, new FolderEntry("animatn", TRUE));
addEntry(LLFolderType::FT_GESTURE, new FolderEntry("gesture", TRUE));
addEntry(LLFolderType::FT_FAVORITE, new FolderEntry("favorite", TRUE));
for (S32 ensemble_num = S32(LLFolderType::FT_ENSEMBLE_START); ensemble_num <= S32(LLFolderType::FT_ENSEMBLE_END); ensemble_num++)
{
addEntry(LLFolderType::EType(ensemble_num), new FolderEntry("ensemble", FALSE));
}
addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE));
addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE));
addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE));
addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE));
addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE));
addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", TRUE));
addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE));
addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE));
};
// static
LLFolderType::EType LLFolderType::lookup(const std::string& name)
{
return LLFolderDictionary::getInstance()->lookup(name);
}
// static
const std::string &LLFolderType::lookup(LLFolderType::EType folder_type)
{
const FolderEntry *entry = LLFolderDictionary::getInstance()->lookup(folder_type);
if (entry)
{
return entry->mName;
}
else
{
return badLookup();
}
}
// static
// Only ensembles and plain folders aren't protected. "Protected" means
// you can't change certain properties such as their type.
bool LLFolderType::lookupIsProtectedType(EType folder_type)
{
const LLFolderDictionary *dict = LLFolderDictionary::getInstance();
const FolderEntry *entry = dict->lookup(folder_type);
if (entry)
{
return entry->mIsProtected;
}
return true;
}
// static
bool LLFolderType::lookupIsEnsembleType(EType folder_type)
{
return (folder_type >= FT_ENSEMBLE_START &&
folder_type <= FT_ENSEMBLE_END);
}
// static
LLAssetType::EType LLFolderType::folderTypeToAssetType(LLFolderType::EType folder_type)
{
if (LLAssetType::lookup(LLAssetType::EType(folder_type)) == LLAssetType::badLookup())
{
llwarns << "Converting to unknown asset type " << folder_type << llendl;
}
return (LLAssetType::EType)folder_type;
}
// static
LLFolderType::EType LLFolderType::assetTypeToFolderType(LLAssetType::EType asset_type)
{
if (LLFolderType::lookup(LLFolderType::EType(asset_type)) == LLFolderType::badLookup())
{
llwarns << "Converting to unknown folder type " << asset_type << llendl;
}
return (LLFolderType::EType)asset_type;
}
// static
const std::string &LLFolderType::badLookup()
{
static const std::string sBadLookup = "llfoldertype_bad_lookup";
return sBadLookup;
}

View File

@@ -0,0 +1,118 @@
/**
* @file llfoldertype.h
* @brief Declaration of LLFolderType.
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2010, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*
*/
#ifndef LL_LLFOLDERTYPE_H
#define LL_LLFOLDERTYPE_H
#include <string>
#include "llassettype.h"
// This class handles folder types (similar to assettype, except for folders)
// and operations on those.
class LL_COMMON_API LLFolderType
{
public:
// ! BACKWARDS COMPATIBILITY ! Folder type enums must match asset type enums.
enum EType
{
FT_TEXTURE = 0,
FT_SOUND = 1,
FT_CALLINGCARD = 2,
FT_LANDMARK = 3,
FT_CLOTHING = 5,
FT_OBJECT = 6,
FT_NOTECARD = 7,
FT_ROOT_INVENTORY = 8,
// We'd really like to change this to 9 since AT_CATEGORY is 8,
// but "My Inventory" has been type 8 for a long time.
FT_LSL_TEXT = 10,
FT_BODYPART = 13,
FT_TRASH = 14,
FT_SNAPSHOT_CATEGORY = 15,
FT_LOST_AND_FOUND = 16,
FT_ANIMATION = 20,
FT_GESTURE = 21,
FT_FAVORITE = 23,
FT_ENSEMBLE_START = 26,
FT_ENSEMBLE_END = 45,
// This range is reserved for special clothing folder types.
FT_CURRENT_OUTFIT = 46,
FT_OUTFIT = 47,
FT_MY_OUTFITS = 48,
FT_MESH = 49,
FT_INBOX = 50,
FT_OUTBOX = 51,
FT_BASIC_ROOT = 52,
FT_COUNT,
FT_NONE = -1
};
static EType lookup(const std::string& type_name);
static const std::string& lookup(EType folder_type);
static bool lookupIsProtectedType(EType folder_type);
static bool lookupIsEnsembleType(EType folder_type);
static LLAssetType::EType folderTypeToAssetType(LLFolderType::EType folder_type);
static LLFolderType::EType assetTypeToFolderType(LLAssetType::EType asset_type);
static const std::string& badLookup(); // error string when a lookup fails
protected:
LLFolderType() {}
~LLFolderType() {}
};
#endif // LL_LLFOLDERTYPE_H

View File

@@ -35,13 +35,15 @@
//static
void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)
{
static std::map<std::string, void *> instances;
typedef std::map<std::string, void *> InstancesMap;
static InstancesMap instances;
std::string k = info.name();
if(instances.find(k) == instances.end())
{
instances[k] = NULL;
}
return instances[k];
// std::map::insert() is just what we want here. You attempt to insert a
// (key, value) pair. If the specified key doesn't yet exist, it inserts
// the pair and returns a std::pair of (iterator, true). If the specified
// key DOES exist, insert() simply returns (iterator, false). One lookup
// handles both cases.
return instances.insert(InstancesMap::value_type(info.name(),
InstancesMap::mapped_type()))
.first->second;
}

View File

@@ -36,6 +36,7 @@
#define LL_LLINSTANCETRACKER_H
#include <map>
#include <typeinfo>
#include "string_table.h"
#include <boost/utility.hpp>
@@ -48,7 +49,32 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
{
protected:
static void * & getInstances(std::type_info const & info);
/// Find or create a STATICDATA instance for the specified TRACKED class.
/// STATICDATA must be default-constructible.
template<typename STATICDATA, class TRACKED>
static STATICDATA& getStatic()
{
void *& instances = getInstances(typeid(TRACKED));
if (! instances)
{
instances = new STATICDATA;
}
return *static_cast<STATICDATA*>(instances);
}
/// It's not essential to derive your STATICDATA (for use with
/// getStatic()) from StaticBase; it's just that both known
/// implementations do.
struct StaticBase
{
StaticBase():
sIterationNestDepth(0)
{}
S32 sIterationNestDepth;
};
};
/// This mix-in class adds support for tracking all instances of the specified class parameter T
/// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup
/// If KEY is not provided, then instances are stored in a simple set
@@ -56,15 +82,89 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
template<typename T, typename KEY = T*>
class LLInstanceTracker : public LLInstanceTrackerBase
{
typedef typename std::map<KEY, T*> InstanceMap;
typedef LLInstanceTracker<T, KEY> MyT;
typedef boost::function<const KEY&(typename InstanceMap::value_type&)> KeyGetter;
typedef boost::function<T*(typename InstanceMap::value_type&)> InstancePtrGetter;
typedef typename std::map<KEY, T*> InstanceMap;
struct StaticData: public StaticBase
{
InstanceMap sMap;
};
static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
static InstanceMap& getMap_() { return getStatic().sMap; }
public:
/// Dereferencing key_iter gives you a const KEY&
typedef boost::transform_iterator<KeyGetter, typename InstanceMap::iterator> key_iter;
/// Dereferencing instance_iter gives you a T&
typedef boost::indirect_iterator< boost::transform_iterator<InstancePtrGetter, typename InstanceMap::iterator> > instance_iter;
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
{
public:
typedef boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> super_t;
instance_iter(const typename InstanceMap::iterator& it)
: mIterator(it)
{
++getStatic().sIterationNestDepth;
}
~instance_iter()
{
--getStatic().sIterationNestDepth;
}
private:
friend class boost::iterator_core_access;
void increment() { mIterator++; }
bool equal(instance_iter const& other) const
{
return mIterator == other.mIterator;
}
T& dereference() const
{
return *(mIterator->second);
}
typename InstanceMap::iterator mIterator;
};
class key_iter : public boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag>
{
public:
typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t;
key_iter(typename InstanceMap::iterator it)
: mIterator(it)
{
++getStatic().sIterationNestDepth;
}
key_iter(const key_iter& other)
: mIterator(other.mIterator)
{
++getStatic().sIterationNestDepth;
}
~key_iter()
{
--getStatic().sIterationNestDepth;
}
private:
friend class boost::iterator_core_access;
void increment() { mIterator++; }
bool equal(key_iter const& other) const
{
return mIterator == other.mIterator;
}
KEY& dereference() const
{
return const_cast<KEY&>(mIterator->first);
}
typename InstanceMap::iterator mIterator;
};
static T* getInstance(const KEY& k)
{
@@ -72,57 +172,51 @@ public:
return (found == getMap_().end()) ? NULL : found->second;
}
static instance_iter beginInstances()
{
return instance_iter(getMap_().begin());
}
static instance_iter endInstances()
{
return instance_iter(getMap_().end());
}
static S32 instanceCount() { return getMap_().size(); }
static key_iter beginKeys()
{
return boost::make_transform_iterator(getMap_().begin(),
boost::bind(&InstanceMap::value_type::first, _1));
return key_iter(getMap_().begin());
}
static key_iter endKeys()
{
return boost::make_transform_iterator(getMap_().end(),
boost::bind(&InstanceMap::value_type::first, _1));
return key_iter(getMap_().end());
}
static instance_iter beginInstances()
{
return instance_iter(boost::make_transform_iterator(getMap_().begin(),
boost::bind(&InstanceMap::value_type::second, _1)));
}
static instance_iter endInstances()
{
return instance_iter(boost::make_transform_iterator(getMap_().end(),
boost::bind(&InstanceMap::value_type::second, _1)));
}
static S32 instanceCount() { return getMap_().size(); }
protected:
LLInstanceTracker(KEY key) { add_(key); }
virtual ~LLInstanceTracker() { remove_(); }
virtual ~LLInstanceTracker()
{
// it's unsafe to delete instances of this type while all instances are being iterated over.
llassert_always(getStatic().sIterationNestDepth == 0);
remove_();
}
virtual void setKey(KEY key) { remove_(); add_(key); }
virtual const KEY& getKey() const { return mKey; }
virtual const KEY& getKey() const { return mInstanceKey; }
private:
void add_(KEY key)
{
mKey = key;
mInstanceKey = key;
getMap_()[key] = static_cast<T*>(this);
}
void remove_()
{
getMap_().erase(mKey);
getMap_().erase(mInstanceKey);
}
static InstanceMap& getMap_()
{
void * & instances = getInstances(typeid(MyT));
if (! instances)
{
instances = new InstanceMap;
}
return * static_cast<InstanceMap*>(instances);
}
private:
KEY mKey;
KEY mInstanceKey;
};
/// explicit specialization for default case where KEY is T*
@@ -130,73 +224,78 @@ private:
template<typename T>
class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
{
typedef typename std::set<T*> InstanceSet;
typedef LLInstanceTracker<T, T*> MyT;
typedef typename std::set<T*> InstanceSet;
struct StaticData: public StaticBase
{
InstanceSet sSet;
};
static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
static InstanceSet& getSet_() { return getStatic().sSet; }
public:
/// Dereferencing key_iter gives you a T* (since T* is the key)
typedef typename InstanceSet::iterator key_iter;
/// Dereferencing instance_iter gives you a T&
typedef boost::indirect_iterator<key_iter> instance_iter;
/// for completeness of analogy with the generic implementation
static T* getInstance(T* k) { return k; }
static S32 instanceCount() { return getSet_().size(); }
// Instantiate this to get access to iterators for this type. It's a 'guard' in the sense
// that it treats deletes of this type as errors as long as there is an instance of
// this class alive in scope somewhere (i.e. deleting while iterating is bad).
class LLInstanceTrackerScopedGuard
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
{
public:
LLInstanceTrackerScopedGuard()
instance_iter(const typename InstanceSet::iterator& it)
: mIterator(it)
{
++sIterationNestDepth;
++getStatic().sIterationNestDepth;
}
~LLInstanceTrackerScopedGuard()
instance_iter(const instance_iter& other)
: mIterator(other.mIterator)
{
--sIterationNestDepth;
++getStatic().sIterationNestDepth;
}
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
static instance_iter endInstances() { return instance_iter(getSet_().end()); }
static key_iter beginKeys() { return getSet_().begin(); }
static key_iter endKeys() { return getSet_().end(); }
~instance_iter()
{
--getStatic().sIterationNestDepth;
}
private:
friend class boost::iterator_core_access;
void increment() { mIterator++; }
bool equal(instance_iter const& other) const
{
return mIterator == other.mIterator;
}
T& dereference() const
{
return **mIterator;
}
typename InstanceSet::iterator mIterator;
};
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
static instance_iter endInstances() { return instance_iter(getSet_().end()); }
protected:
LLInstanceTracker()
{
// it's safe but unpredictable to create instances of this type while all instances are being iterated over. I hate unpredictable. This assert will probably be turned on early in the next development cycle.
//llassert(sIterationNestDepth == 0);
getSet_().insert(static_cast<T*>(this));
}
virtual ~LLInstanceTracker()
{
// it's unsafe to delete instances of this type while all instances are being iterated over.
llassert(sIterationNestDepth == 0);
llassert_always(getStatic().sIterationNestDepth == 0);
getSet_().erase(static_cast<T*>(this));
}
LLInstanceTracker(const LLInstanceTracker& other)
{
//llassert(sIterationNestDepth == 0);
getSet_().insert(static_cast<T*>(this));
}
static InstanceSet& getSet_()
{
void * & instances = getInstances(typeid(MyT));
if (! instances)
{
instances = new InstanceSet;
}
return * static_cast<InstanceSet *>(instances);
}
static S32 sIterationNestDepth;
};
template <typename T> S32 LLInstanceTracker<T, T*>::sIterationNestDepth = 0;
#endif

View File

@@ -118,6 +118,62 @@ public:
THROTTLE_BLOCKED, // rate exceed, block key
};
F64 getActionCount(const T& id)
{
U64 now = 0;
if ( mIsRealtime )
{
now = LLKeyThrottleImpl<T>::getTime();
}
else
{
now = LLKeyThrottleImpl<T>::getFrame();
}
if (now >= (m.startTime + m.intervalLength))
{
if (now < (m.startTime + 2 * m.intervalLength))
{
// prune old data
delete m.prevMap;
m.prevMap = m.currMap;
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
m.startTime += m.intervalLength;
}
else
{
// lots of time has passed, all data is stale
delete m.prevMap;
delete m.currMap;
m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
m.startTime = now;
}
}
U32 prevCount = 0;
typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);
if (prev != m.prevMap->end())
{
prevCount = prev->second.count;
}
typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
// curr.count is the number of keys in
// this current 'time slice' from the beginning of it until now
// prevCount is the number of keys in the previous
// time slice scaled to be one full time slice back from the current
// (now) time.
// compute current, windowed rate
F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength);
F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent);
return averageCount;
}
// call each time the key wants use
State noteAction(const T& id, S32 weight = 1)
{

View File

@@ -48,6 +48,7 @@ const U32 AGENT_TYPING = 0x0200;
const U32 AGENT_CROUCHING = 0x0400;
const U32 AGENT_BUSY = 0x0800;
const U32 AGENT_ALWAYS_RUN = 0x1000;
const U32 AGENT_AUTOPILOT = 0x2000;
const S32 LSL_REMOTE_DATA_CHANNEL = 1;
const S32 LSL_REMOTE_DATA_REQUEST = 2;
@@ -184,6 +185,10 @@ const S32 OBJECT_VELOCITY = 5;
const S32 OBJECT_OWNER = 6;
const S32 OBJECT_GROUP = 7;
const S32 OBJECT_CREATOR = 8;
const S32 OBJECT_RUNNING_SCRIPT_COUNT = 9;
const S32 OBJECT_TOTAL_SCRIPT_COUNT = 10;
const S32 OBJECT_SCRIPT_MEMORY = 11;
const S32 OBJECT_SCRIPT_TIME = 12;
// changed() event flags
const U32 CHANGED_NONE = 0x0;
@@ -198,5 +203,17 @@ const U32 CHANGED_OWNER = 0x80;
const U32 CHANGED_REGION = 0x100;
const U32 CHANGED_TELEPORT = 0x200;
const U32 CHANGED_REGION_START = 0x400;
const U32 CHANGED_MEDIA = 0x800;
// Possible error results
const U32 LSL_STATUS_OK = 0;
const U32 LSL_STATUS_MALFORMED_PARAMS = 1000;
const U32 LSL_STATUS_TYPE_MISMATCH = 1001;
const U32 LSL_STATUS_BOUNDS_ERROR = 1002;
const U32 LSL_STATUS_NOT_FOUND = 1003;
const U32 LSL_STATUS_NOT_SUPPORTED = 1004;
const U32 LSL_STATUS_INTERNAL_ERROR = 1999;
// Start per-function errors below, starting at 2000:
const U32 LSL_STATUS_WHITELIST_FAILED = 2001;
#endif

View File

@@ -276,37 +276,12 @@ void operator delete[] (void *p)
#endif
//----------------------------------------------------------------------------
LLRefCount::LLRefCount() :
mRef(0)
{
}
LLRefCount::LLRefCount(const LLRefCount& other)
: mRef(0)
{
}
LLRefCount::~LLRefCount()
{
if (mRef != 0)
{
llerrs << "deleting non-zero reference" << llendl;
}
}
LLRefCount& LLRefCount::operator=(const LLRefCount&)
{
// do nothing, since ref count is specific to *this* reference
return *this;
}
//----------------------------------------------------------------------------
#if defined(LL_WINDOWS)
U64 getCurrentRSS()
U64 LLMemory::getCurrentRSS()
{
HANDLE self = GetCurrentProcess();
PROCESS_MEMORY_COUNTERS counters;
@@ -320,6 +295,20 @@ U64 getCurrentRSS()
return counters.WorkingSetSize;
}
//static
U32 LLMemory::getWorkingSetSize()
{
PROCESS_MEMORY_COUNTERS pmc ;
U32 ret = 0 ;
if (GetProcessMemoryInfo( GetCurrentProcess(), &pmc, sizeof(pmc)) )
{
ret = pmc.WorkingSetSize ;
}
return ret ;
}
#elif defined(LL_DARWIN)
/*
@@ -344,7 +333,7 @@ U64 getCurrentRSS()
// }
// }
U64 getCurrentRSS()
U64 LLMemory::getCurrentRSS()
{
U64 residentSize = 0;
task_basic_info_data_t basicInfo;
@@ -366,9 +355,14 @@ U64 getCurrentRSS()
return residentSize;
}
U32 LLMemory::getWorkingSetSize()
{
return 0 ;
}
#elif defined(LL_LINUX)
U64 getCurrentRSS()
U64 LLMemory::getCurrentRSS()
{
static const char statPath[] = "/proc/self/stat";
LLFILE *fp = LLFile::fopen(statPath, "r");
@@ -400,6 +394,10 @@ bail:
return rss;
}
U32 LLMemory::getWorkingSetSize()
{
return 0 ;
}
#elif LL_SOLARIS
#include <sys/types.h>
#include <sys/stat.h>
@@ -407,7 +405,7 @@ bail:
#define _STRUCTURED_PROC 1
#include <sys/procfs.h>
U64 getCurrentRSS()
U64 LLMemory::getCurrentRSS()
{
char path [LL_MAX_PATH]; /* Flawfinder: ignore */
@@ -428,11 +426,22 @@ U64 getCurrentRSS()
return((U64)proc_psinfo.pr_rssize * 1024);
}
U32 LLMemory::getWorkingSetSize()
{
return 0 ;
}
#else
U64 getCurrentRSS()
U64 LLMemory::getCurrentRSS()
{
return 0;
}
U32 LLMemory::getWorkingSetSize()
{
return 0 ;
}
#endif

View File

@@ -29,453 +29,115 @@
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_MEMORY_H
#define LL_MEMORY_H
#ifndef LLMEMORY_H
#define LLMEMORY_H
#include <new>
#include <cstdlib>
#if !LL_WINDOWS
#include <stdint.h> // uintptr_t
#endif
#include "llerror.h"
extern S32 gTotalDAlloc;
extern S32 gTotalDAUse;
extern S32 gDACount;
const U32 LLREFCOUNT_SENTINEL_VALUE = 0xAAAAAAAA;
//----------------------------------------------------------------------------
#if LL_DEBUG
inline void* ll_aligned_malloc( size_t size, int align )
{
void* mem = malloc( size + (align - 1) + sizeof(void*) );
char* aligned = ((char*)mem) + sizeof(void*);
aligned += align - ((uintptr_t)aligned & (align - 1));
((void**)aligned)[-1] = mem;
return aligned;
}
inline void ll_aligned_free( void* ptr )
{
free( ((void**)ptr)[-1] );
}
inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
{
#if defined(LL_WINDOWS)
return _mm_malloc(size, 16);
#elif defined(LL_DARWIN)
return malloc(size); // default osx malloc is 16 byte aligned.
#else
void *rtn;
if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size)))
return rtn;
else // bad alignment requested, or out of memory
return NULL;
#endif
}
inline void ll_aligned_free_16(void *p)
{
#if defined(LL_WINDOWS)
_mm_free(p);
#elif defined(LL_DARWIN)
return free(p);
#else
free(p); // posix_memalign() is compatible with heap deallocator
#endif
}
inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
{
#if defined(LL_WINDOWS)
return _mm_malloc(size, 32);
#elif defined(LL_DARWIN)
return ll_aligned_malloc( size, 32 );
#else
void *rtn;
if (LL_LIKELY(0 == posix_memalign(&rtn, 32, size)))
return rtn;
else // bad alignment requested, or out of memory
return NULL;
#endif
}
inline void ll_aligned_free_32(void *p)
{
#if defined(LL_WINDOWS)
_mm_free(p);
#elif defined(LL_DARWIN)
ll_aligned_free( p );
#else
free(p); // posix_memalign() is compatible with heap deallocator
#endif
}
#else // LL_DEBUG
// ll_aligned_foo are noops now that we use tcmalloc everywhere (tcmalloc aligns automatically at appropriate intervals)
#define ll_aligned_malloc( size, align ) malloc(size)
#define ll_aligned_free( ptr ) free(ptr)
#define ll_aligned_malloc_16 malloc
#define ll_aligned_free_16 free
#define ll_aligned_malloc_32 malloc
#define ll_aligned_free_32 free
#endif // LL_DEBUG
class LL_COMMON_API LLMemory
{
public:
static void initClass();
static void cleanupClass();
static void freeReserve();
// Return the resident set size of the current process, in bytes.
// Return value is zero if not known.
static U64 getCurrentRSS();
static U32 getWorkingSetSize();
private:
static char* reserveMem;
};
//----------------------------------------------------------------------------
// RefCount objects should generally only be accessed by way of LLPointer<>'s
// NOTE: LLPointer<LLFoo> x = new LLFoo(); MAY NOT BE THREAD SAFE
// if LLFoo::LLFoo() does anything like put itself in an update queue.
// The queue may get accessed before it gets assigned to x.
// The correct implementation is:
// LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting
// x->instantiate(); // does stuff like place x into an update queue
// see llthread.h for LLThreadSafeRefCount
//----------------------------------------------------------------------------
class LL_COMMON_API LLRefCount
{
protected:
LLRefCount(const LLRefCount&);
private:
LLRefCount&operator=(const LLRefCount&);
protected:
virtual ~LLRefCount(); // use unref()
public:
LLRefCount();
void ref()
{
mRef++;
}
S32 unref()
{
llassert(mRef >= 1);
if (0 == --mRef)
{
delete this;
return 0;
}
return mRef;
}
S32 getNumRefs() const
{
return mRef;
}
private:
S32 mRef;
};
//----------------------------------------------------------------------------
// Note: relies on Type having ref() and unref() methods
template <class Type> class LLPointer
{
public:
LLPointer() :
mPointer(NULL)
{
}
LLPointer(Type* ptr) :
mPointer(ptr)
{
ref();
}
LLPointer(const LLPointer<Type>& ptr) :
mPointer(ptr.mPointer)
{
ref();
}
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLPointer(const LLPointer<Subclass>& ptr) :
mPointer(ptr.get())
{
ref();
}
~LLPointer()
{
unref();
}
Type* get() const { return mPointer; }
const Type* operator->() const { return mPointer; }
Type* operator->() { return mPointer; }
const Type& operator*() const { return *mPointer; }
Type& operator*() { return *mPointer; }
operator BOOL() const { return (mPointer != NULL); }
operator bool() const { return (mPointer != NULL); }
bool operator!() const { return (mPointer == NULL); }
bool isNull() const { return (mPointer == NULL); }
bool notNull() const { return (mPointer != NULL); }
operator Type*() const { return mPointer; }
operator const Type*() const { return mPointer; }
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
LLPointer<Type>& operator =(Type* ptr)
{
if( mPointer != ptr )
{
unref();
mPointer = ptr;
ref();
}
return *this;
}
LLPointer<Type>& operator =(const LLPointer<Type>& ptr)
{
if( mPointer != ptr.mPointer )
{
unref();
mPointer = ptr.mPointer;
ref();
}
return *this;
}
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
{
if( mPointer != ptr.get() )
{
unref();
mPointer = ptr.get();
ref();
}
return *this;
}
// Just exchange the pointers, which will not change the reference counts.
static void swap(LLPointer<Type>& a, LLPointer<Type>& b)
{
Type* temp = a.mPointer;
a.mPointer = b.mPointer;
b.mPointer = temp;
}
protected:
void ref()
{
if (mPointer)
{
mPointer->ref();
}
}
void unref()
{
if (mPointer)
{
Type *tempp = mPointer;
mPointer = NULL;
tempp->unref();
if (mPointer != NULL)
{
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
unref();
}
}
}
protected:
Type* mPointer;
};
//template <class Type>
//class LLPointerTraits
//{
// static Type* null();
//};
//
// Expands LLPointer to return a pointer to a special instance of class Type instead of NULL.
// This is useful in instances where operations on NULL pointers are semantically safe and/or
// when error checking occurs at a different granularity or in a different part of the code
// than when referencing an object via a LLSafeHandle.
//
template <class Type>
class LLSafeHandle
{
public:
LLSafeHandle() :
mPointer(NULL)
{
}
LLSafeHandle(Type* ptr) :
mPointer(NULL)
{
assign(ptr);
}
LLSafeHandle(const LLSafeHandle<Type>& ptr) :
mPointer(NULL)
{
assign(ptr.mPointer);
}
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLSafeHandle(const LLSafeHandle<Subclass>& ptr) :
mPointer(NULL)
{
assign(ptr.get());
}
~LLSafeHandle()
{
unref();
}
const Type* operator->() const { return nonNull(mPointer); }
Type* operator->() { return nonNull(mPointer); }
Type* get() const { return mPointer; }
// we disallow these operations as they expose our null objects to direct manipulation
// and bypass the reference counting semantics
//const Type& operator*() const { return *nonNull(mPointer); }
//Type& operator*() { return *nonNull(mPointer); }
operator BOOL() const { return mPointer != NULL; }
operator bool() const { return mPointer != NULL; }
bool operator!() const { return mPointer == NULL; }
bool isNull() const { return mPointer == NULL; }
bool notNull() const { return mPointer != NULL; }
operator Type*() const { return mPointer; }
operator const Type*() const { return mPointer; }
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
bool operator ==(const LLSafeHandle<Type>& ptr) const { return (mPointer == ptr.mPointer); }
bool operator < (const LLSafeHandle<Type>& ptr) const { return (mPointer < ptr.mPointer); }
bool operator > (const LLSafeHandle<Type>& ptr) const { return (mPointer > ptr.mPointer); }
LLSafeHandle<Type>& operator =(Type* ptr)
{
assign(ptr);
return *this;
}
LLSafeHandle<Type>& operator =(const LLSafeHandle<Type>& ptr)
{
assign(ptr.mPointer);
return *this;
}
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLSafeHandle<Type>& operator =(const LLSafeHandle<Subclass>& ptr)
{
assign(ptr.get());
return *this;
}
public:
typedef Type* (*NullFunc)();
static const NullFunc sNullFunc;
protected:
void ref()
{
if (mPointer)
{
mPointer->ref();
}
}
void unref()
{
if (mPointer)
{
Type *tempp = mPointer;
mPointer = NULL;
tempp->unref();
if (mPointer != NULL)
{
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
unref();
}
}
}
void assign(Type* ptr)
{
if( mPointer != ptr )
{
unref();
mPointer = ptr;
ref();
}
}
static Type* nonNull(Type* ptr)
{
return ptr == NULL ? sNullFunc() : ptr;
}
protected:
Type* mPointer;
};
// LLInitializedPointer is just a pointer with a default constructor that initializes it to NULL
// NOT a smart pointer like LLPointer<>
// Useful for example in std::map<int,LLInitializedPointer<LLFoo> >
// (std::map uses the default constructor for creating new entries)
template <typename T> class LLInitializedPointer
{
public:
LLInitializedPointer() : mPointer(NULL) {}
~LLInitializedPointer() { delete mPointer; }
const T* operator->() const { return mPointer; }
T* operator->() { return mPointer; }
const T& operator*() const { return *mPointer; }
T& operator*() { return *mPointer; }
operator const T*() const { return mPointer; }
operator T*() { return mPointer; }
T* operator=(T* x) { return (mPointer = x); }
operator bool() const { return mPointer != NULL; }
bool operator!() const { return mPointer == NULL; }
bool operator==(T* rhs) { return mPointer == rhs; }
bool operator==(const LLInitializedPointer<T>* rhs) { return mPointer == rhs.mPointer; }
protected:
T* mPointer;
};
//----------------------------------------------------------------------------
// LLSingleton implements the getInstance() method part of the Singleton
// pattern. It can't make the derived class constructors protected, though, so
// you have to do that yourself.
//
// There are two ways to use LLSingleton. The first way is to inherit from it
// while using the typename that you'd like to be static as the template
// parameter, like so:
//
// class Foo: public LLSingleton<Foo>{};
//
// Foo& instance = Foo::instance();
//
// The second way is to use the singleton class directly, without inheritance:
//
// typedef LLSingleton<Foo> FooSingleton;
//
// Foo& instance = FooSingleton::instance();
//
// In this case, the class being managed as a singleton needs to provide an
// initSingleton() method since the LLSingleton virtual method won't be
// available
//
// As currently written, it is not thread-safe.
template <typename T>
class LLSingleton
{
static bool &needsInit()
{
static bool needs_init = true;
return needs_init;
}
public:
static bool instanceExists()
{
return !needsInit();
}
virtual ~LLSingleton() {}
#ifdef LL_MSVC7
// workaround for VC7 compiler bug
// adapted from http://www.codeproject.com/KB/tips/VC2003MeyersSingletonBug.aspx
// our version doesn't introduce a nested struct so that you can still declare LLSingleton<MyClass>
// a friend and hide your constructor
static T* getInstance()
{
LLSingleton<T> singleton;
return singleton.vsHack();
}
T* vsHack()
#else
static T* getInstance()
#endif
{
static T instance;
bool &needs_init = needsInit();
if (needs_init)
{
needs_init = false;
instance.initSingleton();
}
return &instance;
}
static T& instance()
{
return *getInstance();
}
private:
virtual void initSingleton() {}
};
//----------------------------------------------------------------------------
// Return the resident set size of the current process, in bytes.
// Return value is zero if not known.
LL_COMMON_API U64 getCurrentRSS();
//EVENTUALLY REMOVE THESE:
#include "llpointer.h"
#include "llrefcount.h"
#include "llsingleton.h"
#include "llsafehandle.h"
#endif

View File

@@ -74,9 +74,3 @@ void LLMortician::setZealous(BOOL b)
{
sDestroyImmediate = b;
}
// static
BOOL LLMortician::getZealous()
{
return sDestroyImmediate;
}

View File

@@ -46,7 +46,6 @@ public:
// sets destroy immediate true
static void setZealous(BOOL b);
static BOOL getZealous();
private:
static BOOL sDestroyImmediate;

170
indra/llcommon/llpointer.h Normal file
View File

@@ -0,0 +1,170 @@
/**
* @file llpointer.h
* @brief A reference-counted pointer for objects derived from LLRefCount
*
* $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 LLPOINTER_H
#define LLPOINTER_H
#include "llerror.h" // *TODO: consider eliminating this
//----------------------------------------------------------------------------
// RefCount objects should generally only be accessed by way of LLPointer<>'s
// NOTE: LLPointer<LLFoo> x = new LLFoo(); MAY NOT BE THREAD SAFE
// if LLFoo::LLFoo() does anything like put itself in an update queue.
// The queue may get accessed before it gets assigned to x.
// The correct implementation is:
// LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting
// x->instantiate(); // does stuff like place x into an update queue
// see llthread.h for LLThreadSafeRefCount
//----------------------------------------------------------------------------
// Note: relies on Type having ref() and unref() methods
template <class Type> class LLPointer
{
public:
LLPointer() :
mPointer(NULL)
{
}
LLPointer(Type* ptr) :
mPointer(ptr)
{
ref();
}
LLPointer(const LLPointer<Type>& ptr) :
mPointer(ptr.mPointer)
{
ref();
}
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLPointer(const LLPointer<Subclass>& ptr) :
mPointer(ptr.get())
{
ref();
}
~LLPointer()
{
unref();
}
Type* get() const { return mPointer; }
const Type* operator->() const { return mPointer; }
Type* operator->() { return mPointer; }
const Type& operator*() const { return *mPointer; }
Type& operator*() { return *mPointer; }
operator BOOL() const { return (mPointer != NULL); }
operator bool() const { return (mPointer != NULL); }
bool operator!() const { return (mPointer == NULL); }
bool isNull() const { return (mPointer == NULL); }
bool notNull() const { return (mPointer != NULL); }
operator Type*() const { return mPointer; }
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
LLPointer<Type>& operator =(Type* ptr)
{
if( mPointer != ptr )
{
unref();
mPointer = ptr;
ref();
}
return *this;
}
LLPointer<Type>& operator =(const LLPointer<Type>& ptr)
{
if( mPointer != ptr.mPointer )
{
unref();
mPointer = ptr.mPointer;
ref();
}
return *this;
}
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
{
if( mPointer != ptr.get() )
{
unref();
mPointer = ptr.get();
ref();
}
return *this;
}
// Just exchange the pointers, which will not change the reference counts.
static void swap(LLPointer<Type>& a, LLPointer<Type>& b)
{
Type* temp = a.mPointer;
a.mPointer = b.mPointer;
b.mPointer = temp;
}
protected:
void ref()
{
if (mPointer)
{
mPointer->ref();
}
}
void unref()
{
if (mPointer)
{
Type *tempp = mPointer;
mPointer = NULL;
tempp->unref();
if (mPointer != NULL)
{
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
unref();
}
}
}
protected:
Type* mPointer;
};
#endif

View File

@@ -107,7 +107,17 @@
#endif
// Deal with the differences on Windows
// Static linking with apr on windows needs to be declared.
#if LL_WINDOWS && !LL_COMMON_LINK_SHARED
#ifndef APR_DECLARE_STATIC
#define APR_DECLARE_STATIC // For APR on Windows
#endif
#ifndef APU_DECLARE_STATIC
#define APU_DECLARE_STATIC // For APR util on Windows
#endif
#endif
#if defined(LL_WINDOWS)
#define BOOST_REGEX_NO_LIB 1
#define CURL_STATICLIB 1
@@ -159,12 +169,19 @@
#define LL_DLLIMPORT
#endif // LL_WINDOWS
#ifdef llcommon_EXPORTS
// Compiling llcommon (shared)
#define LL_COMMON_API LL_DLLEXPORT
#else // llcommon_EXPORTS
// Using llcommon (shared)
#define LL_COMMON_API LL_DLLIMPORT
#endif // llcommon_EXPORTS
#if LL_COMMON_LINK_SHARED
// CMake automagically defines llcommon_EXPORTS only when building llcommon
// sources, and only when llcommon is a shared library (i.e. when
// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because
// otherwise we can't distinguish between (non-llcommon source) and (llcommon
// not shared).
# if defined(llcommon_EXPORTS)
# define LL_COMMON_API LL_DLLEXPORT
# else //llcommon_EXPORTS
# define LL_COMMON_API LL_DLLIMPORT
# endif //llcommon_EXPORTS
#else // LL_COMMON_LINK_SHARED
# define LL_COMMON_API
#endif // LL_COMMON_LINK_SHARED
#endif // not LL_LINDEN_PREPROCESSOR_H

View File

@@ -36,7 +36,7 @@
#include <apr_file_io.h>
#include <apr_thread_proc.h>
#include "llprocesslauncher.h"
#include "aiaprpool.h"
#include "llaprpool.h"
#include <iostream>
#if LL_DARWIN || LL_LINUX
@@ -102,7 +102,7 @@ int LLProcessLauncher::launch(void)
STARTUPINFOA sinfo;
memset(&sinfo, 0, sizeof(sinfo));
std::string args = "\"" + mExecutable + "\"";
std::string args = mExecutable;
for(int i = 0; i < (int)mLaunchArguments.size(); i++)
{
args += " ";
@@ -114,10 +114,30 @@ int LLProcessLauncher::launch(void)
char *args2 = new char[args.size() + 1];
strcpy(args2, args.c_str());
if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo ) )
const char * working_directory = 0;
if(!mWorkingDir.empty()) working_directory = mWorkingDir.c_str();
if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, working_directory, &sinfo, &pinfo ) )
{
// TODO: do better than returning the OS-specific error code on failure...
result = GetLastError();
LPTSTR error_str = 0;
if(
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
result,
0,
(LPTSTR)&error_str,
0,
NULL)
!= 0)
{
char message[256];
wcstombs(message, error_str, 256);
message[255] = 0;
llwarns << "CreateProcessA failed: " << message << llendl;
LocalFree(error_str);
}
if(result == 0)
{
// Make absolutely certain we return a non-zero value on failure.
@@ -326,7 +346,7 @@ int LLProcessLauncher::launch(void)
// Set up a pipe to the child process for error reporting.
apr_file_t* in;
apr_file_t* out;
AIAPRPool pool;
LLAPRPool pool;
pool.create();
#if(APR_VERSION_MAJOR==1 && APR_VERSION_MINOR>=3 || APR_VERSION_MAJOR>1)
apr_status_t status = apr_file_pipe_create_ex(&in, &out, APR_FULL_BLOCK, pool());

View File

@@ -31,8 +31,9 @@
#include "linden_common.h"
#include "llqueuedthread.h"
#include "llstl.h"
#include "lltimer.h"
#include "lltimer.h" // ms_sleep()
//============================================================================
@@ -41,7 +42,8 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
LLThread(name),
mThreaded(threaded),
mIdleThread(TRUE),
mNextHandle(0)
mNextHandle(0),
mStarted(FALSE)
{
if (mThreaded)
{
@@ -52,6 +54,10 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
// MAIN THREAD
LLQueuedThread::~LLQueuedThread()
{
if (!mThreaded)
{
endThread();
}
shutdown();
// ~LLThread() will be called here
}
@@ -90,6 +96,7 @@ void LLQueuedThread::shutdown()
if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS)
{
++active_count;
req->setStatus(STATUS_ABORTED); // avoid assert in deleteRequest
}
req->deleteRequest();
}
@@ -105,6 +112,14 @@ void LLQueuedThread::shutdown()
// virtual
S32 LLQueuedThread::update(U32 max_time_ms)
{
if (!mStarted)
{
if (!mThreaded)
{
startThread();
mStarted = TRUE;
}
}
return updateQueue(max_time_ms);
}
@@ -118,8 +133,11 @@ S32 LLQueuedThread::updateQueue(U32 max_time_ms)
if (mThreaded)
{
pending = getPending();
if(pending > 0)
{
unpause();
}
}
else
{
while (pending > 0)
@@ -349,9 +367,9 @@ bool LLQueuedThread::completeRequest(handle_t handle)
#if _DEBUG
// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl;
#endif
//re insert to the queue to schedule for a delete later
req->setStatus(STATUS_DELETE);
mRequestQueue.insert(req);
mRequestHash.erase(handle);
req->deleteRequest();
// check();
res = true;
}
unlockData();
@@ -395,19 +413,11 @@ S32 LLQueuedThread::processNextRequest()
}
req = *mRequestQueue.begin();
mRequestQueue.erase(mRequestQueue.begin());
if(req->getStatus() == STATUS_DELETE)
{
mRequestHash.erase(req);
req->deleteRequest();
continue;
}
if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING))
{
req->setStatus(STATUS_ABORTED);
req->finishRequest(false);
if ((req->getFlags() & FLAG_AUTO_COMPLETE))
if (req->getFlags() & FLAG_AUTO_COMPLETE)
{
mRequestHash.erase(req);
req->deleteRequest();
@@ -418,9 +428,11 @@ S32 LLQueuedThread::processNextRequest()
llassert_always(req->getStatus() == STATUS_QUEUED);
break;
}
U32 start_priority = 0 ;
if (req)
{
req->setStatus(STATUS_INPROGRESS);
start_priority = req->getPriority();
}
unlockData();
@@ -436,13 +448,12 @@ S32 LLQueuedThread::processNextRequest()
{
lockData();
req->setStatus(STATUS_COMPLETE);
req->finishRequest(true);
if ((req->getFlags() & FLAG_AUTO_COMPLETE))
if (req->getFlags() & FLAG_AUTO_COMPLETE)
{
mRequestHash.erase(req);
req->deleteRequest();
// check();
}
unlockData();
}
@@ -451,9 +462,8 @@ S32 LLQueuedThread::processNextRequest()
lockData();
req->setStatus(STATUS_QUEUED);
mRequestQueue.insert(req);
U32 priority = req->getPriority();
unlockData();
if (priority < PRIORITY_NORMAL)
if (mThreaded && start_priority < PRIORITY_NORMAL)
{
ms_sleep(1); // sleep the thread a little
}
@@ -481,6 +491,7 @@ void LLQueuedThread::run()
// call checPause() immediately so we don't try to do anything before the class is fully constructed
checkPause();
startThread();
mStarted = TRUE;
while (1)
{

View File

@@ -184,7 +184,7 @@ public:
void waitOnPending();
void printQueueStats();
S32 getPending();
virtual S32 getPending();
bool getThreaded() { return mThreaded ? true : false; }
// Request accessors
@@ -202,6 +202,7 @@ public:
protected:
BOOL mThreaded; // if false, run on main thread and do updates during update()
BOOL mStarted; // required when mThreaded is false to call startThread() from update()
LLAtomic32<BOOL> mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
typedef std::set<QueuedRequest*, queued_request_less> request_queue_t;

View File

@@ -0,0 +1,164 @@
/**
* @file llrefcount.cpp
* @brief Base class for reference counted objects for use with LLPointer
*
* $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 "linden_common.h"
#include "llrefcount.h"
#include "llerror.h"
#if LL_REF_COUNT_DEBUG
#include "llthread.h"
#include "llapr.h"
#endif
LLRefCount::LLRefCount(const LLRefCount& other)
: mRef(0)
{
#if LL_REF_COUNT_DEBUG
if(gAPRPoolp)
{
mMutexp = new LLMutex(gAPRPoolp) ;
}
else
{
mMutexp = NULL ;
}
mCrashAtUnlock = FALSE ;
#endif
}
LLRefCount& LLRefCount::operator=(const LLRefCount&)
{
// do nothing, since ref count is specific to *this* reference
return *this;
}
LLRefCount::LLRefCount() :
mRef(0)
{
#if LL_REF_COUNT_DEBUG
if(gAPRPoolp)
{
mMutexp = new LLMutex(gAPRPoolp) ;
}
else
{
mMutexp = NULL ;
}
mCrashAtUnlock = FALSE ;
#endif
}
LLRefCount::~LLRefCount()
{
if (mRef != 0)
{
llerrs << "deleting non-zero reference" << llendl;
}
#if LL_REF_COUNT_DEBUG
if(gAPRPoolp)
{
delete mMutexp ;
}
#endif
}
#if LL_REF_COUNT_DEBUG
void LLRefCount::ref() const
{
if(mMutexp)
{
if(mMutexp->isLocked())
{
mCrashAtUnlock = TRUE ;
llerrs << "the mutex is locked by the thread: " << mLockedThreadID
<< " Current thread: " << LLThread::currentID() << llendl ;
}
mMutexp->lock() ;
mLockedThreadID = LLThread::currentID() ;
mRef++;
if(mCrashAtUnlock)
{
while(1); //crash here.
}
mMutexp->unlock() ;
}
else
{
mRef++;
}
}
S32 LLRefCount::unref() const
{
if(mMutexp)
{
if(mMutexp->isLocked())
{
mCrashAtUnlock = TRUE ;
llerrs << "the mutex is locked by the thread: " << mLockedThreadID
<< " Current thread: " << LLThread::currentID() << llendl ;
}
mMutexp->lock() ;
mLockedThreadID = LLThread::currentID() ;
llassert(mRef >= 1);
if (0 == --mRef)
{
if(mCrashAtUnlock)
{
while(1); //crash here.
}
mMutexp->unlock() ;
delete this;
return 0;
}
if(mCrashAtUnlock)
{
while(1); //crash here.
}
mMutexp->unlock() ;
return mRef;
}
else
{
llassert(mRef >= 1);
if (0 == --mRef)
{
delete this;
return 0;
}
return mRef;
}
}
#endif

View File

@@ -0,0 +1,89 @@
/**
* @file llrefcount.h
* @brief Base class for reference counted objects for use with LLPointer
*
* $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 LLREFCOUNT_H
#define LLREFCOUNT_H
#include <boost/noncopyable.hpp>
#define LL_REF_COUNT_DEBUG 0
#if LL_REF_COUNT_DEBUG
class LLMutex ;
#endif
//----------------------------------------------------------------------------
// RefCount objects should generally only be accessed by way of LLPointer<>'s
// see llthread.h for LLThreadSafeRefCount
//----------------------------------------------------------------------------
class LL_COMMON_API LLRefCount
{
protected:
LLRefCount(const LLRefCount& other);
LLRefCount& operator=(const LLRefCount&);
virtual ~LLRefCount(); // use unref()
public:
LLRefCount();
#if LL_REF_COUNT_DEBUG
void ref() const ;
S32 unref() const ;
#else
inline void ref() const
{
mRef++;
}
inline S32 unref() const
{
llassert(mRef >= 1);
if (0 == --mRef)
{
delete this;
return 0;
}
return mRef;
}
#endif
//NOTE: when passing around a const LLRefCount object, this can return different results
// at different types, since mRef is mutable
S32 getNumRefs() const
{
return mRef;
}
private:
mutable S32 mRef;
#if LL_REF_COUNT_DEBUG
LLMutex* mMutexp ;
mutable U32 mLockedThreadID ;
mutable BOOL mCrashAtUnlock ;
#endif
};
#endif

View File

@@ -0,0 +1,162 @@
/**
* @file llsafehandle.h
* @brief Reference-counted object where Object() is valid, not NULL.
*
* $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 LLSAFEHANDLE_H
#define LLSAFEHANDLE_H
#include "llerror.h" // *TODO: consider eliminating this
// Expands LLPointer to return a pointer to a special instance of class Type instead of NULL.
// This is useful in instances where operations on NULL pointers are semantically safe and/or
// when error checking occurs at a different granularity or in a different part of the code
// than when referencing an object via a LLSafeHandle.
template <class Type>
class LLSafeHandle
{
public:
LLSafeHandle() :
mPointer(NULL)
{
}
LLSafeHandle(Type* ptr) :
mPointer(NULL)
{
assign(ptr);
}
LLSafeHandle(const LLSafeHandle<Type>& ptr) :
mPointer(NULL)
{
assign(ptr.mPointer);
}
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLSafeHandle(const LLSafeHandle<Subclass>& ptr) :
mPointer(NULL)
{
assign(ptr.get());
}
~LLSafeHandle()
{
unref();
}
const Type* operator->() const { return nonNull(mPointer); }
Type* operator->() { return nonNull(mPointer); }
Type* get() const { return mPointer; }
void clear() { assign(NULL); }
// we disallow these operations as they expose our null objects to direct manipulation
// and bypass the reference counting semantics
//const Type& operator*() const { return *nonNull(mPointer); }
//Type& operator*() { return *nonNull(mPointer); }
operator BOOL() const { return mPointer != NULL; }
operator bool() const { return mPointer != NULL; }
bool operator!() const { return mPointer == NULL; }
bool isNull() const { return mPointer == NULL; }
bool notNull() const { return mPointer != NULL; }
operator Type*() const { return mPointer; }
operator const Type*() const { return mPointer; }
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
bool operator ==(const LLSafeHandle<Type>& ptr) const { return (mPointer == ptr.mPointer); }
bool operator < (const LLSafeHandle<Type>& ptr) const { return (mPointer < ptr.mPointer); }
bool operator > (const LLSafeHandle<Type>& ptr) const { return (mPointer > ptr.mPointer); }
LLSafeHandle<Type>& operator =(Type* ptr)
{
assign(ptr);
return *this;
}
LLSafeHandle<Type>& operator =(const LLSafeHandle<Type>& ptr)
{
assign(ptr.mPointer);
return *this;
}
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLSafeHandle<Type>& operator =(const LLSafeHandle<Subclass>& ptr)
{
assign(ptr.get());
return *this;
}
public:
typedef Type* (*NullFunc)();
static const NullFunc sNullFunc;
protected:
void ref()
{
if (mPointer)
{
mPointer->ref();
}
}
void unref()
{
if (mPointer)
{
Type *tempp = mPointer;
mPointer = NULL;
tempp->unref();
if (mPointer != NULL)
{
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
unref();
}
}
}
void assign(Type* ptr)
{
if( mPointer != ptr )
{
unref();
mPointer = ptr;
ref();
}
}
static Type* nonNull(Type* ptr)
{
return ptr == NULL ? sNullFunc() : ptr;
}
protected:
Type* mPointer;
};
#endif

View File

@@ -35,21 +35,21 @@
#include "llthread.h"
//! Scoped volatile memory pool.
//
// As the AIVolatileAPRPool should never keep allocations very
// long, it's most common use is for allocations with a lifetime
// equal to it's scope.
//
// This is a convenience class that makes just a little easier to type.
//
class LLScopedVolatileAPRPool
/** Scoped volatile memory pool.
*
* As the LLVolatileAPRPool should never keep allocations very
* long, its most common use is for allocations with a lifetime
* equal to it's scope.
*
* This is a convenience class that makes just a little easier to type.
*/
class LL_COMMON_API LLScopedVolatileAPRPool
{
private:
AIVolatileAPRPool& mPool;
LLVolatileAPRPool& mPool;
apr_pool_t* mScopedAPRpool;
public:
LLScopedVolatileAPRPool() : mPool(AIThreadLocalData::tldata().mVolatileAPRPool), mScopedAPRpool(mPool.getVolatileAPRPool()) { }
LLScopedVolatileAPRPool() : mPool(LLThreadLocalData::tldata().mVolatileAPRPool), mScopedAPRpool(mPool.getVolatileAPRPool()) { }
~LLScopedVolatileAPRPool() { mPool.clearVolatileAPRPool(); }
// Only use this to pass the pointer to a libapr-1 function that requires it.
operator apr_pool_t*() const { return mScopedAPRpool; }

View File

@@ -754,11 +754,7 @@ void LLSD::insert(const String& k, const LLSD& v) { makeMap(impl).insert(k, v);
LLSD& LLSD::with(const String& k, const LLSD& v)
{
makeMap(impl).insert(k, v);
#ifdef LL_MSVC7
return *dynamic_cast<LLSD*>(this);
#else
return *this;
#endif
return *this;
}
void LLSD::erase(const String& k) { makeMap(impl).erase(k); }
@@ -784,11 +780,7 @@ void LLSD::insert(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); }
LLSD& LLSD::with(Integer i, const LLSD& v)
{
makeArray(impl).insert(i, v);
#ifdef LL_MSVC7
return *dynamic_cast<LLSD*>(this);
#else
return *this;
#endif
return *this;
}
void LLSD::append(const LLSD& v) { makeArray(impl).append(v); }
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }

View File

@@ -34,11 +34,18 @@
#include "linden_common.h"
#include "llsdserialize.h"
#include "llmemory.h"
#include "llpointer.h"
#include "llstreamtools.h" // for fullread
#include <iostream>
#include "apr_base64.h"
#if MESH_ENABLED
#ifdef LL_STANDALONE
# include <zlib.h>
#else
# include "zlib/zlib.h" // for davep's dirty little zip functions
#endif
#endif //MESH_ENABLED
#if !LL_WINDOWS
#include <netinet/in.h> // htonl & ntohl
@@ -1447,12 +1454,9 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option
}
case LLSD::TypeUUID:
{
ostr.put('u');
LLUUID d = data.asUUID();
ostr.write((const char*)(&(d.mData)), UUID_BYTES);
ostr.write((const char*)(&(data.asUUID().mData)), UUID_BYTES);
break;
}
case LLSD::TypeString:
ostr.put('s');
@@ -1505,7 +1509,7 @@ void LLSDBinaryFormatter::formatString(
*/
int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes)
{
char c = istr.get();
int c = istr.get();
if(istr.fail())
{
// No data in stream, bail out but mention the character we
@@ -1547,7 +1551,7 @@ int deserialize_string_delim(
while (true)
{
char next_char = istr.get();
int next_byte = istr.get();
++count;
if(istr.fail())
@@ -1556,6 +1560,8 @@ int deserialize_string_delim(
value = write_buffer.str();
return LLSDParser::PARSE_FAILURE;
}
char next_char = (char)next_byte; // Now that we know it's not EOF
if(found_escape)
{
@@ -1644,7 +1650,7 @@ int deserialize_string_raw(
char buf[BUF_LEN]; /* Flawfinder: ignore */
istr.get(buf, BUF_LEN - 1, ')');
count += istr.gcount();
char c = istr.get();
int c = istr.get();
c = istr.get();
count += 2;
if(((c == '"') || (c == '\'')) && (buf[0] == '('))
@@ -1990,3 +1996,181 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
return s;
}
#if MESH_ENABLED
//dirty little zippers -- yell at davep if these are horrid
//return a string containing gzipped bytes of binary serialized LLSD
// VERY inefficient -- creates several copies of LLSD block in memory
std::string zip_llsd(LLSD& data)
{
std::stringstream llsd_strm;
LLSDSerialize::toBinary(data, llsd_strm);
const U32 CHUNK = 65536;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION);
if (ret != Z_OK)
{
llwarns << "Failed to compress LLSD block." << llendl;
return std::string();
}
std::string source = llsd_strm.str();
U8 out[CHUNK];
strm.avail_in = source.size();
strm.next_in = (U8*) source.data();
U8* output = NULL;
U32 cur_size = 0;
U32 have = 0;
do
{
strm.avail_out = CHUNK;
strm.next_out = out;
ret = deflate(&strm, Z_FINISH);
if (ret == Z_OK || ret == Z_STREAM_END)
{ //copy result into output
if (strm.avail_out >= CHUNK)
{
free(output);
llwarns << "Failed to compress LLSD block." << llendl;
return std::string();
}
have = CHUNK-strm.avail_out;
output = (U8*) realloc(output, cur_size+have);
memcpy(output+cur_size, out, have);
cur_size += have;
}
else
{
free(output);
llwarns << "Failed to compress LLSD block." << llendl;
return std::string();
}
}
while (ret == Z_OK);
std::string::size_type size = cur_size;
std::string result((char*) output, size);
deflateEnd(&strm);
free(output);
#if 0 //verify results work with unzip_llsd
std::istringstream test(result);
LLSD test_sd;
if (!unzip_llsd(test_sd, test, result.size()))
{
llerrs << "Invalid compression result!" << llendl;
}
#endif
return result;
}
//decompress a block of LLSD from provided istream
// not very efficient -- creats a copy of decompressed LLSD block in memory
// and deserializes from that copy using LLSDSerialize
bool unzip_llsd(LLSD& data, std::istream& is, S32 size)
{
U8* result = NULL;
U32 cur_size = 0;
z_stream strm;
const U32 CHUNK = 65536;
U8 *in = new U8[size];
is.read((char*) in, size);
U8 out[CHUNK];
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = size;
strm.next_in = in;
S32 ret = inflateInit(&strm);
do
{
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
if (ret == Z_STREAM_ERROR)
{
inflateEnd(&strm);
free(result);
delete [] in;
return false;
}
switch (ret)
{
case Z_NEED_DICT:
ret = Z_DATA_ERROR;
case Z_DATA_ERROR:
case Z_MEM_ERROR:
inflateEnd(&strm);
free(result);
delete [] in;
return false;
break;
}
U32 have = CHUNK-strm.avail_out;
result = (U8*) realloc(result, cur_size + have);
memcpy(result+cur_size, out, have);
cur_size += have;
} while (ret == Z_OK);
inflateEnd(&strm);
delete [] in;
if (ret != Z_STREAM_END)
{
free(result);
return false;
}
//result now points to the decompressed LLSD block
{
std::string res_str((char*) result, cur_size);
std::string deprecated_header("<? LLSD/Binary ?>");
if (res_str.substr(0, deprecated_header.size()) == deprecated_header)
{
res_str = res_str.substr(deprecated_header.size()+1, cur_size);
}
cur_size = res_str.size();
std::istringstream istr(res_str);
if (!LLSDSerialize::fromBinary(data, istr, cur_size))
{
llwarns << "Failed to unzip LLSD block" << llendl;
free(result);
return false;
}
}
free(result);
return true;
}
#endif //MESH_ENABLED

View File

@@ -36,8 +36,9 @@
#define LL_LLSDSERIALIZE_H
#include <iosfwd>
#include "llpointer.h"
#include "llrefcount.h"
#include "llsd.h"
#include "llmemory.h"
/**
* @class LLSDParser
@@ -787,4 +788,9 @@ public:
}
};
#if MESH_ENABLED
//dirty little zip functions -- yell at davep
LL_COMMON_API std::string zip_llsd(LLSD& data);
LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size);
#endif //MESH_ENABLED
#endif // LL_LLSDSERIALIZE_H

View File

@@ -37,6 +37,7 @@
#include <deque>
#include "apr_base64.h"
#include <boost/regex.hpp>
extern "C"
{
@@ -734,6 +735,7 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
case ELEMENT_INTEGER:
{
S32 i;
// sscanf okay here with different locales - ints don't change for different locale settings like floats do.
if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
{ // See if sscanf works - it's faster
value = i;
@@ -747,15 +749,19 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
case ELEMENT_REAL:
{
F64 r;
if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
{ // See if sscanf works - it's faster
value = r;
}
else
{
value = LLSD(mCurrentContent).asReal();
}
value = LLSD(mCurrentContent).asReal();
// removed since this breaks when locale has decimal separator that isn't '.'
// investigated changing local to something compatible each time but deemed higher
// risk that just using LLSD.asReal() each time.
//F64 r;
//if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
//{ // See if sscanf works - it's faster
// value = r;
//}
//else
//{
// value = LLSD(mCurrentContent).asReal();
//}
}
break;
@@ -777,10 +783,17 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
case ELEMENT_BINARY:
{
S32 len = apr_base64_decode_len(mCurrentContent.c_str());
// Regex is expensive, but only fix for whitespace in base64,
// created by python and other non-linden systems - DEV-39358
// Fortunately we have very little binary passing now,
// so performance impact shold be negligible. + poppy 2009-09-04
boost::regex r;
r.assign("\\s");
std::string stripped = boost::regex_replace(mCurrentContent, r, "");
S32 len = apr_base64_decode_len(stripped.c_str());
std::vector<U8> data;
data.resize(len);
len = apr_base64_decode_binary(&data[0], mCurrentContent.c_str());
len = apr_base64_decode_binary(&data[0], stripped.c_str());
data.resize(len);
value = data;
break;

View File

@@ -46,6 +46,12 @@
#endif
#include "llsdserialize.h"
#include "stringize.h"
#include "is_approx_equal_fraction.h"
#include <map>
#include <set>
#include <boost/range.hpp>
// U32
LLSD ll_sd_from_U32(const U32 val)
@@ -171,6 +177,15 @@ char* ll_print_sd(const LLSD& sd)
return buffer;
}
char* ll_pretty_print_sd_ptr(const LLSD* sd)
{
if (sd)
{
return ll_pretty_print_sd(*sd);
}
return NULL;
}
char* ll_pretty_print_sd(const LLSD& sd)
{
const U32 bufferSize = 10 * 1024;
@@ -304,3 +319,363 @@ BOOL compare_llsd_with_template(
return TRUE;
}
/*****************************************************************************
* Helpers for llsd_matches()
*****************************************************************************/
// raw data used for LLSD::Type lookup
struct Data
{
LLSD::Type type;
const char* name;
} typedata[] =
{
#define def(type) { LLSD::type, #type + 4 }
def(TypeUndefined),
def(TypeBoolean),
def(TypeInteger),
def(TypeReal),
def(TypeString),
def(TypeUUID),
def(TypeDate),
def(TypeURI),
def(TypeBinary),
def(TypeMap),
def(TypeArray)
#undef def
};
// LLSD::Type lookup class into which we load the above static data
class TypeLookup
{
typedef std::map<LLSD::Type, std::string> MapType;
public:
TypeLookup()
{
for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di)
{
mMap[di->type] = di->name;
}
}
std::string lookup(LLSD::Type type) const
{
MapType::const_iterator found = mMap.find(type);
if (found != mMap.end())
{
return found->second;
}
return STRINGIZE("<unknown LLSD type " << type << ">");
}
private:
MapType mMap;
};
// static instance of the lookup class
static const TypeLookup sTypes;
// describe a mismatch; phrasing may want tweaking
const std::string op(" required instead of ");
// llsd_matches() wants to identify specifically where in a complex prototype
// structure the mismatch occurred. This entails passing a prefix string,
// empty for the top-level call. If the prototype contains an array of maps,
// and the mismatch occurs in the second map in a key 'foo', we want to
// decorate the returned string with: "[1]['foo']: etc." On the other hand, we
// want to omit the entire prefix -- including colon -- if the mismatch is at
// top level. This helper accepts the (possibly empty) recursively-accumulated
// prefix string, returning either empty or the original string with colon
// appended.
static std::string colon(const std::string& pfx)
{
if (pfx.empty())
return pfx;
return pfx + ": ";
}
// param type for match_types
typedef std::vector<LLSD::Type> TypeVector;
// The scalar cases in llsd_matches() use this helper. In most cases, we can
// accept not only the exact type specified in the prototype, but also other
// types convertible to the expected type. That implies looping over an array
// of such types. If the actual type doesn't match any of them, we want to
// provide a list of acceptable conversions as well as the exact type, e.g.:
// "Integer (or Boolean, Real, String) required instead of UUID". Both the
// implementation and the calling logic are simplified by separating out the
// expected type from the convertible types.
static std::string match_types(LLSD::Type expect, // prototype.type()
const TypeVector& accept, // types convertible to that type
LLSD::Type actual, // type we're checking
const std::string& pfx) // as for llsd_matches
{
// Trivial case: if the actual type is exactly what we expect, we're good.
if (actual == expect)
return "";
// For the rest of the logic, build up a suitable error string as we go so
// we only have to make a single pass over the list of acceptable types.
// If we detect success along the way, we'll simply discard the partial
// error string.
std::ostringstream out;
out << colon(pfx) << sTypes.lookup(expect);
// If there are any convertible types, append that list.
if (! accept.empty())
{
out << " (";
const char* sep = "or ";
for (TypeVector::const_iterator ai(accept.begin()), aend(accept.end());
ai != aend; ++ai, sep = ", ")
{
// Don't forget to return success if we match any of those types...
if (actual == *ai)
return "";
out << sep << sTypes.lookup(*ai);
}
out << ')';
}
// If we got this far, it's because 'actual' was not one of the acceptable
// types, so we must return an error. 'out' already contains colon(pfx)
// and the formatted list of acceptable types, so just append the mismatch
// phrase and the actual type.
out << op << sTypes.lookup(actual);
return out.str();
}
// see docstring in .h file
std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx)
{
// An undefined prototype means that any data is valid.
// An undefined slot in an array or map prototype means that any data
// may fill that slot.
if (prototype.isUndefined())
return "";
// A prototype array must match a data array with at least as many
// entries. Moreover, every prototype entry must match the
// corresponding data entry.
if (prototype.isArray())
{
if (! data.isArray())
{
return STRINGIZE(colon(pfx) << "Array" << op << sTypes.lookup(data.type()));
}
if (data.size() < prototype.size())
{
return STRINGIZE(colon(pfx) << "Array size " << prototype.size() << op
<< "Array size " << data.size());
}
for (LLSD::Integer i = 0; i < prototype.size(); ++i)
{
std::string match(llsd_matches(prototype[i], data[i], STRINGIZE('[' << i << ']')));
if (! match.empty())
{
return match;
}
}
return "";
}
// A prototype map must match a data map. Every key in the prototype
// must have a corresponding key in the data map; every value in the
// prototype must match the corresponding key's value in the data.
if (prototype.isMap())
{
if (! data.isMap())
{
return STRINGIZE(colon(pfx) << "Map" << op << sTypes.lookup(data.type()));
}
// If there are a number of keys missing from the data, it would be
// frustrating to a coder to discover them one at a time, with a big
// build each time. Enumerate all missing keys.
std::ostringstream out;
out << colon(pfx);
const char* init = "Map missing keys: ";
const char* sep = init;
for (LLSD::map_const_iterator mi = prototype.beginMap(); mi != prototype.endMap(); ++mi)
{
if (! data.has(mi->first))
{
out << sep << mi->first;
sep = ", ";
}
}
// So... are we missing any keys?
if (sep != init)
{
return out.str();
}
// Good, the data block contains all the keys required by the
// prototype. Now match the prototype entries.
for (LLSD::map_const_iterator mi2 = prototype.beginMap(); mi2 != prototype.endMap(); ++mi2)
{
std::string match(llsd_matches(mi2->second, data[mi2->first],
STRINGIZE("['" << mi2->first << "']")));
if (! match.empty())
{
return match;
}
}
return "";
}
// A String prototype can match String, Boolean, Integer, Real, UUID,
// Date and URI, because any of these can be converted to String.
if (prototype.isString())
{
static LLSD::Type accept[] =
{
LLSD::TypeBoolean,
LLSD::TypeInteger,
LLSD::TypeReal,
LLSD::TypeUUID,
LLSD::TypeDate,
LLSD::TypeURI
};
return match_types(prototype.type(),
TypeVector(boost::begin(accept), boost::end(accept)),
data.type(),
pfx);
}
// Boolean, Integer, Real match each other or String. TBD: ensure that
// a String value is numeric.
if (prototype.isBoolean() || prototype.isInteger() || prototype.isReal())
{
static LLSD::Type all[] =
{
LLSD::TypeBoolean,
LLSD::TypeInteger,
LLSD::TypeReal,
LLSD::TypeString
};
// Funny business: shuffle the set of acceptable types to include all
// but the prototype's type. Get the acceptable types in a set.
std::set<LLSD::Type> rest(boost::begin(all), boost::end(all));
// Remove the prototype's type because we pass that separately.
rest.erase(prototype.type());
return match_types(prototype.type(),
TypeVector(rest.begin(), rest.end()),
data.type(),
pfx);
}
// UUID, Date and URI match themselves or String.
if (prototype.isUUID() || prototype.isDate() || prototype.isURI())
{
static LLSD::Type accept[] =
{
LLSD::TypeString
};
return match_types(prototype.type(),
TypeVector(boost::begin(accept), boost::end(accept)),
data.type(),
pfx);
}
// We don't yet know the conversion semantics associated with any new LLSD
// data type that might be added, so until we've been extended to handle
// them, assume it's strict: the new type matches only itself. (This is
// true of Binary, which is why we don't handle that case separately.) Too
// bad LLSD doesn't define isConvertible(Type to, Type from).
return match_types(prototype.type(), TypeVector(), data.type(), pfx);
}
bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits)
{
// We're comparing strict equality of LLSD representation rather than
// performing any conversions. So if the types aren't equal, the LLSD
// values aren't equal.
if (lhs.type() != rhs.type())
{
return false;
}
// Here we know both types are equal. Now compare values.
switch (lhs.type())
{
case LLSD::TypeUndefined:
// Both are TypeUndefined. There's nothing more to know.
return true;
case LLSD::TypeReal:
// This is where the 'bits' argument comes in handy. If passed
// explicitly, it means to use is_approx_equal_fraction() to compare.
if (bits >= 0)
{
return is_approx_equal_fraction(lhs.asReal(), rhs.asReal(), bits);
}
// Otherwise we compare bit representations, and the usual caveats
// about comparing floating-point numbers apply. Omitting 'bits' when
// comparing Real values is only useful when we expect identical bit
// representation for a given Real value, e.g. for integer-valued
// Reals.
return (lhs.asReal() == rhs.asReal());
#define COMPARE_SCALAR(type) \
case LLSD::Type##type: \
/* LLSD::URI has operator!=() but not operator==() */ \
/* rely on the optimizer for all others */ \
return (! (lhs.as##type() != rhs.as##type()))
COMPARE_SCALAR(Boolean);
COMPARE_SCALAR(Integer);
COMPARE_SCALAR(String);
COMPARE_SCALAR(UUID);
COMPARE_SCALAR(Date);
COMPARE_SCALAR(URI);
COMPARE_SCALAR(Binary);
#undef COMPARE_SCALAR
case LLSD::TypeArray:
{
LLSD::array_const_iterator
lai(lhs.beginArray()), laend(lhs.endArray()),
rai(rhs.beginArray()), raend(rhs.endArray());
// Compare array elements, walking the two arrays in parallel.
for ( ; lai != laend && rai != raend; ++lai, ++rai)
{
// If any one array element is unequal, the arrays are unequal.
if (! llsd_equals(*lai, *rai, bits))
return false;
}
// Here we've reached the end of one or the other array. They're equal
// only if they're BOTH at end: that is, if they have equal length too.
return (lai == laend && rai == raend);
}
case LLSD::TypeMap:
{
// Build a set of all rhs keys.
std::set<LLSD::String> rhskeys;
for (LLSD::map_const_iterator rmi(rhs.beginMap()), rmend(rhs.endMap());
rmi != rmend; ++rmi)
{
rhskeys.insert(rmi->first);
}
// Now walk all the lhs keys.
for (LLSD::map_const_iterator lmi(lhs.beginMap()), lmend(lhs.endMap());
lmi != lmend; ++lmi)
{
// Try to erase this lhs key from the set of rhs keys. If rhs has
// no such key, the maps are unequal. erase(key) returns count of
// items erased.
if (rhskeys.erase(lmi->first) != 1)
return false;
// Both maps have the current key. Compare values.
if (! llsd_equals(lmi->second, rhs[lmi->first], bits))
return false;
}
// We've now established that all the lhs keys have equal values in
// both maps. The maps are equal unless rhs contains a superset of
// those keys.
return rhskeys.empty();
}
default:
// We expect that every possible type() value is specifically handled
// above. Failing to extend this switch to support a new LLSD type is
// an error that must be brought to the coder's attention.
LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << ", " << bits << "): "
"unknown type " << lhs.type() << LL_ENDL;
return false; // pacify the compiler
}
}

View File

@@ -35,7 +35,7 @@
#ifndef LL_LLSDUTIL_H
#define LL_LLSDUTIL_H
#include "llsd.h"
class LLSD;
// U32
LL_COMMON_API LLSD ll_sd_from_U32(const U32);
@@ -59,6 +59,7 @@ LL_COMMON_API LLSD ll_binary_from_string(const LLSD& sd);
LL_COMMON_API char* ll_print_sd(const LLSD& sd);
// Serializes sd to static buffer and returns pointer, using "pretty printing" mode.
LL_COMMON_API char* ll_pretty_print_sd_ptr(const LLSD* sd);
LL_COMMON_API char* ll_pretty_print_sd(const LLSD& sd);
//compares the structure of an LLSD to a template LLSD and stores the
@@ -73,6 +74,66 @@ LL_COMMON_API BOOL compare_llsd_with_template(
const LLSD& template_llsd,
LLSD& resultant_llsd);
/**
* Recursively determine whether a given LLSD data block "matches" another
* LLSD prototype. The returned string is empty() on success, non-empty() on
* mismatch.
*
* This function tests structure (types) rather than data values. It is
* intended for when a consumer expects an LLSD block with a particular
* structure, and must succinctly detect whether the arriving block is
* well-formed. For instance, a test of the form:
* @code
* if (! (data.has("request") && data.has("target") && data.has("modifier") ...))
* @endcode
* could instead be expressed by initializing a prototype LLSD map with the
* required keys and writing:
* @code
* if (! llsd_matches(prototype, data).empty())
* @endcode
*
* A non-empty return value is an error-message fragment intended to indicate
* to (English-speaking) developers where in the prototype structure the
* mismatch occurred.
*
* * If a slot in the prototype isUndefined(), then anything is valid at that
* place in the real object. (Passing prototype == LLSD() matches anything
* at all.)
* * An array in the prototype must match a data array at least that large.
* (Additional entries in the data array are ignored.) Every isDefined()
* entry in the prototype array must match the corresponding entry in the
* data array.
* * A map in the prototype must match a map in the data. Every key in the
* prototype map must match a corresponding key in the data map. (Additional
* keys in the data map are ignored.) Every isDefined() value in the
* prototype map must match the corresponding key's value in the data map.
* * Scalar values in the prototype are tested for @em type rather than value.
* For instance, a String in the prototype matches any String at all. In
* effect, storing an Integer at a particular place in the prototype asserts
* that the caller intends to apply asInteger() to the corresponding slot in
* the data.
* * A String in the prototype matches String, Boolean, Integer, Real, UUID,
* Date and URI, because asString() applied to any of these produces a
* meaningful result.
* * Similarly, a Boolean, Integer or Real in the prototype can match any of
* Boolean, Integer or Real in the data -- or even String.
* * UUID matches UUID or String.
* * Date matches Date or String.
* * URI matches URI or String.
* * Binary in the prototype matches only Binary in the data.
*
* @TODO: when a Boolean, Integer or Real in the prototype matches a String in
* the data, we should examine the String @em value to ensure it can be
* meaningfully converted to the requested type. The same goes for UUID, Date
* and URI.
*/
LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx="");
/// Deep equality. If you want to compare LLSD::Real values for approximate
/// equality rather than bitwise equality, pass @a bits as for
/// is_approx_equal_fraction().
LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits=-1);
// Simple function to copy data out of input & output iterators if
// there is no need for casting.
template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
@@ -85,4 +146,283 @@ template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
return dest;
}
/*****************************************************************************
* LLSDArray
*****************************************************************************/
/**
* Construct an LLSD::Array inline, with implicit conversion to LLSD. Usage:
*
* @code
* void somefunc(const LLSD&);
* ...
* somefunc(LLSDArray("text")(17)(3.14));
* @endcode
*
* For completeness, LLSDArray() with no args constructs an empty array, so
* <tt>LLSDArray()("text")(17)(3.14)</tt> produces an array equivalent to the
* above. But for most purposes, LLSD() is already equivalent to an empty
* array, and if you explicitly want an empty isArray(), there's
* LLSD::emptyArray(). However, supporting a no-args LLSDArray() constructor
* follows the principle of least astonishment.
*/
class LLSDArray
{
public:
LLSDArray():
_data(LLSD::emptyArray())
{}
/**
* Need an explicit copy constructor. Consider the following:
*
* @code
* LLSD array_of_arrays(LLSDArray(LLSDArray(17)(34))
* (LLSDArray("x")("y")));
* @endcode
*
* The coder intends to construct [[17, 34], ["x", "y"]].
*
* With the compiler's implicit copy constructor, s/he gets instead
* [17, 34, ["x", "y"]].
*
* The expression LLSDArray(17)(34) constructs an LLSDArray with those two
* values. The reader assumes it should be converted to LLSD, as we always
* want with LLSDArray, before passing it to the @em outer LLSDArray
* constructor! This copy constructor makes that happen.
*/
LLSDArray(const LLSDArray& inner):
_data(LLSD::emptyArray())
{
_data.append(inner);
}
LLSDArray(const LLSD& value):
_data(LLSD::emptyArray())
{
_data.append(value);
}
LLSDArray& operator()(const LLSD& value)
{
_data.append(value);
return *this;
}
operator LLSD() const { return _data; }
LLSD get() const { return _data; }
private:
LLSD _data;
};
/*****************************************************************************
* LLSDMap
*****************************************************************************/
/**
* Construct an LLSD::Map inline, with implicit conversion to LLSD. Usage:
*
* @code
* void somefunc(const LLSD&);
* ...
* somefunc(LLSDMap("alpha", "abc")("number", 17)("pi", 3.14));
* @endcode
*
* For completeness, LLSDMap() with no args constructs an empty map, so
* <tt>LLSDMap()("alpha", "abc")("number", 17)("pi", 3.14)</tt> produces a map
* equivalent to the above. But for most purposes, LLSD() is already
* equivalent to an empty map, and if you explicitly want an empty isMap(),
* there's LLSD::emptyMap(). However, supporting a no-args LLSDMap()
* constructor follows the principle of least astonishment.
*/
class LLSDMap
{
public:
LLSDMap():
_data(LLSD::emptyMap())
{}
LLSDMap(const LLSD::String& key, const LLSD& value):
_data(LLSD::emptyMap())
{
_data[key] = value;
}
LLSDMap& operator()(const LLSD::String& key, const LLSD& value)
{
_data[key] = value;
return *this;
}
operator LLSD() const { return _data; }
LLSD get() const { return _data; }
private:
LLSD _data;
};
/*****************************************************************************
* LLSDParam
*****************************************************************************/
/**
* LLSDParam is a customization point for passing LLSD values to function
* parameters of more or less arbitrary type. LLSD provides a small set of
* native conversions; but if a generic algorithm explicitly constructs an
* LLSDParam object in the function's argument list, a consumer can provide
* LLSDParam specializations to support more different parameter types than
* LLSD's native conversions.
*
* Usage:
*
* @code
* void somefunc(const paramtype&);
* ...
* somefunc(..., LLSDParam<paramtype>(someLLSD), ...);
* @endcode
*/
template <typename T>
class LLSDParam
{
public:
/**
* Default implementation converts to T on construction, saves converted
* value for later retrieval
*/
LLSDParam(const LLSD& value):
_value(value)
{}
operator T() const { return _value; }
private:
T _value;
};
/**
* Turns out that several target types could accept an LLSD param using any of
* a few different conversions, e.g. LLUUID's constructor can accept LLUUID or
* std::string. Therefore, the compiler can't decide which LLSD conversion
* operator to choose, even though to us it seems obvious. But that's okay, we
* can specialize LLSDParam for such target types, explicitly specifying the
* desired conversion -- that's part of what LLSDParam is all about. Turns out
* we have to do that enough to make it worthwhile generalizing. Use a macro
* because I need to specify one of the asReal, etc., explicit conversion
* methods as well as a type. If I'm overlooking a clever way to implement
* that using a template instead, feel free to reimplement.
*/
#define LLSDParam_for(T, AS) \
template <> \
class LLSDParam<T> \
{ \
public: \
LLSDParam(const LLSD& value): \
_value(value.AS()) \
{} \
\
operator T() const { return _value; } \
\
private: \
T _value; \
}
LLSDParam_for(float, asReal);
LLSDParam_for(LLUUID, asUUID);
LLSDParam_for(LLDate, asDate);
LLSDParam_for(LLURI, asURI);
LLSDParam_for(LLSD::Binary, asBinary);
/**
* LLSDParam<const char*> is an example of the kind of conversion you can
* support with LLSDParam beyond native LLSD conversions. Normally you can't
* pass an LLSD object to a function accepting const char* -- but you can
* safely pass an LLSDParam<const char*>(yourLLSD).
*/
template <>
class LLSDParam<const char*>
{
private:
// The difference here is that we store a std::string rather than a const
// char*. It's important that the LLSDParam object own the std::string.
std::string _value;
// We don't bother storing the incoming LLSD object, but we do have to
// distinguish whether _value is an empty string because the LLSD object
// contains an empty string or because it's isUndefined().
bool _undefined;
public:
LLSDParam(const LLSD& value):
_value(value),
_undefined(value.isUndefined())
{}
// The const char* we retrieve is for storage owned by our _value member.
// That's how we guarantee that the const char* is valid for the lifetime
// of this LLSDParam object. Constructing your LLSDParam in the argument
// list should ensure that the LLSDParam object will persist for the
// duration of the function call.
operator const char*() const
{
if (_undefined)
{
// By default, an isUndefined() LLSD object's asString() method
// will produce an empty string. But for a function accepting
// const char*, it's often important to be able to pass NULL, and
// isUndefined() seems like the best way. If you want to pass an
// empty string, you can still pass LLSD(""). Without this special
// case, though, no LLSD value could pass NULL.
return NULL;
}
return _value.c_str();
}
};
namespace llsd
{
/*****************************************************************************
* BOOST_FOREACH() helpers for LLSD
*****************************************************************************/
/// Usage: BOOST_FOREACH(LLSD item, inArray(someLLSDarray)) { ... }
class inArray
{
public:
inArray(const LLSD& array):
_array(array)
{}
typedef LLSD::array_const_iterator const_iterator;
typedef LLSD::array_iterator iterator;
iterator begin() { return _array.beginArray(); }
iterator end() { return _array.endArray(); }
const_iterator begin() const { return _array.beginArray(); }
const_iterator end() const { return _array.endArray(); }
private:
LLSD _array;
};
/// MapEntry is what you get from dereferencing an LLSD::map_[const_]iterator.
typedef std::map<LLSD::String, LLSD>::value_type MapEntry;
/// Usage: BOOST_FOREACH([const] MapEntry& e, inMap(someLLSDmap)) { ... }
class inMap
{
public:
inMap(const LLSD& map):
_map(map)
{}
typedef LLSD::map_const_iterator const_iterator;
typedef LLSD::map_iterator iterator;
iterator begin() { return _map.beginMap(); }
iterator end() { return _map.endMap(); }
const_iterator begin() const { return _map.beginMap(); }
const_iterator end() const { return _map.endMap(); }
private:
LLSD _map;
};
} // namespace llsd
#endif // LL_LLSDUTIL_H

View File

@@ -0,0 +1,32 @@
/**
* @file llsingleton.cpp
* @author Brad Kittenbrink
*
* $LicenseInfo:firstyear=2009&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 "linden_common.h"
#include "llsingleton.h"
std::map<std::string, void *> * LLSingletonRegistry::sSingletonMap = NULL;

View File

@@ -0,0 +1,225 @@
/**
* @file llsingleton.h
*
* $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 LLSINGLETON_H
#define LLSINGLETON_H
#include "llerror.h" // *TODO: eliminate this
#include <typeinfo>
#include <boost/noncopyable.hpp>
/// @brief A global registry of all singletons to prevent duplicate allocations
/// across shared library boundaries
class LL_COMMON_API LLSingletonRegistry {
private:
typedef std::map<std::string, void *> TypeMap;
static TypeMap * sSingletonMap;
static void checkInit()
{
if(sSingletonMap == NULL)
{
sSingletonMap = new TypeMap();
}
}
public:
template<typename T> static void * & get()
{
std::string name(typeid(T).name());
checkInit();
// the first entry of the pair returned by insert will be either the existing
// iterator matching our key, or the newly inserted NULL initialized entry
// see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
TypeMap::iterator result =
sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first;
return result->second;
}
};
// LLSingleton implements the getInstance() method part of the Singleton
// pattern. It can't make the derived class constructors protected, though, so
// you have to do that yourself.
//
// There are two ways to use LLSingleton. The first way is to inherit from it
// while using the typename that you'd like to be static as the template
// parameter, like so:
//
// class Foo: public LLSingleton<Foo>{};
//
// Foo& instance = Foo::instance();
//
// The second way is to use the singleton class directly, without inheritance:
//
// typedef LLSingleton<Foo> FooSingleton;
//
// Foo& instance = FooSingleton::instance();
//
// In this case, the class being managed as a singleton needs to provide an
// initSingleton() method since the LLSingleton virtual method won't be
// available
//
// As currently written, it is not thread-safe.
template <typename DERIVED_TYPE>
class LLSingleton : private boost::noncopyable
{
private:
typedef enum e_init_state
{
UNINITIALIZED,
CONSTRUCTING,
INITIALIZING,
INITIALIZED,
DELETED
} EInitState;
// stores pointer to singleton instance
// and tracks initialization state of singleton
struct SingletonInstanceData
{
EInitState mInitState;
DERIVED_TYPE* mSingletonInstance;
SingletonInstanceData()
: mSingletonInstance(NULL),
mInitState(UNINITIALIZED)
{}
~SingletonInstanceData()
{
if (mInitState != DELETED)
{
deleteSingleton();
}
}
};
public:
virtual ~LLSingleton()
{
SingletonInstanceData& data = getData();
data.mSingletonInstance = NULL;
data.mInitState = DELETED;
}
/**
* @brief Immediately delete the singleton.
*
* A subsequent call to LLProxy::getInstance() will construct a new
* instance of the class.
*
* LLSingletons are normally destroyed after main() has exited and the C++
* runtime is cleaning up statically-constructed objects. Some classes
* derived from LLSingleton have objects that are part of a runtime system
* that is terminated before main() exits. Calling the destructor of those
* objects after the termination of their respective systems can cause
* crashes and other problems during termination of the project. Using this
* method to destroy the singleton early can prevent these crashes.
*
* An example where this is needed is for a LLSingleton that has an APR
* object as a member that makes APR calls on destruction. The APR system is
* shut down explicitly before main() exits. This causes a crash on exit.
* Using this method before the call to apr_terminate() and NOT calling
* getInstance() again will prevent the crash.
*/
static void deleteSingleton()
{
delete getData().mSingletonInstance;
getData().mSingletonInstance = NULL;
getData().mInitState = DELETED;
}
static SingletonInstanceData& getData()
{
// this is static to cache the lookup results
static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>();
// *TODO - look into making this threadsafe
if(NULL == registry)
{
static SingletonInstanceData data;
registry = &data;
}
return *static_cast<SingletonInstanceData *>(registry);
}
static DERIVED_TYPE* getInstance()
{
SingletonInstanceData& data = getData();
if (data.mInitState == CONSTRUCTING)
{
llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl;
}
if (data.mInitState == DELETED)
{
llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl;
}
if (!data.mSingletonInstance)
{
data.mInitState = CONSTRUCTING;
data.mSingletonInstance = new DERIVED_TYPE();
data.mInitState = INITIALIZING;
data.mSingletonInstance->initSingleton();
data.mInitState = INITIALIZED;
}
return data.mSingletonInstance;
}
// Reference version of getInstance()
// Preferred over getInstance() as it disallows checking for NULL
static DERIVED_TYPE& instance()
{
return *getInstance();
}
// Has this singleton been created uet?
// Use this to avoid accessing singletons before the can safely be constructed
static bool instanceExists()
{
return getData().mInitState == INITIALIZED;
}
// Has this singleton already been deleted?
// Use this to avoid accessing singletons from a static object's destructor
static bool destroyed()
{
return getData().mInitState == DELETED;
}
private:
virtual void initSingleton() {}
};
#endif

View File

@@ -43,9 +43,10 @@
// statics
BOOL LLPerfBlock::sStatsEnabled = FALSE; // Flag for detailed information
S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded
LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects
std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
LLStat::stat_map_t LLStat::sStatList;
//------------------------------------------------------------------------
// Live config file to trigger stats logging
@@ -129,6 +130,7 @@ bool LLStatsConfigFile::loadFile()
F32 duration = 0.f;
F32 interval = 0.f;
S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;
const char * w = "duration";
if (stats_config.has(w))
@@ -140,8 +142,18 @@ bool LLStatsConfigFile::loadFile()
{
interval = (F32)stats_config[w].asReal();
}
w = "flags";
if (stats_config.has(w))
{
flags = (S32)stats_config[w].asInteger();
if (flags == LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS &&
duration > 0)
{ // No flags passed in, but have a duration, so reset to basic stats
flags = LLPerfBlock::LLSTATS_BASIC_STATS;
}
}
mStatsp->setReportPerformanceDuration( duration );
mStatsp->setReportPerformanceDuration( duration, flags );
mStatsp->setReportPerformanceInterval( interval );
if ( duration > 0 )
@@ -253,13 +265,14 @@ void LLPerfStats::dumpIntervalPerformanceStats()
}
}
// Set length of performance stat recording
void LLPerfStats::setReportPerformanceDuration( F32 seconds )
// Set length of performance stat recording.
// If turning stats on, caller must provide flags
void LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ )
{
if ( seconds <= 0.f )
{
mReportPerformanceStatEnd = 0.0;
LLPerfBlock::setStatsEnabled( FALSE );
LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off
mFrameStatsFile.close();
LLPerfBlock::clearDynamicStats();
}
@@ -268,8 +281,8 @@ void LLPerfStats::setReportPerformanceDuration( F32 seconds )
mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
// Clear failure flag to try and create the log file once
mFrameStatsFileFailure = FALSE;
LLPerfBlock::setStatsEnabled( TRUE );
mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
LLPerfBlock::setStatsFlags(flags);
}
}
@@ -611,11 +624,26 @@ LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicSta
}
}
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key.
// These are also turned on or off via the switch passed in
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat(NULL), mDynamicStat(NULL)
// Use this constructor for normal, optional LLPerfBlock time slices
LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)
{
if (!sStatsEnabled) return;
if ((sStatsFlags & LLSTATS_BASIC_STATS) == 0)
{ // These are off unless the base set is enabled
return;
}
initDynamicStat(key);
}
// Use this constructor for dynamically created LLPerfBlock time slices
// that are only enabled by specific control flags
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2, S32 flags ) : mPredefinedStat(NULL), mDynamicStat(NULL)
{
if ((sStatsFlags & flags) == 0)
{
return;
}
if (NULL == key2 || strlen(key2) == 0)
{
@@ -629,10 +657,12 @@ LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat
}
}
// Set up the result data map if dynamic stats are enabled
void LLPerfBlock::initDynamicStat(const std::string& key)
{
// Early exit if dynamic stats aren't enabled.
if (!sStatsEnabled) return;
if (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS)
return;
mLastPath = sCurrentStatPath; // Save and restore current path
sCurrentStatPath += "/" + key; // Add key to current path
@@ -713,7 +743,7 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
}
}
else
{ // WTF? Shouldn't have a NULL pointer in the map.
{ // Shouldn't have a NULL pointer in the map.
llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
}
}
@@ -725,14 +755,12 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
LLTimer LLStat::sTimer;
LLFrameTimer LLStat::sFrameTimer;
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
void LLStat::init()
{
llassert(num_bins > 0);
mUseFrameTimer = use_frame_timer;
llassert(mNumBins > 0);
mNumValues = 0;
mLastValue = 0.f;
mLastTime = 0.f;
mNumBins = num_bins;
mCurBin = (mNumBins-1);
mNextBin = 0;
mBins = new F32[mNumBins];
@@ -746,6 +774,29 @@ LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
mTime[i] = 0.0;
mDT[i] = 0.f;
}
if (!mName.empty())
{
stat_map_t::iterator iter = sStatList.find(mName);
if (iter != sStatList.end())
llwarns << "LLStat with duplicate name: " << mName << llendl;
sStatList.insert(std::make_pair(mName, this));
}
}
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
: mUseFrameTimer(use_frame_timer),
mNumBins(num_bins)
{
init();
}
LLStat::LLStat(std::string name, U32 num_bins, BOOL use_frame_timer)
: mUseFrameTimer(use_frame_timer),
mNumBins(num_bins),
mName(name)
{
init();
}
LLStat::~LLStat()
@@ -754,6 +805,15 @@ LLStat::~LLStat()
delete[] mBeginTime;
delete[] mTime;
delete[] mDT;
if (!mName.empty())
{
// handle multiple entries with the same name
stat_map_t::iterator iter = sStatList.find(mName);
while (iter != sStatList.end() && iter->second != this)
++iter;
sStatList.erase(iter);
}
}
void LLStat::reset()

View File

@@ -192,14 +192,23 @@ public:
// Use this constructor for pre-defined LLStatTime objects
LLPerfBlock(LLStatTime* stat);
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key
LLPerfBlock( const char* key1, const char* key2 = NULL);
// Use this constructor for normal, optional LLPerfBlock time slices
LLPerfBlock( const char* key );
// Use this constructor for dynamically created LLPerfBlock time slices
// that are only enabled by specific control flags
LLPerfBlock( const char* key1, const char* key2, S32 flags = LLSTATS_BASIC_STATS );
~LLPerfBlock();
static void setStatsEnabled( BOOL enable ) { sStatsEnabled = enable; };
static S32 getStatsEnabled() { return sStatsEnabled; };
enum
{ // Stats bitfield flags
LLSTATS_NO_OPTIONAL_STATS = 0x00, // No optional stats gathering, just pre-defined LLStatTime objects
LLSTATS_BASIC_STATS = 0x01, // Gather basic optional runtime stats
LLSTATS_SCRIPT_FUNCTIONS = 0x02, // Include LSL function calls
};
static void setStatsFlags( S32 flags ) { sStatsFlags = flags; };
static S32 getStatsFlags() { return sStatsFlags; };
static void clearDynamicStats(); // Reset maps to clear out dynamic objects
static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin
@@ -213,7 +222,7 @@ private:
LLStatTime * mPredefinedStat; // LLStatTime object to get data
StatEntry * mDynamicStat; // StatEntryobject to get data
static BOOL sStatsEnabled; // Normally FALSE
static S32 sStatsFlags; // Control what is being recorded
static stat_map_t sStatMap; // Map full path string to LLStatTime objects
static std::string sCurrentStatPath; // Something like "frame/physics/physics step"
};
@@ -236,7 +245,7 @@ public:
BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; };
void setReportPerformanceDuration( F32 seconds );
void setReportPerformanceDuration( F32 seconds, S32 flags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS );
void setProcessName(const std::string& process_name) { mProcessName = process_name; }
void setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
@@ -258,8 +267,15 @@ private:
// ----------------------------------------------------------------------------
class LL_COMMON_API LLStat
{
private:
typedef std::multimap<std::string, LLStat*> stat_map_t;
static stat_map_t sStatList;
void init();
public:
LLStat(const U32 num_bins = 32, BOOL use_frame_timer = FALSE);
LLStat(U32 num_bins = 32, BOOL use_frame_timer = FALSE);
LLStat(std::string name, U32 num_bins = 32, BOOL use_frame_timer = FALSE);
~LLStat();
void reset();
@@ -322,8 +338,22 @@ private:
F32 *mDT;
S32 mCurBin;
S32 mNextBin;
std::string mName;
static LLTimer sTimer;
static LLFrameTimer sFrameTimer;
public:
static LLStat* getStat(const std::string& name)
{
// return the first stat that matches 'name'
stat_map_t::iterator iter = sStatList.find(name);
if (iter != sStatList.end())
return iter->second;
else
return NULL;
}
};
#endif // LL_STAT_

View File

@@ -45,7 +45,7 @@
// skips spaces and tabs
bool skip_whitespace(std::istream& input_stream)
{
char c = input_stream.peek();
int c = input_stream.peek();
while (('\t' == c || ' ' == c) && input_stream.good())
{
input_stream.get();
@@ -57,7 +57,7 @@ bool skip_whitespace(std::istream& input_stream)
// skips whitespace, newlines, and carriage returns
bool skip_emptyspace(std::istream& input_stream)
{
char c = input_stream.peek();
int c = input_stream.peek();
while ( input_stream.good()
&& ('\t' == c || ' ' == c || '\n' == c || '\r' == c) )
{
@@ -72,7 +72,7 @@ bool skip_comments_and_emptyspace(std::istream& input_stream)
{
while (skip_emptyspace(input_stream))
{
char c = input_stream.peek();
int c = input_stream.peek();
if ('#' == c )
{
while ('\n' != c && input_stream.good())
@@ -90,7 +90,7 @@ bool skip_comments_and_emptyspace(std::istream& input_stream)
bool skip_line(std::istream& input_stream)
{
char c;
int c;
do
{
c = input_stream.get();
@@ -100,7 +100,7 @@ bool skip_line(std::istream& input_stream)
bool skip_to_next_word(std::istream& input_stream)
{
char c = input_stream.peek();
int c = input_stream.peek();
while ( input_stream.good()
&& ( (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
@@ -132,7 +132,7 @@ bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream
while (input_stream.good())
{
skip_emptyspace(input_stream);
char c = input_stream.get();
int c = input_stream.get();
if (keyword[0] != c)
{
skip_line(input_stream);
@@ -181,7 +181,7 @@ bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stre
while (input_stream.good())
{
skip_emptyspace(input_stream);
char c = input_stream.get();
int c = input_stream.get();
if (keyword[0] != c)
{
skip_line(input_stream);
@@ -229,7 +229,7 @@ bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stre
bool get_word(std::string& output_string, std::istream& input_stream)
{
skip_emptyspace(input_stream);
char c = input_stream.peek();
int c = input_stream.peek();
while ( !isspace(c)
&& '\n' != c
&& '\r' != c
@@ -246,7 +246,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
{
skip_emptyspace(input_stream);
int char_count = 0;
char c = input_stream.peek();
int c = input_stream.peek();
while (!isspace(c)
&& '\n' != c
&& '\r' != c
@@ -265,7 +265,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
bool get_line(std::string& output_string, std::istream& input_stream)
{
output_string.clear();
char c = input_stream.get();
int c = input_stream.get();
while (input_stream.good())
{
output_string += c;
@@ -285,7 +285,7 @@ bool get_line(std::string& output_string, std::istream& input_stream, int n)
{
output_string.clear();
int char_count = 0;
char c = input_stream.get();
int c = input_stream.get();
while (input_stream.good() && char_count < n)
{
char_count++;

View File

@@ -42,14 +42,17 @@ template <class Object> class LLStrider
U8* mBytep;
};
U32 mSkip;
U32 mTypeSize;
public:
LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); }
LLStrider() { mObjectp = NULL; mTypeSize = mSkip = sizeof(Object); }
~LLStrider() { }
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}
void setTypeSize (S32 typeBytes){ mTypeSize = (typeBytes ? typeBytes : sizeof(Object)); }
bool isStrided() const { return mTypeSize != mSkip; }
void skip(const U32 index) { mBytep += mSkip*index;}
U32 getSkip() const { return mSkip; }
Object* get() { return mObjectp; }
@@ -58,6 +61,71 @@ public:
Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; }
Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; }
Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); }
void assignArray(U8* __restrict source, const size_t elem_size, const size_t elem_count)
{
llassert_always(sizeof(Object) <= elem_size);
U8* __restrict dest = mBytep; //refer to dest instead of mBytep to benefit from __restrict hint
const U32 bytes = elem_size * elem_count; //total bytes to copy from source to dest
//stride == sizeof(element) implies entire buffer is unstrided and thus memcpy-able, provided source buffer elements match in size.
//Because LLStrider is often passed an LLVector3 even if the reprensentation is LLVector4 in the vertex buffer, mTypeSize is set to
//the TRUE vbo datatype size via VertexBufferStrider::get
if(!isStrided() && mTypeSize == elem_size)
{
if(bytes >= sizeof(LLVector4) * 4) //Should be able to pull at least 3 16byte blocks from this. Smaller isn't really beneficial.
{
U8* __restrict aligned_source = LL_NEXT_ALIGNED_ADDRESS(source);
U8* __restrict aligned_dest = LL_NEXT_ALIGNED_ADDRESS(dest);
const U32 source_offset = aligned_source - source; //Offset to first aligned location in source buffer.
const U32 dest_offset = aligned_dest - dest; //Offset to first aligned location in dest buffer.
llassert_always(source_offset < 16);
llassert_always(dest_offset < 16);
if(source_offset == dest_offset) //delta to aligned location matches between source and destination! _mm_*_ps should be viable.
{
const U32 end_offset = (bytes - source_offset) % sizeof(LLVector4); //buffers may not neatly end on a 16byte alignment boundary.
const U32 aligned_bytes = bytes - source_offset - end_offset; //how many bytes to copy from aligned start to aligned end.
llassert_always(aligned_bytes > 0);
if(source_offset) //memcpy up to the aligned location if needed
memcpy(dest,source,source_offset);
LLVector4a::memcpyNonAliased16((F32*) aligned_dest, (F32*) aligned_source, aligned_bytes);
if(end_offset) //memcpy to the very end if needed.
memcpy(aligned_dest+aligned_bytes,aligned_source+aligned_bytes,end_offset);
}
else //buffers non-uniformly offset from aligned location. Using _mm_*u_ps.
{
U32 end = bytes/sizeof(LLVector4); //sizeof(LLVector4) = 16 bytes = 128 bits
llassert_always(end > 0);
__m128* dst = (__m128*) dest;
__m128* src = (__m128*) source;
for (U32 i = 0; i < end; i++) //copy 128bit chunks
{
__m128 res = _mm_loadu_ps((F32*)&src[i]);
_mm_storeu_ps((F32*)&dst[i], res);
}
end*=16;//Convert to real byte offset
if(end < bytes) //just memcopy the rest
memcpy(dest+end,source+end,bytes-end);
}
}
else //Too small. just do a simple memcpy.
memcpy(dest,source,bytes);
}
else
{
for(U32 i=0;i<elem_count;i++)
{
memcpy(dest,source,sizeof(Object));
dest+=mSkip;
source+=elem_size;
}
}
}
};
#endif // LL_LLSTRIDER_H

View File

@@ -957,13 +957,18 @@ LLStringUtil::size_type LLStringUtil::getSubstitution(const std::string& instr,
{
const std::string delims (",");
// Find the first ]
size_type pos2 = instr.find(']', start);
// Find the first [
size_type pos1 = instr.find('[', start);
if (pos1 == std::string::npos)
return std::string::npos;
//Find the first ] after the initial [
size_type pos2 = instr.find(']', pos1);
if (pos2 == std::string::npos)
return std::string::npos;
// Find the last [ before ]
size_type pos1 = instr.find_last_of('[', pos2-1);
// Find the last [ before ] in case of nested [[]]
pos1 = instr.find_last_of('[', pos2-1);
if (pos1 == std::string::npos || pos1 < start)
return std::string::npos;

View File

@@ -62,6 +62,21 @@
//
//----------------------------------------------------------------------------
#if !LL_DARWIN
U32 ll_thread_local local_thread_ID = 0;
#endif
U32 LLThread::sIDIter = 0;
LL_COMMON_API void assert_main_thread()
{
static U32 s_thread_id = LLThread::currentID();
if (LLThread::currentID() != s_thread_id)
{
llerrs << "Illegal execution outside main thread." << llendl;
}
}
//
// Handed to the APR thread creation function
//
@@ -73,31 +88,43 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
LLThread *threadp = (LLThread *)datap;
// Set thread state to running
threadp->mStatus = RUNNING;
#if !LL_DARWIN
local_thread_ID = threadp->mID;
#endif
// Create a thread local data.
AIThreadLocalData::create(threadp);
LLThreadLocalData::create(threadp);
// Run the user supplied function
threadp->run();
llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl;
// Setting mStatus to STOPPED is done non-thread-safe, so it's
// possible that the thread is deleted by another thread at
// the moment it happens... therefore make a copy here.
char const* volatile name = threadp->mName.c_str();
// We're done with the run function, this thread is done executing now.
threadp->mStatus = STOPPED;
// Only now print this info [doing that before setting mStatus
// to STOPPED makes it much more likely that another thread runs
// after the LLCurl::Multi::run() function exits and we actually
// change this variable (which really SHOULD have been inside
// the critical area of the mSignal lock)].
llinfos << "LLThread::staticRun() Exiting: " << name << llendl;
return NULL;
}
LLThread::LLThread(std::string const& name) :
mPaused(FALSE),
mPaused(false),
mName(name),
mAPRThreadp(NULL),
mStatus(STOPPED),
mThreadLocalData(NULL)
{
mID = ++sIDIter;
mRunCondition = new LLCondition;
}
@@ -119,7 +146,7 @@ void LLThread::shutdown()
// First, set the flag that indicates that we're ready to die
setQuitting();
llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl;
llinfos << "LLThread::shutdown() Killing thread " << mName << " Status: " << mStatus << llendl;
// Now wait a bit for the thread to exit
// It's unclear whether I should even bother doing this - this destructor
// should netver get called unless we're already stopped, really...
@@ -142,20 +169,38 @@ void LLThread::shutdown()
{
// This thread just wouldn't stop, even though we gave it time
llwarns << "LLThread::shutdown() exiting thread before clean exit!" << llendl;
// Put a stake in its heart.
apr_thread_exit(mAPRThreadp, -1);
return;
}
mAPRThreadp = NULL;
}
delete mRunCondition;
mRunCondition = 0;
}
void LLThread::start()
{
apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, tldata().mRootPool());
llassert(isStopped());
// Set thread state to running
mStatus = RUNNING;
// We won't bother joining
apr_thread_detach(mAPRThreadp);
apr_status_t status =
apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, tldata().mRootPool());
if(status == APR_SUCCESS)
{
// We won't bother joining
apr_thread_detach(mAPRThreadp);
}
else
{
mStatus = STOPPED;
llwarns << "failed to start thread " << mName << llendl;
ll_apr_warn_status(status);
}
}
//============================================================================
@@ -168,7 +213,7 @@ 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
mPaused = true; // Does not need to be atomic since this is only set/unset from the main thread
}
}
@@ -176,7 +221,7 @@ void LLThread::unpause()
{
if (mPaused)
{
mPaused = 0;
mPaused = false;
}
wake(); // wake up the thread if necessary
@@ -256,14 +301,14 @@ void LLThread::wakeLocked()
#ifdef SHOW_ASSERT
// This allows the use of llassert(is_main_thread()) to assure the current thread is the main thread.
static apr_os_thread_t main_thread_id;
LL_COMMON_API bool is_main_thread() { return apr_os_thread_equal(main_thread_id, apr_os_thread_current()); }
LL_COMMON_API bool is_main_thread(void) { return apr_os_thread_equal(main_thread_id, apr_os_thread_current()); }
#endif
// The thread private handle to access the AIThreadLocalData instance.
apr_threadkey_t* AIThreadLocalData::sThreadLocalDataKey;
// The thread private handle to access the LLThreadLocalData instance.
apr_threadkey_t* LLThreadLocalData::sThreadLocalDataKey;
//static
void AIThreadLocalData::init(void)
void LLThreadLocalData::init(void)
{
// Only do this once.
if (sThreadLocalDataKey)
@@ -271,13 +316,13 @@ void AIThreadLocalData::init(void)
return;
}
apr_status_t status = apr_threadkey_private_create(&sThreadLocalDataKey, &AIThreadLocalData::destroy, AIAPRRootPool::get()());
apr_status_t status = apr_threadkey_private_create(&sThreadLocalDataKey, &LLThreadLocalData::destroy, LLAPRRootPool::get()());
ll_apr_assert_status(status); // Or out of memory, or system-imposed limit on the
// total number of keys per process {PTHREAD_KEYS_MAX}
// total number of keys per process {PTHREAD_KEYS_MAX}
// has been exceeded.
// Create the thread-local data for the main thread (this function is called by the main thread).
AIThreadLocalData::create(NULL);
LLThreadLocalData::create(NULL);
#ifdef SHOW_ASSERT
// This function is called by the main thread.
@@ -287,15 +332,15 @@ void AIThreadLocalData::init(void)
// This is called once for every thread when the thread is destructed.
//static
void AIThreadLocalData::destroy(void* thread_local_data)
void LLThreadLocalData::destroy(void* thread_local_data)
{
delete reinterpret_cast<AIThreadLocalData*>(thread_local_data);
delete static_cast<LLThreadLocalData*>(thread_local_data);
}
//static
void AIThreadLocalData::create(LLThread* threadp)
void LLThreadLocalData::create(LLThread* threadp)
{
AIThreadLocalData* new_tld = new AIThreadLocalData;
LLThreadLocalData* new_tld = new LLThreadLocalData;
if (threadp)
{
threadp->mThreadLocalData = new_tld;
@@ -305,36 +350,27 @@ void AIThreadLocalData::create(LLThread* threadp)
}
//static
AIThreadLocalData& AIThreadLocalData::tldata(void)
LLThreadLocalData& LLThreadLocalData::tldata(void)
{
if (!sThreadLocalDataKey)
AIThreadLocalData::init();
{
LLThreadLocalData::init();
}
void* data;
apr_status_t status = apr_threadkey_private_get(&data, sThreadLocalDataKey);
llassert_always(status == APR_SUCCESS);
return *static_cast<AIThreadLocalData*>(data);
return *static_cast<LLThreadLocalData*>(data);
}
//============================================================================
bool LLMutexBase::isLocked()
{
if (!tryLock())
{
return true;
}
apr_thread_mutex_unlock(mAPRMutexp);
return false;
}
//============================================================================
LLCondition::LLCondition(AIAPRPool& parent) : LLMutex(parent)
LLCondition::LLCondition(LLAPRPool& parent) : LLMutex(parent)
{
apr_thread_cond_create(&mAPRCondp, mPool());
}
LLCondition::~LLCondition()
{
apr_thread_cond_destroy(mAPRCondp);
@@ -357,7 +393,45 @@ void LLCondition::broadcast()
}
//============================================================================
LLMutexBase::LLMutexBase() :
mLockingThread(NO_THREAD),
mCount(0)
{
}
void LLMutexBase::lock()
{
#if LL_DARWIN
if (mLockingThread == LLThread::currentID())
#else
if (mLockingThread == local_thread_ID)
#endif
{ //redundant lock
mCount++;
return;
}
apr_thread_mutex_lock(mAPRMutexp);
#if LL_DARWIN
mLockingThread = LLThread::currentID();
#else
mLockingThread = local_thread_ID;
#endif
}
void LLMutexBase::unlock()
{
if (mCount > 0)
{ //not the root unlock
mCount--;
return;
}
mLockingThread = NO_THREAD;
apr_thread_mutex_unlock(mAPRMutexp);
}
//----------------------------------------------------------------------------
//static

View File

@@ -33,12 +33,11 @@
#ifndef LL_LLTHREAD_H
#define LL_LLTHREAD_H
#include "llapr.h"
#include "llapp.h"
#include "llapr.h"
#include "llmemory.h"
#include "apr_thread_cond.h"
#include "aiaprpool.h"
#include "llaprpool.h"
#ifdef SHOW_ASSERT
extern LL_COMMON_API bool is_main_thread(void);
@@ -48,24 +47,33 @@ class LLThread;
class LLMutex;
class LLCondition;
class LL_COMMON_API AIThreadLocalData
#if LL_WINDOWS
#define ll_thread_local __declspec(thread)
#else
#define ll_thread_local __thread
#endif
class LL_COMMON_API LLThreadLocalData
{
private:
static apr_threadkey_t* sThreadLocalDataKey;
public:
// Thread-local memory pool.
AIAPRRootPool mRootPool;
AIVolatileAPRPool mVolatileAPRPool;
LLAPRRootPool mRootPool;
LLVolatileAPRPool mVolatileAPRPool;
static void init(void);
static void destroy(void* thread_local_data);
static void create(LLThread* pthread);
static AIThreadLocalData& tldata(void);
static LLThreadLocalData& tldata(void);
};
class LL_COMMON_API LLThread
{
private:
static U32 sIDIter;
public:
typedef enum e_thread_status
{
@@ -89,7 +97,7 @@ public:
// Called from MAIN THREAD.
void pause();
void unpause();
bool isPaused() { return isStopped() || mPaused == TRUE; }
bool isPaused() { return isStopped() || mPaused; }
// Cause the thread to wake up and check its condition
void wake();
@@ -104,10 +112,12 @@ public:
void start(void);
// Return thread-local data for the current thread.
static AIThreadLocalData& tldata(void) { return AIThreadLocalData::tldata(); }
static LLThreadLocalData& tldata(void) { return LLThreadLocalData::tldata(); }
U32 getID() const { return mID; }
private:
BOOL mPaused;
bool mPaused;
// static function passed to APR thread creation routine
static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap);
@@ -117,10 +127,11 @@ protected:
LLCondition* mRunCondition;
apr_thread_t *mAPRThreadp;
EThreadStatus mStatus;
volatile EThreadStatus mStatus;
U32 mID;
friend void AIThreadLocalData::create(LLThread* threadp);
AIThreadLocalData* mThreadLocalData;
friend void LLThreadLocalData::create(LLThread* threadp);
LLThreadLocalData* mThreadLocalData;
void setQuitting();
@@ -148,37 +159,60 @@ protected:
//============================================================================
#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
#ifdef MUTEX_DEBUG
// We really shouldn't be using recursive locks. Make sure of that in debug mode.
#define MUTEX_FLAG APR_THREAD_MUTEX_UNNESTED
#else
// Use the fastest platform-optimal lock behavior (can be recursive or non-recursive).
#define MUTEX_FLAG APR_THREAD_MUTEX_DEFAULT
#endif
class LL_COMMON_API LLMutexBase
{
public:
void lock() { apr_thread_mutex_lock(mAPRMutexp); }
void unlock() { apr_thread_mutex_unlock(mAPRMutexp); }
typedef enum
{
NO_THREAD = 0xFFFFFFFF
} e_locking_thread;
LLMutexBase() ;
void lock(); //blocks
void unlock();
// Returns true if lock was obtained successfully.
bool tryLock() { return !APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp)); }
bool isLocked(); // non-blocking, but does do a lock/unlock so not free
// non-blocking, but does do a lock/unlock so not free
bool isLocked() { bool is_not_locked = tryLock(); if (is_not_locked) unlock(); return !is_not_locked; }
// get ID of locking thread
U32 lockingThread() const { return mLockingThread; }
protected:
// mAPRMutexp is initialized and uninitialized in the derived class.
apr_thread_mutex_t* mAPRMutexp;
mutable U32 mCount;
mutable U32 mLockingThread;
};
class LL_COMMON_API LLMutex : public LLMutexBase
{
public:
LLMutex(AIAPRPool& parent = LLThread::tldata().mRootPool) : mPool(parent)
LLMutex(LLAPRPool& parent = LLThread::tldata().mRootPool) : mPool(parent)
{
apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mPool());
apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mPool());
}
~LLMutex()
{
llassert(!isLocked()); // better not be locked!
//this assertion erroneously triggers whenever an LLCondition is destroyed
//llassert(!isLocked()); // better not be locked!
apr_thread_mutex_destroy(mAPRMutexp);
mAPRMutexp = NULL;
}
protected:
AIAPRPool mPool;
LLAPRPool mPool;
private:
// Disable copy construction, as si teh bomb!!! -SG
LLMutex(const LLMutex&);
@@ -194,7 +228,7 @@ class LL_COMMON_API LLMutexRootPool : public LLMutexBase
public:
LLMutexRootPool(void)
{
apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mRootPool());
apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mRootPool());
}
~LLMutexRootPool()
{
@@ -208,7 +242,7 @@ public:
}
protected:
AIAPRRootPool mRootPool;
LLAPRRootPool mRootPool;
};
#endif // APR_HAS_THREADS
@@ -216,7 +250,7 @@ protected:
class LL_COMMON_API LLCondition : public LLMutex
{
public:
LLCondition(AIAPRPool& parent = LLThread::tldata().mRootPool);
LLCondition(LLAPRPool& parent = LLThread::tldata().mRootPool);
~LLCondition();
void wait(); // blocks
@@ -246,7 +280,7 @@ private:
class AIRWLock
{
public:
AIRWLock(AIAPRPool& parent = LLThread::tldata().mRootPool) :
AIRWLock(LLAPRPool& parent = LLThread::tldata().mRootPool) :
mWriterWaitingMutex(parent), mNoHoldersCondition(parent), mHoldersCount(0), mWriterIsWaiting(false) { }
private:
@@ -350,6 +384,7 @@ void LLThread::unlockData()
mRunCondition->unlock();
}
//============================================================================
// see llmemory.h for LLPointer<> definition

View File

@@ -0,0 +1,100 @@
/**
* @file llthread.cpp
*
* $LicenseInfo:firstyear=2004&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 "linden_common.h"
#include <apr_pools.h>
#include <apr_queue.h>
#include "llthreadsafequeue.h"
// LLThreadSafeQueueImplementation
//-----------------------------------------------------------------------------
LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(unsigned int capacity):
mQueue(0)
{
mPool.create();
apr_status_t status = apr_queue_create(&mQueue, capacity, mPool());
if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue");
}
LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation()
{
if(mQueue != 0) {
if(apr_queue_size(mQueue) != 0) llwarns <<
"terminating queue which still contains " << apr_queue_size(mQueue) <<
" elements;" << "memory will be leaked" << LL_ENDL;
apr_queue_term(mQueue);
}
}
void LLThreadSafeQueueImplementation::pushFront(void * element)
{
apr_status_t status = apr_queue_push(mQueue, element);
if(status == APR_EINTR) {
throw LLThreadSafeQueueInterrupt();
} else if(status != APR_SUCCESS) {
throw LLThreadSafeQueueError("push failed");
} else {
; // Success.
}
}
bool LLThreadSafeQueueImplementation::tryPushFront(void * element){
return apr_queue_trypush(mQueue, element) == APR_SUCCESS;
}
void * LLThreadSafeQueueImplementation::popBack(void)
{
void * element;
apr_status_t status = apr_queue_pop(mQueue, &element);
if(status == APR_EINTR) {
throw LLThreadSafeQueueInterrupt();
} else if(status != APR_SUCCESS) {
throw LLThreadSafeQueueError("pop failed");
} else {
return element;
}
}
bool LLThreadSafeQueueImplementation::tryPopBack(void *& element)
{
return apr_queue_trypop(mQueue, &element) == APR_SUCCESS;
}
size_t LLThreadSafeQueueImplementation::size()
{
return apr_queue_size(mQueue);
}

View File

@@ -0,0 +1,203 @@
/**
* @file llthreadsafequeue.h
* @brief Base classes for thread, mutex and condition handling.
*
* $LicenseInfo:firstyear=2004&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_LLTHREADSAFEQUEUE_H
#define LL_LLTHREADSAFEQUEUE_H
#include <string>
#include <stdexcept>
#include "llaprpool.h"
class LLThreadSafeQueueImplementation; // See below.
//
// A general queue exception.
//
class LL_COMMON_API LLThreadSafeQueueError:
public std::runtime_error
{
public:
LLThreadSafeQueueError(std::string const & message):
std::runtime_error(message)
{
; // No op.
}
};
//
// An exception raised when blocking operations are interrupted.
//
class LL_COMMON_API LLThreadSafeQueueInterrupt:
public LLThreadSafeQueueError
{
public:
LLThreadSafeQueueInterrupt(void):
LLThreadSafeQueueError("queue operation interrupted")
{
; // No op.
}
};
struct apr_queue_t; // From apr_queue.h
//
// Implementation details.
//
class LL_COMMON_API LLThreadSafeQueueImplementation
{
public:
LLThreadSafeQueueImplementation(unsigned int capacity);
~LLThreadSafeQueueImplementation();
void pushFront(void * element);
bool tryPushFront(void * element);
void * popBack(void);
bool tryPopBack(void *& element);
size_t size();
private:
LLAPRPool mPool; // The pool used for mQueue.
apr_queue_t * mQueue;
};
//
// Implements a thread safe FIFO.
//
template<typename ElementT>
class LLThreadSafeQueue
{
public:
typedef ElementT value_type;
// Constructor.
LLThreadSafeQueue(unsigned int capacity = 1024);
// Add an element to the front of queue (will block if the queue has
// reached capacity).
//
// This call will raise an interrupt error if the queue is deleted while
// the caller is blocked.
void pushFront(ElementT const & element);
// Try to add an element to the front ofqueue without blocking. Returns
// true only if the element was actually added.
bool tryPushFront(ElementT const & element);
// Pop the element at the end of the queue (will block if the queue is
// empty).
//
// This call will raise an interrupt error if the queue is deleted while
// the caller is blocked.
ElementT popBack(void);
// Pop an element from the end of the queue if there is one available.
// Returns true only if an element was popped.
bool tryPopBack(ElementT & element);
// Returns the size of the queue.
size_t size();
private:
LLThreadSafeQueueImplementation mImplementation;
};
// LLThreadSafeQueue
//-----------------------------------------------------------------------------
template<typename ElementT>
LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(unsigned int capacity) :
mImplementation(capacity)
{
; // No op.
}
template<typename ElementT>
void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element)
{
ElementT * elementCopy = new ElementT(element);
try {
mImplementation.pushFront(elementCopy);
} catch (LLThreadSafeQueueInterrupt) {
delete elementCopy;
throw;
}
}
template<typename ElementT>
bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element)
{
ElementT * elementCopy = new ElementT(element);
bool result = mImplementation.tryPushFront(elementCopy);
if(!result) delete elementCopy;
return result;
}
template<typename ElementT>
ElementT LLThreadSafeQueue<ElementT>::popBack(void)
{
ElementT * element = reinterpret_cast<ElementT *> (mImplementation.popBack());
ElementT result(*element);
delete element;
return result;
}
template<typename ElementT>
bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element)
{
void * storedElement;
bool result = mImplementation.tryPopBack(storedElement);
if(result) {
ElementT * elementPtr = reinterpret_cast<ElementT *>(storedElement);
element = *elementPtr;
delete elementPtr;
} else {
; // No op.
}
return result;
}
template<typename ElementT>
size_t LLThreadSafeQueue<ElementT>::size(void)
{
return mImplementation.size();
}
#endif

View File

@@ -36,6 +36,8 @@
#include "u64.h"
#include "lldate.h"
#if LL_WINDOWS
# define WIN32_LEAN_AND_MEAN
# include <winsock2.h>

View File

@@ -39,8 +39,6 @@
#include <limits.h>
#include "stdtypes.h"
#include "llpreprocessor.h"
#include "lldate.h"
#include <string>
#include <list>
@@ -55,8 +53,6 @@ const U32 USEC_PER_HOUR = USEC_PER_MIN * MIN_PER_HOUR;
const U32 SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR;
const F64 SEC_PER_USEC = 1.0 / (F64) USEC_PER_SEC;
LL_COMMON_API U64 totalTime(); // Returns current system time in microseconds
class LL_COMMON_API LLTimer
{
public:
@@ -175,4 +171,5 @@ LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstri
LL_COMMON_API void timeToFormattedString(time_t time, std::string format, std::string &timestr);
LL_COMMON_API void timeStructToFormattedString(struct tm * time, std::string format, std::string &timestr);
U64 LL_COMMON_API totalTime(); // Returns current system time in microseconds
#endif

View File

@@ -0,0 +1,705 @@
/**
* @file lltreeiterators.h
* @author Nat Goodspeed
* @date 2008-08-19
* @brief This file defines iterators useful for traversing arbitrary node
* classes, potentially polymorphic, linked into strict tree
* structures.
*
* Dereferencing any one of these iterators actually yields a @em
* pointer to the node in question. For example, given an
* LLLinkedIter<MyNode> <tt>li</tt>, <tt>*li</tt> gets you a pointer
* to MyNode, and <tt>**li</tt> gets you the MyNode instance itself.
* More commonly, instead of writing <tt>li->member</tt>, you write
* <tt>(*li)->member</tt> -- as you would if you were traversing an
* STL container of MyNode pointers.
*
* It would certainly be possible to build these iterators so that
* <tt>*iterator</tt> would return a reference to the node itself
* rather than a pointer to the node, and for many purposes it would
* even be more convenient. However, that would be insufficiently
* flexible. If you want to use an iterator range to (e.g.) initialize
* a std::vector collecting results -- you rarely want to actually @em
* copy the nodes in question. You're much more likely to want to copy
* <i>pointers to</i> the traversed nodes. Hence these iterators
* produce pointers.
*
* Though you specify the actual NODE class as the template parameter,
* these iterators internally use LLPtrTo<> to discover whether to
* store and return an LLPointer<NODE> or a simple NODE*.
*
* By strict tree structures, we mean that each child must have
* exactly one parent. This forbids a child claiming any ancestor as a
* child of its own. Child nodes with multiple parents will be visited
* once for each parent. Cycles in the graph will result in either an
* infinite loop or an out-of-memory crash. You Have Been Warned.
*
* $LicenseInfo:firstyear=2008&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$
*/
#if ! defined(LL_LLTREEITERATORS_H)
#define LL_LLTREEITERATORS_H
#include "llptrto.h"
#include <vector>
#include <deque>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/function.hpp>
#include <boost/static_assert.hpp>
namespace LLTreeIter
{
/// Discriminator between LLTreeUpIter and LLTreeDownIter
enum RootIter { UP, DOWN };
/// Discriminator between LLTreeDFSIter, LLTreeDFSPostIter and LLTreeBFSIter
enum WalkIter { DFS_PRE, DFS_POST, BFS };
}
/**
* LLBaseIter defines some machinery common to all these iterators. We use
* boost::iterator_facade to define the iterator boilerplate: the conventional
* operators and methods necessary to implement a standards-conforming
* iterator. That allows us to specify the actual iterator semantics in terms
* of equal(), dereference() and increment() methods.
*/
template <class SELFTYPE, class NODE>
class LLBaseIter: public boost::iterator_facade<SELFTYPE,
// use pointer type as the
// reference type
typename LLPtrTo<NODE>::type,
boost::forward_traversal_tag>
{
protected:
/// LLPtrTo<NODE>::type is either NODE* or LLPointer<NODE>, as appropriate
typedef typename LLPtrTo<NODE>::type ptr_type;
/// function that advances from this node to next accepts a node pointer
/// and returns another
typedef boost::function<ptr_type(const ptr_type&)> func_type;
typedef SELFTYPE self_type;
};
/// Functor returning NULL, suitable for an end-iterator's 'next' functor
template <class NODE>
typename LLPtrTo<NODE>::type LLNullNextFunctor(const typename LLPtrTo<NODE>::type&)
{
return typename LLPtrTo<NODE>::type();
}
/**
* LLLinkedIter is an iterator over an intrusive singly-linked list. The
* beginning of the list is represented by LLLinkedIter(list head); the end is
* represented by LLLinkedIter().
*
* The begin LLLinkedIter must be instantiated with a functor to extract the
* 'next' pointer from the current node. Supposing that the link pointer is @c
* public, something like:
*
* @code
* NODE* mNext;
* @endcode
*
* you can use (e.g.) <tt>boost::bind(&NODE::mNext, _1)</tt> for the purpose.
* Alternatively, you can bind whatever accessor method is normally used to
* advance to the next node, e.g. for:
*
* @code
* NODE* next() const;
* @endcode
*
* you can use <tt>boost::bind(&NODE::next, _1)</tt>.
*/
template <class NODE>
class LLLinkedIter: public LLBaseIter<LLLinkedIter<NODE>, NODE>
{
typedef LLBaseIter<LLLinkedIter<NODE>, NODE> super;
protected:
/// some methods need to return a reference to self
typedef typename super::self_type self_type;
typedef typename super::ptr_type ptr_type;
typedef typename super::func_type func_type;
public:
/// Instantiate an LLLinkedIter to start a range, or to end a range before
/// a particular list entry. Pass a functor to extract the 'next' pointer
/// from the current node.
LLLinkedIter(const ptr_type& entry, const func_type& nextfunc):
mCurrent(entry),
mNextFunc(nextfunc)
{}
/// Instantiate an LLLinkedIter to end a range at the end of the list
LLLinkedIter():
mCurrent(),
mNextFunc(LLNullNextFunctor<NODE>)
{}
private:
/// leverage boost::iterator_facade
friend class boost::iterator_core_access;
/// advance
void increment()
{
mCurrent = mNextFunc(mCurrent);
}
/// equality
bool equal(const self_type& that) const { return this->mCurrent == that.mCurrent; }
/// dereference
ptr_type& dereference() const { return const_cast<ptr_type&>(mCurrent); }
ptr_type mCurrent;
func_type mNextFunc;
};
/**
* LLTreeUpIter walks from the node in hand to the root of the tree. The term
* "up" is applied to a tree visualized with the root at the top.
*
* LLTreeUpIter is an alias for LLLinkedIter, since any linked tree that you
* can navigate that way at all contains parent pointers.
*/
template <class NODE>
class LLTreeUpIter: public LLLinkedIter<NODE>
{
typedef LLLinkedIter<NODE> super;
public:
/// Instantiate an LLTreeUpIter to start from a particular tree node, or
/// to end a parent traversal before reaching a particular ancestor. Pass
/// a functor to extract the 'parent' pointer from the current node.
LLTreeUpIter(const typename super::ptr_type& node,
const typename super::func_type& parentfunc):
super(node, parentfunc)
{}
/// Instantiate an LLTreeUpIter to end a range at the root of the tree
LLTreeUpIter():
super()
{}
};
/**
* LLTreeDownIter walks from the root of the tree to the node in hand. The
* term "down" is applied to a tree visualized with the root at the top.
*
* Though you instantiate the begin() LLTreeDownIter with a pointer to some
* node at an arbitrary location in the tree, the root will be the first node
* you dereference and the passed node will be the last node you dereference.
*
* On construction, LLTreeDownIter walks from the current node to the root,
* capturing the path. Then in use, it replays that walk in reverse. As with
* all traversals of interesting data structures, it is actively dangerous to
* modify the tree during an LLTreeDownIter walk.
*/
template <class NODE>
class LLTreeDownIter: public LLBaseIter<LLTreeDownIter<NODE>, NODE>
{
typedef LLBaseIter<LLTreeDownIter<NODE>, NODE> super;
typedef typename super::self_type self_type;
protected:
typedef typename super::ptr_type ptr_type;
typedef typename super::func_type func_type;
private:
typedef std::vector<ptr_type> list_type;
public:
/// Instantiate an LLTreeDownIter to end at a particular tree node. Pass a
/// functor to extract the 'parent' pointer from the current node.
LLTreeDownIter(const ptr_type& node,
const func_type& parentfunc)
{
for (ptr_type n = node; n; n = parentfunc(n))
mParents.push_back(n);
}
/// Instantiate an LLTreeDownIter representing "here", the end of the loop
LLTreeDownIter() {}
private:
/// leverage boost::iterator_facade
friend class boost::iterator_core_access;
/// advance
void increment()
{
mParents.pop_back();
}
/// equality
bool equal(const self_type& that) const { return this->mParents == that.mParents; }
/// implement dereference/indirection operators
ptr_type& dereference() const { return const_cast<ptr_type&>(mParents.back()); }
list_type mParents;
};
/**
* When you want to select between LLTreeUpIter and LLTreeDownIter with a
* compile-time discriminator, use LLTreeRootIter with an LLTreeIter::RootIter
* template arg.
*/
template <LLTreeIter::RootIter DISCRIM, class NODE>
class LLTreeRootIter
{
enum { use_a_valid_LLTreeIter_RootIter_value = false };
public:
/// Bogus constructors for default (unrecognized discriminator) case
template <typename TYPE1, typename TYPE2>
LLTreeRootIter(TYPE1, TYPE2)
{
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value);
}
LLTreeRootIter()
{
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value);
}
};
/// Specialize for LLTreeIter::UP
template <class NODE>
class LLTreeRootIter<LLTreeIter::UP, NODE>: public LLTreeUpIter<NODE>
{
typedef LLTreeUpIter<NODE> super;
public:
/// forward begin ctor
LLTreeRootIter(const typename super::ptr_type& node,
const typename super::func_type& parentfunc):
super(node, parentfunc)
{}
/// forward end ctor
LLTreeRootIter():
super()
{}
};
/// Specialize for LLTreeIter::DOWN
template <class NODE>
class LLTreeRootIter<LLTreeIter::DOWN, NODE>: public LLTreeDownIter<NODE>
{
typedef LLTreeDownIter<NODE> super;
public:
/// forward begin ctor
LLTreeRootIter(const typename super::ptr_type& node,
const typename super::func_type& parentfunc):
super(node, parentfunc)
{}
/// forward end ctor
LLTreeRootIter():
super()
{}
};
/**
* Instantiated with a tree node, typically the root, LLTreeDFSIter "flattens"
* a depth-first tree walk through that node and all its descendants.
*
* The begin() LLTreeDFSIter must be instantiated with functors to obtain from
* a given node begin() and end() iterators for that node's children. For this
* reason, you must specify the type of the node's child iterator as an
* additional template parameter.
*
* Specifically, the begin functor must return an iterator whose dereferenced
* value is a @em pointer to a child tree node. For instance, if each node
* tracks its children in an STL container of node* pointers, you can simply
* return that container's begin() iterator.
*
* Alternatively, if a node tracks its children with a classic linked list,
* write a functor returning LLLinkedIter<NODE>.
*
* The end() LLTreeDFSIter must, of course, match the begin() iterator's
* template parameters, but is constructed without runtime parameters.
*/
template <class NODE, typename CHILDITER>
class LLTreeDFSIter: public LLBaseIter<LLTreeDFSIter<NODE, CHILDITER>, NODE>
{
typedef LLBaseIter<LLTreeDFSIter<NODE, CHILDITER>, NODE> super;
typedef typename super::self_type self_type;
protected:
typedef typename super::ptr_type ptr_type;
// The func_type is different for this: from a NODE pointer, we must
// obtain a CHILDITER.
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
private:
typedef std::vector<ptr_type> list_type;
public:
/// Instantiate an LLTreeDFSIter to start a depth-first walk. Pass
/// functors to extract the 'child begin' and 'child end' iterators from
/// each node.
LLTreeDFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc)
: mBeginFunc(beginfunc),
mEndFunc(endfunc),
mSkipChildren(false)
{
// Only push back this node if it's non-NULL!
if (node)
mPending.push_back(node);
}
/// Instantiate an LLTreeDFSIter to mark the end of the walk
LLTreeDFSIter() : mSkipChildren(false) {}
/// flags iterator logic to skip traversing children of current node on next increment
void skipDescendants(bool skip = true) { mSkipChildren = skip; }
private:
/// leverage boost::iterator_facade
friend class boost::iterator_core_access;
/// advance
/// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search
void increment()
{
// Capture the node we were just looking at
ptr_type current = mPending.back();
// Remove it from mPending so we don't process it again later
mPending.pop_back();
if (!mSkipChildren)
{
// Add all its children to mPending
addChildren(current);
}
// reset flag after each step
mSkipChildren = false;
}
/// equality
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
/// implement dereference/indirection operators
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back()); }
/// Add the direct children of the specified node to mPending
void addChildren(const ptr_type& node)
{
// If we just use push_back() for each child in turn, we'll end up
// processing children in reverse order. We don't want to assume
// CHILDITER is reversible: some of the linked trees we'll be
// processing manage their children using singly-linked lists. So
// figure out how many children there are, grow mPending by that size
// and reverse-copy the children into the new space.
CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node);
// grow mPending by the number of children
mPending.resize(mPending.size() + std::distance(chi, chend));
// reverse-copy the children into the newly-expanded space
std::copy(chi, chend, mPending.rbegin());
}
/// list of the nodes yet to be processed
list_type mPending;
/// functor to extract begin() child iterator
func_type mBeginFunc;
/// functor to extract end() child iterator
func_type mEndFunc;
/// flag which controls traversal of children (skip children of current node if true)
bool mSkipChildren;
};
/**
* Instantiated with a tree node, typically the root, LLTreeDFSPostIter
* "flattens" a depth-first tree walk through that node and all its
* descendants. Whereas LLTreeDFSIter visits each node before visiting any of
* its children, LLTreeDFSPostIter visits all of a node's children before
* visiting the node itself.
*
* The begin() LLTreeDFSPostIter must be instantiated with functors to obtain
* from a given node begin() and end() iterators for that node's children. For
* this reason, you must specify the type of the node's child iterator as an
* additional template parameter.
*
* Specifically, the begin functor must return an iterator whose dereferenced
* value is a @em pointer to a child tree node. For instance, if each node
* tracks its children in an STL container of node* pointers, you can simply
* return that container's begin() iterator.
*
* Alternatively, if a node tracks its children with a classic linked list,
* write a functor returning LLLinkedIter<NODE>.
*
* The end() LLTreeDFSPostIter must, of course, match the begin() iterator's
* template parameters, but is constructed without runtime parameters.
*/
template <class NODE, typename CHILDITER>
class LLTreeDFSPostIter: public LLBaseIter<LLTreeDFSPostIter<NODE, CHILDITER>, NODE>
{
typedef LLBaseIter<LLTreeDFSPostIter<NODE, CHILDITER>, NODE> super;
typedef typename super::self_type self_type;
protected:
typedef typename super::ptr_type ptr_type;
// The func_type is different for this: from a NODE pointer, we must
// obtain a CHILDITER.
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
private:
// Upon reaching a given node in our pending list, we need to know whether
// we've already pushed that node's children, so we must associate a bool
// with each node pointer.
typedef std::vector< std::pair<ptr_type, bool> > list_type;
public:
/// Instantiate an LLTreeDFSPostIter to start a depth-first walk. Pass
/// functors to extract the 'child begin' and 'child end' iterators from
/// each node.
LLTreeDFSPostIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc)
: mBeginFunc(beginfunc),
mEndFunc(endfunc),
mSkipAncestors(false)
{
if (! node)
return;
mPending.push_back(typename list_type::value_type(node, false));
makeCurrent();
}
/// Instantiate an LLTreeDFSPostIter to mark the end of the walk
LLTreeDFSPostIter() : mSkipAncestors(false) {}
/// flags iterator logic to skip traversing ancestors of current node on next increment
void skipAncestors(bool skip = true) { mSkipAncestors = skip; }
private:
/// leverage boost::iterator_facade
friend class boost::iterator_core_access;
/// advance
/// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search
void increment()
{
// Pop the previous current node
mPending.pop_back();
makeCurrent();
}
/// equality
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
/// implement dereference/indirection operators
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back().first); }
struct isOpen
{
bool operator()(const typename list_type::value_type& item)
{
return item.second;
}
};
/// Call this each time we change mPending.back() -- that is, every time
/// we're about to change the value returned by dereference(). If we
/// haven't yet pushed the new node's children, do so now.
void makeCurrent()
{
if (mSkipAncestors)
{
mPending.erase(std::remove_if(mPending.begin(), mPending.end(), isOpen()), mPending.end());
mSkipAncestors = false;
}
// Once we've popped the last node, this becomes a no-op.
if (mPending.empty())
return;
// Here mPending.back() holds the node pointer we're proposing to
// dereference next. Have we pushed that node's children yet?
if (mPending.back().second)
return; // if so, it's okay to visit this node now
// We haven't yet pushed this node's children. Do so now. Remember
// that we did -- while the node in question is still back().
mPending.back().second = true;
addChildren(mPending.back().first);
// Now, because we've just changed mPending.back(), make that new node
// current.
makeCurrent();
}
/// Add the direct children of the specified node to mPending
void addChildren(const ptr_type& node)
{
// If we just use push_back() for each child in turn, we'll end up
// processing children in reverse order. We don't want to assume
// CHILDITER is reversible: some of the linked trees we'll be
// processing manage their children using singly-linked lists. So
// figure out how many children there are, grow mPending by that size
// and reverse-copy the children into the new space.
CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node);
// grow mPending by the number of children
mPending.resize(mPending.size() + std::distance(chi, chend));
// Reverse-copy the children into the newly-expanded space. We can't
// just use std::copy() because the source is a ptr_type, whereas the
// dest is a pair of (ptr_type, bool).
for (typename list_type::reverse_iterator pi = mPending.rbegin(); chi != chend; ++chi, ++pi)
{
pi->first = *chi; // copy the child pointer
pi->second = false; // we haven't yet pushed this child's chldren
}
}
/// list of the nodes yet to be processed
list_type mPending;
/// functor to extract begin() child iterator
func_type mBeginFunc;
/// functor to extract end() child iterator
func_type mEndFunc;
/// flags logic to skip traversal of ancestors of current node
bool mSkipAncestors;
};
/**
* Instantiated with a tree node, typically the root, LLTreeBFSIter "flattens"
* a breadth-first tree walk through that node and all its descendants.
*
* The begin() LLTreeBFSIter must be instantiated with functors to obtain from
* a given node the begin() and end() iterators of that node's children. For
* this reason, you must specify the type of the node's child iterator as an
* additional template parameter.
*
* Specifically, the begin functor must return an iterator whose dereferenced
* value is a @em pointer to a child tree node. For instance, if each node
* tracks its children in an STL container of node* pointers, you can simply
* return that container's begin() iterator.
*
* Alternatively, if a node tracks its children with a classic linked list,
* write a functor returning LLLinkedIter<NODE>.
*
* The end() LLTreeBFSIter must, of course, match the begin() iterator's
* template parameters, but is constructed without runtime parameters.
*/
template <class NODE, typename CHILDITER>
class LLTreeBFSIter: public LLBaseIter<LLTreeBFSIter<NODE, CHILDITER>, NODE>
{
typedef LLBaseIter<LLTreeBFSIter<NODE, CHILDITER>, NODE> super;
typedef typename super::self_type self_type;
protected:
typedef typename super::ptr_type ptr_type;
// The func_type is different for this: from a NODE pointer, we must
// obtain a CHILDITER.
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
private:
// We need a FIFO queue rather than a LIFO stack. Use a deque rather than
// a vector, since vector can't implement pop_front() efficiently.
typedef std::deque<ptr_type> list_type;
public:
/// Instantiate an LLTreeBFSIter to start a depth-first walk. Pass
/// functors to extract the 'child begin' and 'child end' iterators from
/// each node.
LLTreeBFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc):
mBeginFunc(beginfunc),
mEndFunc(endfunc)
{
if (node)
mPending.push_back(node);
}
/// Instantiate an LLTreeBFSIter to mark the end of the walk
LLTreeBFSIter() {}
private:
/// leverage boost::iterator_facade
friend class boost::iterator_core_access;
/// advance
/// This implementation is due to http://en.wikipedia.org/wiki/Breadth-first_search
void increment()
{
// Capture the node we were just looking at
ptr_type current = mPending.front();
// Remove it from mPending so we don't process it again later
mPending.pop_front();
// Add all its children to mPending
CHILDITER chend = mEndFunc(current);
for (CHILDITER chi = mBeginFunc(current); chi != chend; ++chi)
mPending.push_back(*chi);
}
/// equality
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
/// implement dereference/indirection operators
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.front()); }
/// list of the nodes yet to be processed
list_type mPending;
/// functor to extract begin() child iterator
func_type mBeginFunc;
/// functor to extract end() child iterator
func_type mEndFunc;
};
/**
* When you want to select between LLTreeDFSIter, LLTreeDFSPostIter and
* LLTreeBFSIter with a compile-time discriminator, use LLTreeWalkIter with an
* LLTreeIter::WalkIter template arg.
*/
template <LLTreeIter::WalkIter DISCRIM, class NODE, typename CHILDITER>
class LLTreeWalkIter
{
enum { use_a_valid_LLTreeIter_WalkIter_value = false };
public:
/// Bogus constructors for default (unrecognized discriminator) case
template <typename TYPE1, typename TYPE2>
LLTreeWalkIter(TYPE1, TYPE2)
{
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value);
}
LLTreeWalkIter()
{
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value);
}
};
/// Specialize for LLTreeIter::DFS_PRE
template <class NODE, typename CHILDITER>
class LLTreeWalkIter<LLTreeIter::DFS_PRE, NODE, CHILDITER>:
public LLTreeDFSIter<NODE, CHILDITER>
{
typedef LLTreeDFSIter<NODE, CHILDITER> super;
public:
/// forward begin ctor
LLTreeWalkIter(const typename super::ptr_type& node,
const typename super::func_type& beginfunc,
const typename super::func_type& endfunc):
super(node, beginfunc, endfunc)
{}
/// forward end ctor
LLTreeWalkIter():
super()
{}
};
/// Specialize for LLTreeIter::DFS_POST
template <class NODE, typename CHILDITER>
class LLTreeWalkIter<LLTreeIter::DFS_POST, NODE, CHILDITER>:
public LLTreeDFSPostIter<NODE, CHILDITER>
{
typedef LLTreeDFSPostIter<NODE, CHILDITER> super;
public:
/// forward begin ctor
LLTreeWalkIter(const typename super::ptr_type& node,
const typename super::func_type& beginfunc,
const typename super::func_type& endfunc):
super(node, beginfunc, endfunc)
{}
/// forward end ctor
LLTreeWalkIter():
super()
{}
};
/// Specialize for LLTreeIter::BFS
template <class NODE, typename CHILDITER>
class LLTreeWalkIter<LLTreeIter::BFS, NODE, CHILDITER>:
public LLTreeBFSIter<NODE, CHILDITER>
{
typedef LLTreeBFSIter<NODE, CHILDITER> super;
public:
/// forward begin ctor
LLTreeWalkIter(const typename super::ptr_type& node,
const typename super::func_type& beginfunc,
const typename super::func_type& endfunc):
super(node, beginfunc, endfunc)
{}
/// forward end ctor
LLTreeWalkIter():
super()
{}
};
#endif /* ! defined(LL_LLTREEITERATORS_H) */

View File

@@ -202,9 +202,9 @@ void LLWorkerThread::WorkRequest::finishRequest(bool completed)
LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& name)
: mWorkerThread(workerthread),
mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
mWorkerClassName(name),
mRequestHandle(LLWorkerThread::nullHandle()),
mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
mWorkFlags(0)
{
if (!mWorkerThread)

View File

@@ -109,6 +109,7 @@ const U64 GP_LAND_ALLOW_FLY = 0x1 << 24; // Bypass Fly Restriction
const U64 GP_LAND_ALLOW_CREATE = 0x1 << 25; // Bypass Create/Edit Objects Restriction
const U64 GP_LAND_ALLOW_LANDMARK = 0x1 << 26; // Bypass Landmark Restriction
const U64 GP_LAND_ALLOW_SET_HOME = 0x1 << 28; // Bypass Set Home Point Restriction
const U64 GP_LAND_ALLOW_HOLD_EVENT = 0x1LL << 41; // Allowed to hold events on group-owned land
// Parcel Access
const U64 GP_LAND_MANAGE_ALLOWED = 0x1 << 29; // Manage Allowed List

107
indra/llcommon/stringize.h Normal file
View File

@@ -0,0 +1,107 @@
/**
* @file stringize.h
* @author Nat Goodspeed
* @date 2008-12-17
* @brief stringize(item) template function and STRINGIZE(expression) macro
*
* $LicenseInfo:firstyear=2008&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$
*/
#if ! defined(LL_STRINGIZE_H)
#define LL_STRINGIZE_H
#include <sstream>
#include <boost/lambda/lambda.hpp>
/**
* stringize(item) encapsulates an idiom we use constantly, using
* operator<<(std::ostringstream&, TYPE) followed by std::ostringstream::str()
* to render a string expressing some item.
*/
template <typename T>
std::string stringize(const T& item)
{
std::ostringstream out;
out << item;
return out.str();
}
/**
* stringize_f(functor)
*/
template <typename Functor>
std::string stringize_f(Functor const & f)
{
std::ostringstream out;
f(out);
return out.str();
}
/**
* STRINGIZE(item1 << item2 << item3 ...) effectively expands to the
* following:
* @code
* std::ostringstream out;
* out << item1 << item2 << item3 ... ;
* return out.str();
* @endcode
*/
#define STRINGIZE(EXPRESSION) (stringize_f(boost::lambda::_1 << EXPRESSION))
/**
* destringize(str)
* defined for symmetry with stringize
* *NOTE - this has distinct behavior from boost::lexical_cast<T> regarding
* leading/trailing whitespace and handling of bad_lexical_cast exceptions
*/
template <typename T>
T destringize(std::string const & str)
{
T val;
std::istringstream in(str);
in >> val;
return val;
}
/**
* destringize_f(str, functor)
*/
template <typename Functor>
void destringize_f(std::string const & str, Functor const & f)
{
std::istringstream in(str);
f(in);
}
/**
* DESTRINGIZE(str, item1 >> item2 >> item3 ...) effectively expands to the
* following:
* @code
* std::istringstream in(str);
* in >> item1 >> item2 >> item3 ... ;
* @endcode
*/
#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), (boost::lambda::_1 >> EXPRESSION)))
#endif /* ! defined(LL_STRINGIZE_H) */

View File

@@ -89,7 +89,8 @@ LLCrashLogger::LLCrashLogger() :
mCrashBehavior(CRASH_BEHAVIOR_ASK),
mCrashInPreviousExec(false),
mSentCrashLogs(false),
mCrashHost("")
mCrashHost(""),
mCrashSettings("CrashSettings")
{
}

View File

@@ -138,8 +138,7 @@ void LLImageBase::sanityCheck()
// virtual
void LLImageBase::deleteData()
{
if(mData)
delete[] mData;
delete[] mData;
mData = NULL;
mDataSize = 0;
}
@@ -154,7 +153,7 @@ U8* LLImageBase::allocateData(S32 size)
size = mWidth * mHeight * mComponents;
if (size <= 0)
{
llerrs << llformat("LLImageBase::allocateData called with bad dimensions: %dx%dx%d",mWidth,mHeight,mComponents) << llendl;
llerrs << llformat("LLImageBase::allocateData called with bad dimensions: %dx%dx%d",mWidth,mHeight,(S32)mComponents) << llendl;
}
}
else if (size <= 0 || (size > 4096*4096*16 && !mAllowOverSize))
@@ -1299,28 +1298,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip
return false;
}
LLPointer<LLImageFormatted> image;
switch(codec)
{
//case IMG_CODEC_RGB:
case IMG_CODEC_BMP:
image = new LLImageBMP();
break;
case IMG_CODEC_TGA:
image = new LLImageTGA();
break;
case IMG_CODEC_JPEG:
image = new LLImageJPEG();
break;
case IMG_CODEC_J2C:
image = new LLImageJ2C();
break;
case IMG_CODEC_DXT:
image = new LLImageDXT();
break;
default:
return false;
}
LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
llassert(image.notNull());
U8 *buffer = image->allocateData(length);
@@ -1602,8 +1580,7 @@ BOOL LLImageFormatted::load(const std::string &filename)
resetLastError();
S32 file_size = 0;
LLAPRFile infile ;
infile.open(filename, LL_APR_RB, LLAPRFile::global, &file_size);
LLAPRFile infile(filename, LL_APR_RB, &file_size);
apr_file_t* apr_file = infile.getFileHandle();
if (!apr_file)
{
@@ -1638,8 +1615,7 @@ BOOL LLImageFormatted::save(const std::string &filename)
{
resetLastError();
LLAPRFile outfile ;
outfile.open(filename, LL_APR_WB, LLAPRFile::global);
LLAPRFile outfile(filename, LL_APR_WB);
if (!outfile.getFileHandle())
{
setLastError("Unable to open file for writing", filename);

View File

@@ -47,7 +47,7 @@ typedef const char* (*EngineInfoLLImageJ2CFunction)();
CreateLLImageJ2CFunction j2cimpl_create_func;
DestroyLLImageJ2CFunction j2cimpl_destroy_func;
EngineInfoLLImageJ2CFunction j2cimpl_engineinfo_func;
AIAPRPool j2cimpl_dso_memory_pool;
LLAPRPool j2cimpl_dso_memory_pool;
apr_dso_handle_t *j2cimpl_dso_handle;
//Declare the prototype for theses functions here, their functionality
@@ -473,8 +473,7 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
resetLastError();
S32 file_size = 0;
LLAPRFile infile ;
infile.open(filename, LL_APR_RB, LLAPRFile::global, &file_size);
LLAPRFile infile(filename, LL_APR_RB, &file_size);
apr_file_t* apr_file = infile.getFileHandle() ;
if (!apr_file)
{

View File

@@ -32,7 +32,7 @@
#ifndef LL_LLECONOMY_H
#define LL_LLECONOMY_H
#include "llmemory.h"
#include "llsingleton.h"
class LLMessageSystem;
class LLVector3;

View File

@@ -31,10 +31,10 @@
*/
#include "linden_common.h"
#include "llinventory.h"
#include "lldbstrings.h"
#include "llinventorydefines.h"
#include "llxorcipher.h"
#include "llsd.h"
#include "message.h"
@@ -1120,7 +1120,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd)
{
if (sd[w].isString())
{
mType = LLAssetType::lookup(sd[w].asString().c_str());
mType = LLAssetType::lookup(sd[w].asString());
}
else if (sd[w].isInteger())
{
@@ -1425,26 +1425,13 @@ void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size)
setCreationDate(now);
}
// returns TRUE if a should appear before b
BOOL item_dictionary_sort( LLInventoryItem* a, LLInventoryItem* b )
{
return (LLStringUtil::compareDict( a->getName().c_str(), b->getName().c_str() ) < 0);
}
// returns TRUE if a should appear before b
BOOL item_date_sort( LLInventoryItem* a, LLInventoryItem* b )
{
return a->getCreationDate() < b->getCreationDate();
}
///----------------------------------------------------------------------------
/// Class LLInventoryCategory
///----------------------------------------------------------------------------
LLInventoryCategory::LLInventoryCategory(const LLUUID& uuid,
const LLUUID& parent_uuid,
LLAssetType::EType preferred_type,
LLFolderType::EType preferred_type,
const std::string& name) :
LLInventoryObject(uuid, parent_uuid, LLAssetType::AT_CATEGORY, name),
mPreferredType(preferred_type)
@@ -1452,7 +1439,7 @@ LLInventoryCategory::LLInventoryCategory(const LLUUID& uuid,
}
LLInventoryCategory::LLInventoryCategory() :
mPreferredType(LLAssetType::AT_NONE)
mPreferredType(LLFolderType::FT_NONE)
{
mType = LLAssetType::AT_CATEGORY;
}
@@ -1474,12 +1461,12 @@ void LLInventoryCategory::copyCategory(const LLInventoryCategory* other)
mPreferredType = other->mPreferredType;
}
LLAssetType::EType LLInventoryCategory::getPreferredType() const
LLFolderType::EType LLInventoryCategory::getPreferredType() const
{
return mPreferredType;
}
void LLInventoryCategory::setPreferredType(LLAssetType::EType type)
void LLInventoryCategory::setPreferredType(LLFolderType::EType type)
{
mPreferredType = type;
}
@@ -1525,13 +1512,13 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd)
if (sd.has(w))
{
S8 type = (U8)sd[w].asInteger();
mPreferredType = static_cast<LLAssetType::EType>(type);
mPreferredType = static_cast<LLFolderType::EType>(type);
}
w = INV_ASSET_TYPE_LABEL_WS;
if (sd.has(w))
{
S8 type = (U8)sd[w].asInteger();
mPreferredType = static_cast<LLAssetType::EType>(type);
mPreferredType = static_cast<LLFolderType::EType>(type);
}
w = INV_NAME_LABEL;
@@ -1553,7 +1540,7 @@ void LLInventoryCategory::unpackMessage(LLMessageSystem* msg,
msg->getUUIDFast(block, _PREHASH_ParentID, mParentUUID, block_num);
S8 type;
msg->getS8Fast(block, _PREHASH_Type, type, block_num);
mPreferredType = static_cast<LLAssetType::EType>(type);
mPreferredType = static_cast<LLFolderType::EType>(type);
msg->getStringFast(block, _PREHASH_Name, mName, block_num);
LLStringUtil::replaceNonstandardASCII(mName, ' ');
}
@@ -1602,7 +1589,7 @@ BOOL LLInventoryCategory::importFile(LLFILE* fp)
}
else if(0 == strcmp("pref_type", keyword))
{
mPreferredType = LLAssetType::lookup(valuestr);
mPreferredType = LLFolderType::lookup(valuestr);
}
else if(0 == strcmp("name", keyword))
{
@@ -1634,7 +1621,7 @@ BOOL LLInventoryCategory::exportFile(LLFILE* fp, BOOL) const
mParentUUID.toString(uuid_str);
fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str());
fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
fprintf(fp, "\t\tpref_type\t%s\n", LLAssetType::lookup(mPreferredType));
fprintf(fp, "\t\tpref_type\t%s\n", LLFolderType::lookup(mPreferredType).c_str());
fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
fprintf(fp,"\t}\n");
return TRUE;
@@ -1681,7 +1668,7 @@ BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream)
}
else if(0 == strcmp("pref_type", keyword))
{
mPreferredType = LLAssetType::lookup(valuestr);
mPreferredType = LLFolderType::lookup(valuestr);
}
else if(0 == strcmp("name", keyword))
{
@@ -1713,7 +1700,7 @@ BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL)
mParentUUID.toString(uuid_str);
output_stream << "\t\tparent_id\t" << uuid_str << "\n";
output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
output_stream << "\t\tpref_type\t" << LLAssetType::lookup(mPreferredType) << "\n";
output_stream << "\t\tpref_type\t" << LLFolderType::lookup(mPreferredType) << "\n";
output_stream << "\t\tname\t" << mName.c_str() << "|\n";
output_stream << "\t}\n";
return TRUE;
@@ -1793,10 +1780,10 @@ LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat)
rv[INV_PARENT_ID_LABEL] = cat->getParentUUID();
rv[INV_NAME_LABEL] = cat->getName();
rv[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(cat->getType());
if(LLAssetType::AT_NONE != cat->getPreferredType())
if(LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
{
rv[INV_PREFERRED_TYPE_LABEL] =
LLAssetType::lookup(cat->getPreferredType());
LLFolderType::lookup(cat->getPreferredType()).c_str();
}
return rv;
}
@@ -1810,7 +1797,7 @@ LLPointer<LLInventoryCategory> ll_create_category_from_sd(const LLSD& sd_cat)
rv->setType(
LLAssetType::lookup(sd_cat[INV_ASSET_TYPE_LABEL].asString()));
rv->setPreferredType(
LLAssetType::lookup(
LLFolderType::lookup(
sd_cat[INV_PREFERRED_TYPE_LABEL].asString()));
return rv;
}

View File

@@ -33,12 +33,12 @@
#ifndef LL_LLINVENTORY_H
#define LL_LLINVENTORY_H
#include "llassetstorage.h"
#include "lldarray.h"
#include "llfoldertype.h"
#include "llinventorytype.h"
#include "llinventorydefines.h"
#include "llmemtype.h"
#include "llpermissions.h"
#include "llrefcount.h"
#include "llsaleinfo.h"
#include "llsd.h"
#include "lluuid.h"
@@ -242,10 +242,6 @@ protected:
time_t mCreationDate; // seconds from 1/1/1970, UTC
};
BOOL item_dictionary_sort(LLInventoryItem* a,LLInventoryItem* b);
BOOL item_date_sort(LLInventoryItem* a, LLInventoryItem* b);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLInventoryCategory
//
@@ -265,7 +261,7 @@ public:
public:
MEM_TYPE_NEW(LLMemType::MTYPE_INVENTORY);
LLInventoryCategory(const LLUUID& uuid, const LLUUID& parent_uuid,
LLAssetType::EType preferred_type,
LLFolderType::EType preferred_type,
const std::string& name);
LLInventoryCategory();
LLInventoryCategory(const LLInventoryCategory* other);
@@ -277,8 +273,8 @@ protected:
// Accessors And Mutators
//--------------------------------------------------------------------
public:
LLAssetType::EType getPreferredType() const;
void setPreferredType(LLAssetType::EType type);
LLFolderType::EType getPreferredType() const;
void setPreferredType(LLFolderType::EType type);
LLSD asLLSD() const;
bool fromLLSD(const LLSD& sd);
@@ -302,91 +298,16 @@ public:
// Member Variables
//--------------------------------------------------------------------
protected:
LLAssetType::EType mPreferredType; // Type that this category was "meant" to hold (although it may hold any type).
LLFolderType::EType mPreferredType; // Type that this category was "meant" to hold (although it may hold any type).
};
//-----------------------------------------------------------------------------
// Useful bits
// Convertors
//
// These functions convert between structured data and an inventory
// item, appropriate for serialization.
//-----------------------------------------------------------------------------
// This functor tests if an item is transferrable and returns true if
// it is. Derived from unary_function<> so that the object can be used
// in stl-compliant adaptable predicates (eg, not1<>). You might want
// to use this in std::partition() or similar logic.
struct IsItemTransferable : public std::unary_function<LLInventoryItem*, bool>
{
LLUUID mDestID;
IsItemTransferable(const LLUUID& dest_id) : mDestID(dest_id) {}
bool operator()(const LLInventoryItem* item) const
{
return (item->getPermissions().allowTransferTo(mDestID)) ? true:false;
}
};
// This functor is used to set the owner and group of inventory items,
// for example, in a simple std::for_each() loop. Note that the call
// to setOwnerAndGroup can fail if authority_id != LLUUID::null.
struct SetItemOwnerAndGroup
{
LLUUID mAuthorityID;
LLUUID mOwnerID;
LLUUID mGroupID;
SetItemOwnerAndGroup(const LLUUID& authority_id,
const LLUUID& owner_id,
const LLUUID& group_id) :
mAuthorityID(authority_id), mOwnerID(owner_id), mGroupID(group_id) {}
void operator()(LLInventoryItem* item) const
{
LLPermissions perm = item->getPermissions();
bool is_atomic = (LLAssetType::AT_OBJECT == item->getType()) ? false : true;
perm.setOwnerAndGroup(mAuthorityID, mOwnerID, mGroupID, is_atomic);
// If no owner id is set, this is equivalent to a deed action.
// Clear 'share with group'.
if (mOwnerID.isNull())
{
perm.setMaskGroup(PERM_NONE);
}
item->setPermissions(perm);
}
};
// This functor is used to unset the share with group, everyone perms, and
// for sale info for objects being sold through contents.
struct SetNotForSale
{
LLUUID mAgentID;
LLUUID mGroupID;
SetNotForSale(const LLUUID& agent_id,
const LLUUID& group_id) :
mAgentID(agent_id), mGroupID(group_id) {}
void operator()(LLInventoryItem* item) const
{
// Clear group & everyone permissions.
LLPermissions perm = item->getPermissions();
perm.setGroupBits(mAgentID, mGroupID, FALSE, PERM_MODIFY | PERM_MOVE | PERM_COPY);
perm.setEveryoneBits(mAgentID, mGroupID, FALSE, PERM_MOVE | PERM_COPY);
item->setPermissions(perm);
// Mark group & everyone permissions for overwrite on the next
// rez if it is an object.
if(LLAssetType::AT_OBJECT == item->getType())
{
U32 flags = item->getFlags();
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
item->setFlags(flags);
}
// Clear for sale info.
item->setSaleInfo(LLSaleInfo::DEFAULT);
}
};
typedef std::list<LLPointer<LLInventoryObject> > InventoryObjectList;
// These functions convert between structured data and an inventroy
// item, appropriate for serialization.
LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item);
LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item);
LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat);

View File

@@ -35,6 +35,7 @@
#include "llinventorytype.h"
#include "lldictionary.h"
#include "llmemory.h"
#include "llsingleton.h"
static const std::string empty_string;
@@ -122,7 +123,7 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
LLInventoryType::IT_NONE, // AT_FAVORITE
LLInventoryType::IT_NONE, // AT_LINK
LLInventoryType::IT_NONE, // AT_LINK_FOLDER
LLInventoryType::IT_NONE, // FT_ENSEMBLE_START
/*LLInventoryType::IT_NONE, // FT_ENSEMBLE_START
LLInventoryType::IT_NONE, //
LLInventoryType::IT_NONE, //
LLInventoryType::IT_NONE, //
@@ -144,7 +145,7 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
LLInventoryType::IT_NONE, // FT_ENSEMBLE_END
LLInventoryType::IT_NONE, // AT_CURRENT_OUTFIT
LLInventoryType::IT_NONE, // AT_OUTFIT
LLInventoryType::IT_NONE // AT_MY_OUTFITS
LLInventoryType::IT_NONE // AT_MY_OUTFITS*/
};
// static

View File

@@ -33,7 +33,7 @@
#ifndef LL_NOTECARD_H
#define LL_NOTECARD_H
#include "llmemory.h"
#include "llpointer.h"
#include "llinventory.h"
class LLNotecard

View File

@@ -177,7 +177,7 @@ void LLParcel::init(const LLUUID &owner_id,
mSaleTimerExpires.stop();
mGraceExtension = 0;
//mExpireAction = STEA_REVERT;
mRecordTransaction = FALSE;
//mRecordTransaction = FALSE;
mAuctionID = 0;
mInEscrow = false;
@@ -452,7 +452,7 @@ BOOL LLParcel::allowTerraformBy(const LLUUID &agent_id) const
bool LLParcel::isAgentBlockedFromParcel(LLParcel* parcelp,
const LLUUID& agent_id,
const std::vector<LLUUID>& group_ids,
const uuid_vec_t& group_ids,
const BOOL is_agent_identified,
const BOOL is_agent_transacted,
const BOOL is_agent_ageverified)

View File

@@ -38,8 +38,8 @@
#include "lluuid.h"
#include "llparcelflags.h"
#include "llpermissions.h"
#include "v3math.h"
#include "lltimer.h"
#include "v3math.h"
// Grid out of which parcels taken is stepped every 4 meters.
const F32 PARCEL_GRID_STEP_METERS = 4.f;
@@ -136,9 +136,15 @@ class LLSD;
class LLAccessEntry
{
public:
LLUUID mID;
S32 mTime;
U32 mFlags;
LLAccessEntry()
: mID(),
mTime(0),
mFlags(0)
{}
LLUUID mID; // Agent ID
S32 mTime; // Time (unix seconds) when entry expires
U32 mFlags; // Not used - currently should always be zero
};
typedef std::map<LLUUID,LLAccessEntry>::iterator access_map_iterator;
@@ -427,13 +433,10 @@ public:
void completeSale(U32& type, U8& flags, LLUUID& to_id);
void clearSale();
// this function returns TRUE if the parcel needs conversion to a
// lease from a non-owned-status state.
BOOL getRecordTransaction() const { return mRecordTransaction; }
void setRecordTransaction(BOOL record) { mRecordTransaction = record; }
BOOL isMediaResetTimerExpired(const U64& time);
// more accessors
U32 getParcelFlags() const { return mParcelFlags; }
@@ -468,7 +471,9 @@ public:
{ return (mParcelFlags & PF_ALLOW_FLY) ? TRUE : FALSE; }
BOOL getAllowLandmark() const
{ return (mParcelFlags & PF_ALLOW_LANDMARK) ? TRUE : FALSE; }
{ return TRUE; }
//Perhaps revert for opensim?
//{ return (mParcelFlags & PF_ALLOW_LANDMARK) ? TRUE : FALSE; }
BOOL getAllowGroupScripts() const
{ return (mParcelFlags & PF_ALLOW_GROUP_SCRIPTS) ? TRUE : FALSE; }
@@ -594,6 +599,7 @@ public:
BOOL getPreviouslyGroupOwned() const { return mPreviouslyGroupOwned; }
BOOL getSellWithObjects() const { return (mParcelFlags & PF_SELL_PARCEL_OBJECTS) ? TRUE : FALSE; }
protected:
LLUUID mID;
LLUUID mOwnerID;
@@ -613,8 +619,6 @@ protected:
LLTimer mMediaResetTimer;
S32 mGraceExtension;
BOOL mRecordTransaction;
// This value is non-zero if there is an auction associated with
// the parcel.
@@ -667,7 +671,6 @@ protected:
BOOL mRegionDenyAnonymousOverride;
BOOL mRegionDenyAgeUnverifiedOverride;
public:
// HACK, make private
S32 mLocalID;

View File

@@ -132,5 +132,7 @@ const S32 PARCEL_DETAILS_DESC = 1;
const S32 PARCEL_DETAILS_OWNER = 2;
const S32 PARCEL_DETAILS_GROUP = 3;
const S32 PARCEL_DETAILS_AREA = 4;
const S32 PARCEL_DETAILS_ID = 5;
const S32 PARCEL_DETAILS_SEE_AVATARS = 6;
#endif

View File

@@ -30,8 +30,8 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
#include <iostream>
#include "linden_common.h"
#include "llsaleinfo.h"

View File

@@ -17,13 +17,16 @@ set(llmath_SOURCE_FILES
llcamera.cpp
llcoordframe.cpp
llline.cpp
llmatrix3a.cpp
llmodularmath.cpp
llperlin.cpp
llquaternion.cpp
llrect.cpp
llsphere.cpp
llvector4a.cpp
llvolume.cpp
llvolumemgr.cpp
llvolumeoctree.cpp
llsdutil_math.cpp
m3math.cpp
m4math.cpp
@@ -53,21 +56,32 @@ set(llmath_HEADER_FILES
llinterp.h
llline.h
llmath.h
llmatrix3a.h
llmatrix3a.inl
llmodularmath.h
lloctree.h
llperlin.h
llplane.h
llquantize.h
llquaternion.h
llquaternion2.h
llquaternion2.inl
llrect.h
llsimdmath.h
llsimdtypes.h
llsimdtypes.inl
llsphere.h
lltreenode.h
llvector4a.h
llvector4a.inl
llvector4logical.h
llv4math.h
llv4matrix3.h
llv4matrix4.h
llv4vector3.h
llvolume.h
llvolumemgr.h
llvolumeoctree.h
llsdutil_math.h
m3math.h
m4math.h

View File

@@ -54,28 +54,20 @@ LLCalc* LLCalc::sInstance = NULL;
LLCalc::LLCalc() : mLastErrorPos(0)
{
// mUserVariables = new calc_map_t;
mVariables = new calc_map_t;
mConstants = new calc_map_t;
// Init table of constants
(*mConstants)["PI"] = F_PI;
(*mConstants)["TWO_PI"] = F_TWO_PI;
(*mConstants)["PI_BY_TWO"] = F_PI_BY_TWO;
(*mConstants)["SQRT2"] = F_SQRT2;
(*mConstants)["DEG_TO_RAD"] = DEG_TO_RAD;
(*mConstants)["RAD_TO_DEG"] = RAD_TO_DEG;
(*mConstants)["GRAVITY"] = GRAVITY;
(*mConstants)["ALMOST_ZERO"] = F_ALMOST_ZERO;
(*mConstants)["ALMOST_ONE"] = F_ALMOST_ONE;
(*mConstants)["THE_ANSWER"] = 42;
mConstants["PI"] = F_PI;
mConstants["TWO_PI"] = F_TWO_PI;
mConstants["PI_BY_TWO"] = F_PI_BY_TWO;
mConstants["SQRT_TWO_PI"] = F_SQRT_TWO_PI;
mConstants["SQRT2"] = F_SQRT2;
mConstants["SQRT3"] = F_SQRT3;
mConstants["DEG_TO_RAD"] = DEG_TO_RAD;
mConstants["RAD_TO_DEG"] = RAD_TO_DEG;
mConstants["GRAVITY"] = GRAVITY;
}
LLCalc::~LLCalc()
{
delete mConstants;
delete mVariables;
// delete mUserVariables;
}
//static
@@ -94,17 +86,17 @@ LLCalc* LLCalc::getInstance()
void LLCalc::setVar(const std::string& name, const F32& value)
{
(*mVariables)[name] = value;
mVariables[name] = value;
}
void LLCalc::clearVar(const std::string& name)
{
mVariables->erase(name);
mVariables.erase(name);
}
void LLCalc::clearAllVariables()
{
mVariables->clear();
mVariables.clear();
}
/*
@@ -123,7 +115,7 @@ bool LLCalc::evalString(const std::string& expression, F32& result)
std::string expr_upper = expression;
LLStringUtil::toUpper(expr_upper);
LLCalcParser calc(result, mConstants, mVariables);
LLCalcParser calc(result, &mConstants, &mVariables);
mLastErrorPos = 0;
std::string::iterator start = expr_upper.begin();

View File

@@ -69,8 +69,8 @@ public:
private:
std::string::size_type mLastErrorPos;
calc_map_t* mConstants;
calc_map_t* mVariables;
calc_map_t mConstants;
calc_map_t mVariables;
// *TODO: Add support for storing user defined variables, and stored functions.
// Will need UI work, and a means to save them between sessions.

View File

@@ -73,7 +73,9 @@ struct LLCalcParser : grammar<LLCalcParser>
(str_p("SQRT") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_sqrt)(self,arg1)]) |
(str_p("LOG") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_log)(self,arg1)]) |
(str_p("EXP") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_exp)(self,arg1)]) |
(str_p("ABS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_fabs)(self,arg1)])
(str_p("ABS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_fabs)(self,arg1)]) |
(str_p("FLR") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_floor)(self,arg1)]) |
(str_p("CEIL") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_ceil)(self,arg1)])
) >> assert_syntax(ch_p(')'))
;
@@ -118,7 +120,8 @@ struct LLCalcParser : grammar<LLCalcParser>
term =
power[term.value = arg1] >>
*(('*' >> assert_syntax(power[term.value *= arg1])) |
('/' >> assert_syntax(power[term.value /= arg1]))
('/' >> assert_syntax(power[term.value /= arg1])) |
('%' >> assert_syntax(power[term.value = bind(&fmodf)(term.value, arg1)]))
)
;
@@ -153,7 +156,9 @@ private:
F32 _sqrt(const F32& a) const { return sqrt(a); }
F32 _log(const F32& a) const { return log(a); }
F32 _exp(const F32& a) const { return exp(a); }
F32 _fabs(const F32& a) const { return fabs(a) * RAD_TO_DEG; }
F32 _fabs(const F32& a) const { return fabs(a); }
F32 _floor(const F32& a) const { return llfloor(a); }
F32 _ceil(const F32& a) const { return llceil(a); }
F32 _atan2(const F32& a,const F32& b) const { return atan2(a,b); }

View File

@@ -92,7 +92,7 @@ F32 LLCamera::getMaxView() const
// ---------------- LLCamera::setFoo() member functions ----------------
void LLCamera::setUserClipPlane(LLPlane const& plane)
void LLCamera::setUserClipPlane(const LLPlane& plane)
{
mPlaneCount = 7;
mAgentPlanes[6] = plane;
@@ -168,166 +168,91 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer)
// ---------------- test methods ----------------
S32 LLCamera::AABBInFrustum(const LLVector3 &center, const LLVector3& radius)
S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius)
{
static const LLVector3 scaler[] = {
LLVector3(-1,-1,-1),
LLVector3( 1,-1,-1),
LLVector3(-1, 1,-1),
LLVector3( 1, 1,-1),
LLVector3(-1,-1, 1),
LLVector3( 1,-1, 1),
LLVector3(-1, 1, 1),
LLVector3( 1, 1, 1)
static const LLVector4a scaler[] = {
LLVector4a(-1,-1,-1),
LLVector4a( 1,-1,-1),
LLVector4a(-1, 1,-1),
LLVector4a( 1, 1,-1),
LLVector4a(-1,-1, 1),
LLVector4a( 1,-1, 1),
LLVector4a(-1, 1, 1),
LLVector4a( 1, 1, 1)
};
U8 mask = 0;
S32 result = 2;
/*if (radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist)
{ //box is larger than frustum, check frustum quads against box planes
static const LLVector3 dir[] =
{
LLVector3(1, 0, 0),
LLVector3(-1, 0, 0),
LLVector3(0, 1, 0),
LLVector3(0, -1, 0),
LLVector3(0, 0, 1),
LLVector3(0, 0, -1)
};
U32 quads[] =
{
0, 1, 2, 3,
0, 1, 5, 4,
2, 3, 7, 6,
3, 0, 7, 4,
1, 2, 6, 4,
4, 5, 6, 7
};
result = 0;
BOOL total_inside = TRUE;
for (U32 i = 0; i < 6; i++)
{
LLVector3 p = center + radius.scaledVec(dir[i]);
F32 d = -p*dir[i];
for (U32 j = 0; j < 6; j++)
{ //for each quad
F32 dist = mAgentFrustum[quads[j*4+0]]*dir[i] + d;
if (dist > 0)
{ //at least one frustum point is outside the AABB
total_inside = FALSE;
for (U32 k = 1; k < 4; k++)
{ //for each other point on quad
if ( mAgentFrustum[quads[j*4+k]]*dir[i]+d <= 0.f)
{ //quad is straddling some plane of AABB
return 1;
}
}
}
else
{
for (U32 k = 1; k < 4; k++)
{
if (mAgentFrustum[quads[j*4+k]]*dir[i]+d > 0.f)
{
return 1;
}
}
}
}
}
if (total_inside)
{
result = 1;
}
}
else*/
bool result = false;
LLVector4a rscale, maxp, minp;
LLSimdScalar d;
for (U32 i = 0; i < mPlaneCount; i++)
{
for (U32 i = 0; i < mPlaneCount; i++)
mask = mPlaneMask[i];
if (mask != 0xff)
{
mask = mPlaneMask[i];
if (mask == 0xff)
{
continue;
}
LLPlane p = mAgentPlanes[i];
LLVector3 n = LLVector3(p);
float d = p.mV[3];
LLVector3 rscale = radius.scaledVec(scaler[mask]);
LLVector3 minp = center - rscale;
LLVector3 maxp = center + rscale;
if (n * minp > -d)
const LLPlane& p(mAgentPlanes[i]);
p.getAt<3>(d);
rscale.setMul(radius, scaler[mask]);
minp.setSub(center, rscale);
d = -d;
if (p.dot3(minp).getF32() > d)
{
return 0;
}
if (n * maxp > -d)
if(!result)
{
result = 1;
maxp.setAdd(center, rscale);
result = (p.dot3(maxp).getF32() > d);
}
}
}
return result;
return result?1:2;
}
S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& radius)
S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius)
{
static const LLVector3 scaler[] = {
LLVector3(-1,-1,-1),
LLVector3( 1,-1,-1),
LLVector3(-1, 1,-1),
LLVector3( 1, 1,-1),
LLVector3(-1,-1, 1),
LLVector3( 1,-1, 1),
LLVector3(-1, 1, 1),
LLVector3( 1, 1, 1)
static const LLVector4a scaler[] = {
LLVector4a(-1,-1,-1),
LLVector4a( 1,-1,-1),
LLVector4a(-1, 1,-1),
LLVector4a( 1, 1,-1),
LLVector4a(-1,-1, 1),
LLVector4a( 1,-1, 1),
LLVector4a(-1, 1, 1),
LLVector4a( 1, 1, 1)
};
U8 mask = 0;
S32 result = 2;
bool result = false;
LLVector4a rscale, maxp, minp;
LLSimdScalar d;
for (U32 i = 0; i < mPlaneCount; i++)
{
if (i == 5)
{
continue;
}
mask = mPlaneMask[i];
if (mask == 0xff)
if ((i != 5) && (mask != 0xff))
{
continue;
}
LLPlane p = mAgentPlanes[i];
LLVector3 n = LLVector3(p);
float d = p.mV[3];
LLVector3 rscale = radius.scaledVec(scaler[mask]);
LLVector3 minp = center - rscale;
LLVector3 maxp = center + rscale;
if (n * minp > -d)
{
return 0;
}
if (n * maxp > -d)
{
result = 1;
const LLPlane& p(mAgentPlanes[i]);
p.getAt<3>(d);
rscale.setMul(radius, scaler[mask]);
minp.setSub(center, rscale);
d = -d;
if (p.dot3(minp).getF32() > d)
{
return 0;
}
if(!result)
{
maxp.setAdd(center, rscale);
result = (p.dot3(maxp).getF32() > d);
}
}
}
return result;
return result?1:2;
}
int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius)
@@ -715,9 +640,10 @@ void LLCamera::calculateWorldFrustumPlanes()
F32 d;
LLVector3 center = mOrigin - mXAxis*mNearPlane;
mWorldPlanePos = center;
LLVector3 pnorm;
for (int p=0; p<4; p++)
{
LLVector3 pnorm = LLVector3(mLocalPlanes[p]);
mLocalPlanes[p].getVector3(pnorm);
LLVector3 norm = rotateToAbsolute(pnorm);
norm.normVec();
d = -(center * norm);
@@ -727,13 +653,15 @@ void LLCamera::calculateWorldFrustumPlanes()
LLVector3 zaxis(0, 0, 1.0f);
F32 yaw = getYaw();
{
LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_LEFT]);
LLVector3 tnorm;
mLocalPlanes[PLANE_LEFT].getVector3(tnorm);
tnorm.rotVec(yaw, zaxis);
d = -(mOrigin * tnorm);
mHorizPlanes[HORIZ_PLANE_LEFT] = LLPlane(tnorm, d);
}
{
LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_RIGHT]);
LLVector3 tnorm;
mLocalPlanes[PLANE_RIGHT].getVector3(tnorm);
tnorm.rotVec(yaw, zaxis);
d = -(mOrigin * tnorm);
mHorizPlanes[HORIZ_PLANE_RIGHT] = LLPlane(tnorm, d);

View File

@@ -37,6 +37,7 @@
#include "llmath.h"
#include "llcoordframe.h"
#include "llplane.h"
#include "llvector4a.h"
const F32 DEFAULT_FIELD_OF_VIEW = 60.f * DEG_TO_RAD;
const F32 DEFAULT_ASPECT_RATIO = 640.f / 480.f;
@@ -143,7 +144,7 @@ public:
virtual ~LLCamera();
void setUserClipPlane(LLPlane const& plane);
void setUserClipPlane(const LLPlane& plane);
void disableUserClipPlane();
virtual void setView(F32 vertical_fov_rads);
void setViewHeightInPixels(S32 height);
@@ -191,8 +192,8 @@ public:
S32 sphereInFrustum(const LLVector3 &center, const F32 radius) const;
S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
S32 sphereInFrustumFull(const LLVector3 &center, const F32 radius) const { return sphereInFrustum(center, radius); }
S32 AABBInFrustum(const LLVector3 &center, const LLVector3& radius);
S32 AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& radius);
S32 AABBInFrustum(const LLVector4a& center, const LLVector4a& radius);
S32 AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius);
//does a quick 'n dirty sphere-sphere check
S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius);

View File

@@ -38,6 +38,7 @@
// So, let's define _USE_MATH_DEFINES before including math.h
#define _USE_MATH_DEFINES
#endif
#include "math.h"
// Class from which different types of interpolators can be derived

View File

@@ -35,10 +35,10 @@
#include <cmath>
#include <cstdlib>
#include <complex>
#include <vector>
#include "lldefs.h"
#include "llstl.h" // *TODO: Remove when LLString is gone
#include "llstring.h" // *TODO: Remove when LLString is gone
//#include "llstl.h" // *TODO: Remove when LLString is gone
//#include "llstring.h" // *TODO: Remove when LLString is gone
// lltut.h uses is_approx_equal_fraction(). This was moved to its own header
// file in llcommon so we can use lltut.h for llcommon tests without making
// llcommon depend on llmath.
@@ -61,32 +61,11 @@
#endif
// Single Precision Floating Point Routines
#ifndef sqrtf
#define sqrtf(x) ((F32)sqrt((F64)(x)))
#endif
#ifndef fsqrtf
#define fsqrtf(x) sqrtf(x)
#endif
#ifndef cosf
#define cosf(x) ((F32)cos((F64)(x)))
#endif
#ifndef sinf
#define sinf(x) ((F32)sin((F64)(x)))
#endif
#ifndef tanf
// (There used to be more defined here, but they appeared to be redundant and
// were breaking some other includes. Removed by Falcon, reviewed by Andrew, 11/25/09)
/*#ifndef tanf
#define tanf(x) ((F32)tan((F64)(x)))
#endif
#ifndef acosf
#define acosf(x) ((F32)acos((F64)(x)))
#endif
#ifndef powf
#define powf(x,y) ((F32)pow((F64)(x),(F64)(y)))
#endif
#ifndef expf
#define expf(x) ((F32)exp((F64)(x)))
#endif
#endif*/
const F32 GRAVITY = -9.8f;
@@ -206,7 +185,7 @@ inline S32 llfloor( F32 f )
}
return result;
#else
return (S32)floorf(f);
return (S32)floor(f);
#endif
}
@@ -537,6 +516,12 @@ inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k)
VEC_TYPE Q1 = data[data.size()/4];
VEC_TYPE Q3 = data[data.size()-data.size()/4-1];
if ((F32)(Q3-Q1) < 1.f)
{
// not enough variation to detect outliers
return;
}
VEC_TYPE min = (VEC_TYPE) ((F32) Q1-k * (F32) (Q3-Q1));
VEC_TYPE max = (VEC_TYPE) ((F32) Q3+k * (F32) (Q3-Q1));
@@ -562,4 +547,7 @@ inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k)
data.erase(data.begin(), data.begin()+i);
}
}
// Include simd math header
#include "llsimdmath.h"
#endif

134
indra/llmath/llmatrix3a.cpp Normal file
View File

@@ -0,0 +1,134 @@
/**
* @file llvector4a.cpp
* @brief SIMD vector implementation
*
* $LicenseInfo:firstyear=2010&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 "llmath.h"
static LL_ALIGN_16(const F32 M_IDENT_3A[12]) =
{ 1.f, 0.f, 0.f, 0.f, // Column 1
0.f, 1.f, 0.f, 0.f, // Column 2
0.f, 0.f, 1.f, 0.f }; // Column 3
extern const LLMatrix3a LL_M3A_IDENTITY = *reinterpret_cast<const LLMatrix3a*> (M_IDENT_3A);
void LLMatrix3a::setMul( const LLMatrix3a& lhs, const LLMatrix3a& rhs )
{
const LLVector4a col0 = lhs.getColumn(0);
const LLVector4a col1 = lhs.getColumn(1);
const LLVector4a col2 = lhs.getColumn(2);
for ( int i = 0; i < 3; i++ )
{
LLVector4a xxxx = _mm_load_ss( rhs.mColumns[i].getF32ptr() );
xxxx.splat<0>( xxxx );
xxxx.mul( col0 );
{
LLVector4a yyyy = _mm_load_ss( rhs.mColumns[i].getF32ptr() + 1 );
yyyy.splat<0>( yyyy );
yyyy.mul( col1 );
xxxx.add( yyyy );
}
{
LLVector4a zzzz = _mm_load_ss( rhs.mColumns[i].getF32ptr() + 2 );
zzzz.splat<0>( zzzz );
zzzz.mul( col2 );
xxxx.add( zzzz );
}
xxxx.store4a( mColumns[i].getF32ptr() );
}
}
/*static */void LLMatrix3a::batchTransform( const LLMatrix3a& xform, const LLVector4a* src, int numVectors, LLVector4a* dst )
{
const LLVector4a col0 = xform.getColumn(0);
const LLVector4a col1 = xform.getColumn(1);
const LLVector4a col2 = xform.getColumn(2);
const LLVector4a* maxAddr = src + numVectors;
if ( numVectors & 0x1 )
{
LLVector4a xxxx = _mm_load_ss( (const F32*)src );
LLVector4a yyyy = _mm_load_ss( (const F32*)src + 1 );
LLVector4a zzzz = _mm_load_ss( (const F32*)src + 2 );
xxxx.splat<0>( xxxx );
yyyy.splat<0>( yyyy );
zzzz.splat<0>( zzzz );
xxxx.mul( col0 );
yyyy.mul( col1 );
zzzz.mul( col2 );
xxxx.add( yyyy );
xxxx.add( zzzz );
xxxx.store4a( (F32*)dst );
src++;
dst++;
}
numVectors >>= 1;
while ( src < maxAddr )
{
_mm_prefetch( (const char*)(src + 32 ), _MM_HINT_NTA );
_mm_prefetch( (const char*)(dst + 32), _MM_HINT_NTA );
LLVector4a xxxx = _mm_load_ss( (const F32*)src );
LLVector4a xxxx1= _mm_load_ss( (const F32*)(src + 1) );
xxxx.splat<0>( xxxx );
xxxx1.splat<0>( xxxx1 );
xxxx.mul( col0 );
xxxx1.mul( col0 );
{
LLVector4a yyyy = _mm_load_ss( (const F32*)src + 1 );
LLVector4a yyyy1 = _mm_load_ss( (const F32*)(src + 1) + 1);
yyyy.splat<0>( yyyy );
yyyy1.splat<0>( yyyy1 );
yyyy.mul( col1 );
yyyy1.mul( col1 );
xxxx.add( yyyy );
xxxx1.add( yyyy1 );
}
{
LLVector4a zzzz = _mm_load_ss( (const F32*)(src) + 2 );
LLVector4a zzzz1 = _mm_load_ss( (const F32*)(++src) + 2 );
zzzz.splat<0>( zzzz );
zzzz1.splat<0>( zzzz1 );
zzzz.mul( col2 );
zzzz1.mul( col2 );
xxxx.add( zzzz );
xxxx1.add( zzzz1 );
}
xxxx.store4a(dst->getF32ptr());
src++;
dst++;
xxxx1.store4a((F32*)dst++);
}
}

128
indra/llmath/llmatrix3a.h Normal file
View File

@@ -0,0 +1,128 @@
/**
* @file llmatrix3a.h
* @brief LLMatrix3a class header file - memory aligned and vectorized 3x3 matrix
*
* $LicenseInfo:firstyear=2010&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_LLMATRIX3A_H
#define LL_LLMATRIX3A_H
/////////////////////////////
// LLMatrix3a, LLRotation
/////////////////////////////
// This class stores a 3x3 (technically 4x3) matrix in column-major order
/////////////////////////////
/////////////////////////////
// These classes are intentionally minimal right now. If you need additional
// functionality, please contact someone with SSE experience (e.g., Falcon or
// Huseby).
/////////////////////////////
// LLMatrix3a is the base class for LLRotation, which should be used instead any time you're dealing with a
// rotation matrix.
class LLMatrix3a
{
public:
// Utility function for quickly transforming an array of LLVector4a's
// For transforming a single LLVector4a, see LLVector4a::setRotated
static void batchTransform( const LLMatrix3a& xform, const LLVector4a* src, int numVectors, LLVector4a* dst );
// Utility function to obtain the identity matrix
static inline const LLMatrix3a& getIdentity();
//////////////////////////
// Ctors
//////////////////////////
// Ctor
LLMatrix3a() {}
// Ctor for setting by columns
inline LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 );
//////////////////////////
// Get/Set
//////////////////////////
// Loads from an LLMatrix3
inline void loadu(const LLMatrix3& src);
// Set rows
inline void setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2);
// Set columns
inline void setColumns(const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2);
// Get the read-only access to a specified column. Valid columns are 0-2, but the
// function is unchecked. You've been warned.
inline const LLVector4a& getColumn(const U32 column) const;
/////////////////////////
// Matrix modification
/////////////////////////
// Set this matrix to the product of lhs and rhs ( this = lhs * rhs )
void setMul( const LLMatrix3a& lhs, const LLMatrix3a& rhs );
// Set this matrix to the transpose of src
inline void setTranspose(const LLMatrix3a& src);
// Set this matrix to a*w + b*(1-w)
inline void setLerp(const LLMatrix3a& a, const LLMatrix3a& b, F32 w);
/////////////////////////
// Matrix inspection
/////////////////////////
// Sets all 4 elements in 'dest' to the determinant of this matrix.
// If you will be using the determinant in subsequent ops with LLVector4a, use this version
inline void getDeterminant( LLVector4a& dest ) const;
// Returns the determinant as an LLSimdScalar. Use this if you will be using the determinant
// primary for scalar operations.
inline LLSimdScalar getDeterminant() const;
// Returns nonzero if rows 0-2 and colums 0-2 contain no NaN or INF values. Row 3 is ignored
inline LLBool32 isFinite() const;
// Returns true if this matrix is equal to 'rhs' up to 'tolerance'
inline bool isApproximatelyEqual( const LLMatrix3a& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const;
protected:
LLVector4a mColumns[3];
};
class LLRotation : public LLMatrix3a
{
public:
LLRotation() {}
// Returns true if this rotation is orthonormal with det ~= 1
inline bool isOkRotation() const;
};
#endif

119
indra/llmath/llmatrix3a.inl Normal file
View File

@@ -0,0 +1,119 @@
/**
* @file llmatrix3a.inl
* @brief LLMatrix3a inline definitions
*
* $LicenseInfo:firstyear=2010&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 "llmatrix3a.h"
#include "m3math.h"
inline LLMatrix3a::LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 )
{
setColumns( c0, c1, c2 );
}
inline void LLMatrix3a::loadu(const LLMatrix3& src)
{
mColumns[0].load3(src.mMatrix[0]);
mColumns[1].load3(src.mMatrix[1]);
mColumns[2].load3(src.mMatrix[2]);
}
inline void LLMatrix3a::setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2)
{
mColumns[0] = r0;
mColumns[1] = r1;
mColumns[2] = r2;
setTranspose( *this );
}
inline void LLMatrix3a::setColumns(const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2)
{
mColumns[0] = c0;
mColumns[1] = c1;
mColumns[2] = c2;
}
inline void LLMatrix3a::setTranspose(const LLMatrix3a& src)
{
const LLQuad srcCol0 = src.mColumns[0];
const LLQuad srcCol1 = src.mColumns[1];
const LLQuad unpacklo = _mm_unpacklo_ps( srcCol0, srcCol1 );
mColumns[0] = _mm_movelh_ps( unpacklo, src.mColumns[2] );
mColumns[1] = _mm_shuffle_ps( _mm_movehl_ps( srcCol0, unpacklo ), src.mColumns[2], _MM_SHUFFLE(0, 1, 1, 0) );
mColumns[2] = _mm_shuffle_ps( _mm_unpackhi_ps( srcCol0, srcCol1 ), src.mColumns[2], _MM_SHUFFLE(0, 2, 1, 0) );
}
inline const LLVector4a& LLMatrix3a::getColumn(const U32 column) const
{
llassert( column < 3 );
return mColumns[column];
}
inline void LLMatrix3a::setLerp(const LLMatrix3a& a, const LLMatrix3a& b, F32 w)
{
mColumns[0].setLerp( a.mColumns[0], b.mColumns[0], w );
mColumns[1].setLerp( a.mColumns[1], b.mColumns[1], w );
mColumns[2].setLerp( a.mColumns[2], b.mColumns[2], w );
}
inline LLBool32 LLMatrix3a::isFinite() const
{
return mColumns[0].isFinite3() && mColumns[1].isFinite3() && mColumns[2].isFinite3();
}
inline void LLMatrix3a::getDeterminant( LLVector4a& dest ) const
{
LLVector4a col1xcol2; col1xcol2.setCross3( mColumns[1], mColumns[2] );
dest.setAllDot3( col1xcol2, mColumns[0] );
}
inline LLSimdScalar LLMatrix3a::getDeterminant() const
{
LLVector4a col1xcol2; col1xcol2.setCross3( mColumns[1], mColumns[2] );
return col1xcol2.dot3( mColumns[0] );
}
inline bool LLMatrix3a::isApproximatelyEqual( const LLMatrix3a& rhs, F32 tolerance /*= F_APPROXIMATELY_ZERO*/ ) const
{
return rhs.getColumn(0).equals3(mColumns[0], tolerance)
&& rhs.getColumn(1).equals3(mColumns[1], tolerance)
&& rhs.getColumn(2).equals3(mColumns[2], tolerance);
}
inline const LLMatrix3a& LLMatrix3a::getIdentity()
{
extern const LLMatrix3a LL_M3A_IDENTITY;
return LL_M3A_IDENTITY;
}
inline bool LLRotation::isOkRotation() const
{
LLMatrix3a transpose; transpose.setTranspose( *this );
LLMatrix3a product; product.setMul( *this, transpose );
LLSimdScalar detMinusOne = getDeterminant() - 1.f;
return product.isApproximatelyEqual( LLMatrix3a::getIdentity() ) && (detMinusOne.getAbs() < F_APPROXIMATELY_ZERO);
}

Some files were not shown because too many files have changed in this diff Show More