From 89fe5dab825a62a0e3fd8d248cbc91c65eb2a426 Mon Sep 17 00:00:00 2001 From: Jacek Antonelli Date: Fri, 15 Aug 2008 23:44:50 -0500 Subject: Second Life viewer sources 1.14.0.0 --- linden/indra/llcommon/files.lst | 6 +- linden/indra/llcommon/imageids.h | 2 +- linden/indra/llcommon/indra_constants.h | 12 +- linden/indra/llcommon/linden_common.h | 1 + linden/indra/llcommon/llapp.cpp | 8 +- linden/indra/llcommon/llapr.cpp | 174 ++++- linden/indra/llcommon/llapr.h | 18 +- linden/indra/llcommon/llassettype.cpp | 14 + linden/indra/llcommon/llassettype.h | 1 + linden/indra/llcommon/llavatarconstants.h | 12 +- linden/indra/llcommon/llbase32.cpp | 214 ++++++ linden/indra/llcommon/llbase32.h | 38 + linden/indra/llcommon/llbase64.cpp | 62 ++ linden/indra/llcommon/llbase64.h | 38 + linden/indra/llcommon/llcommon.cpp | 1 + linden/indra/llcommon/llcommon.h | 1 - linden/indra/llcommon/llcommon.vcproj | 38 +- linden/indra/llcommon/llcommon_vc8.vcproj | 759 +++++++++++++++++++ linden/indra/llcommon/llerror.cpp | 1043 ++++++++++++++++++++++++++- linden/indra/llcommon/llerror.h | 404 +++++------ linden/indra/llcommon/llerrorbuffer.cpp | 279 ------- linden/indra/llcommon/llerrorbuffer.h | 117 --- linden/indra/llcommon/llerrorcontrol.h | 142 ++++ linden/indra/llcommon/llerrorlegacy.h | 117 +++ linden/indra/llcommon/llerrorstream.cpp | 188 ----- linden/indra/llcommon/llerrorstream.h | 126 ---- linden/indra/llcommon/llevent.cpp | 10 +- linden/indra/llcommon/llevent.h | 2 + linden/indra/llcommon/llfasttimer.h | 27 + linden/indra/llcommon/llfile.cpp | 28 +- linden/indra/llcommon/llfile.h | 11 +- linden/indra/llcommon/llformat.cpp | 47 ++ linden/indra/llcommon/llformat.h | 42 ++ linden/indra/llcommon/llliveappconfig.cpp | 65 ++ linden/indra/llcommon/llliveappconfig.h | 52 ++ linden/indra/llcommon/lllivefile.cpp | 88 ++- linden/indra/llcommon/lllivefile.h | 21 +- linden/indra/llcommon/lllslconstants.h | 4 + linden/indra/llcommon/llmemory.cpp | 43 +- linden/indra/llcommon/llmemory.h | 200 +++-- linden/indra/llcommon/llmemtype.h | 1 + linden/indra/llcommon/llpreprocessor.h | 7 +- linden/indra/llcommon/llprocessor.cpp | 10 +- linden/indra/llcommon/llqueuedthread.cpp | 195 ++--- linden/indra/llcommon/llqueuedthread.h | 56 +- linden/indra/llcommon/llsd.cpp | 6 +- linden/indra/llcommon/llsdserialize.cpp | 4 +- linden/indra/llcommon/llsdserialize_xml.cpp | 1 + linden/indra/llcommon/llsecondlifeurls.cpp | 4 +- linden/indra/llcommon/llsecondlifeurls.h | 12 - linden/indra/llcommon/llstreamtools.cpp | 2 +- linden/indra/llcommon/llstrider.h | 1 + linden/indra/llcommon/llstring.cpp | 1 + linden/indra/llcommon/llstring.h | 13 +- linden/indra/llcommon/llstringtable.h | 5 +- linden/indra/llcommon/llsys.cpp | 12 +- linden/indra/llcommon/llthread.cpp | 63 +- linden/indra/llcommon/llthread.h | 75 +- linden/indra/llcommon/lluri.cpp | 482 ++++--------- linden/indra/llcommon/lluri.h | 90 ++- linden/indra/llcommon/llversion.h | 6 +- linden/indra/llcommon/llworkerthread.cpp | 325 +++++---- linden/indra/llcommon/llworkerthread.h | 85 ++- linden/indra/llcommon/metaproperty.cpp | 2 +- linden/indra/llcommon/u64.cpp | 14 +- 65 files changed, 4124 insertions(+), 1803 deletions(-) create mode 100644 linden/indra/llcommon/llbase32.cpp create mode 100644 linden/indra/llcommon/llbase32.h create mode 100644 linden/indra/llcommon/llbase64.cpp create mode 100644 linden/indra/llcommon/llbase64.h create mode 100644 linden/indra/llcommon/llcommon_vc8.vcproj delete mode 100644 linden/indra/llcommon/llerrorbuffer.cpp delete mode 100644 linden/indra/llcommon/llerrorbuffer.h create mode 100644 linden/indra/llcommon/llerrorcontrol.h create mode 100644 linden/indra/llcommon/llerrorlegacy.h delete mode 100644 linden/indra/llcommon/llerrorstream.cpp delete mode 100644 linden/indra/llcommon/llerrorstream.h create mode 100644 linden/indra/llcommon/llformat.cpp create mode 100644 linden/indra/llcommon/llformat.h create mode 100644 linden/indra/llcommon/llliveappconfig.cpp create mode 100644 linden/indra/llcommon/llliveappconfig.h (limited to 'linden/indra/llcommon') diff --git a/linden/indra/llcommon/files.lst b/linden/indra/llcommon/files.lst index 2482eec..5fcb8c7 100644 --- a/linden/indra/llcommon/files.lst +++ b/linden/indra/llcommon/files.lst @@ -2,18 +2,20 @@ llcommon/bitpack.cpp llcommon/llapp.cpp llcommon/llapr.cpp llcommon/llassettype.cpp +llcommon/llbase32.cpp +llcommon/llbase64.cpp llcommon/llcommon.cpp llcommon/llcriticaldamp.cpp llcommon/lldate.cpp -llcommon/llerrorbuffer.cpp llcommon/llerror.cpp -llcommon/llerrorstream.cpp llcommon/llerrorthread.cpp llcommon/llevent.cpp llcommon/llfasttimer.cpp llcommon/llfile.cpp llcommon/llfixedbuffer.cpp +llcommon/llformat.cpp llcommon/llframetimer.cpp +llcommon/llliveappconfig.cpp llcommon/lllivefile.cpp llcommon/llmemory.cpp llcommon/llmemorystream.cpp diff --git a/linden/indra/llcommon/imageids.h b/linden/indra/llcommon/imageids.h index 150322e..d65b374 100644 --- a/linden/indra/llcommon/imageids.h +++ b/linden/indra/llcommon/imageids.h @@ -50,7 +50,7 @@ const LLUUID IMG_CLEAR ("11ee27f5-43c0-414e-afd5-d7f5688c351f"); // VIEWER const LLUUID IMG_SMOKE ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER -const LLUUID IMG_DEFAULT ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER +const LLUUID IMG_DEFAULT ("d2114404-dd59-4a4d-8e6c-49359e91bbf0"); // VIEWER //const LLUUID IMG_SAND ("0ff70ead-4562-45f9-9e8a-52b1a3286868"); // VIEWER 1.5k //const LLUUID IMG_GRASS ("5ab48dd5-05d0-4f1a-ace6-efd4e2fb3508"); // VIEWER 1.2k diff --git a/linden/indra/llcommon/indra_constants.h b/linden/indra/llcommon/indra_constants.h index 31c2559..deb9c9d 100644 --- a/linden/indra/llcommon/indra_constants.h +++ b/linden/indra/llcommon/indra_constants.h @@ -28,6 +28,7 @@ #ifndef LL_INDRA_CONSTANTS_H #define LL_INDRA_CONSTANTS_H +#include "stdtypes.h" #include "lluuid.h" // Viewer object cache version, change if object update @@ -105,8 +106,8 @@ const char* const DEFAULT_LOCAL_ASSET_SERVER = "http://localhost:12041/asset/tmp const char* const LOCAL_ASSET_URL_FORMAT = "http://%s:12041/asset"; const U32 DEFAULT_LAUNCHER_PORT = 12029; -const U32 DEFAULT_BIGBOARD_PORT = 12030; -const U32 DEFAULT_QUERYSIM_PORT = 12031; +//const U32 DEFAULT_BIGBOARD_PORT = 12030; // Deprecated +//const U32 DEFAULT_QUERYSIM_PORT = 12031; // Deprecated const U32 DEFAULT_DATA_SERVER_PORT = 12032; const U32 DEFAULT_SPACE_SERVER_PORT = 12033; const U32 DEFAULT_VIEWER_PORT = 12034; @@ -115,8 +116,11 @@ const U32 DEFAULT_USER_SERVER_PORT = 12036; const U32 DEFAULT_RPC_SERVER_PORT = 12037; const U32 DEFAULT_LOG_DATA_SERVER_PORT = 12039; const U32 DEFAULT_BACKBONE_PORT = 12040; +const U32 DEFAULT_CGI_SERVICES_PORT = 12045; const U32 DEFAULT_LOCAL_ASSET_PORT = 12041; -const U32 DEFAULT_BACKBONE_CAP_PORT = 12042; +//const U32 DEFAULT_BACKBONE_CAP_PORT = 12042; // Deprecated +const U32 DEFAULT_CAP_PROXY_PORT = 12043; +const U32 DEFAULT_INV_DATA_SERVER_PORT = 12044; // For automatic port discovery when running multiple viewers on one host const U32 PORT_DISCOVERY_RANGE_MIN = 13000; @@ -322,7 +326,7 @@ const U32 MAP_ITEM_TELEHUB = 0x01; const U32 MAP_ITEM_PG_EVENT = 0x02; const U32 MAP_ITEM_MATURE_EVENT = 0x03; const U32 MAP_ITEM_POPULAR = 0x04; -const U32 MAP_ITEM_AGENT_COUNT = 0x05; +//const U32 MAP_ITEM_AGENT_COUNT = 0x05; const U32 MAP_ITEM_AGENT_LOCATIONS = 0x06; const U32 MAP_ITEM_LAND_FOR_SALE = 0x07; const U32 MAP_ITEM_CLASSIFIED = 0x08; diff --git a/linden/indra/llcommon/linden_common.h b/linden/indra/llcommon/linden_common.h index ff77b3d..b1c5f3b 100644 --- a/linden/indra/llcommon/linden_common.h +++ b/linden/indra/llcommon/linden_common.h @@ -49,6 +49,7 @@ #include "stdtypes.h" #include "lldefs.h" #include "llerror.h" +#include "llformat.h" #include "llstring.h" #include "lltimer.h" #include "llfasttimer.h" diff --git a/linden/indra/llcommon/llapp.cpp b/linden/indra/llcommon/llapp.cpp index 42d9050..f48ff8f 100644 --- a/linden/indra/llcommon/llapp.cpp +++ b/linden/indra/llcommon/llapp.cpp @@ -30,9 +30,11 @@ #include "llcommon.h" #include "llapr.h" +#include "llerrorcontrol.h" #include "llerrorthread.h" #include "llframetimer.h" #include "llmemory.h" +#include "lltimer.h" // // Signal handling @@ -193,10 +195,8 @@ LLSD LLApp::getOptionData(OptionPriority level) void LLApp::stepFrame() { - // Update the static frame timer. LLFrameTimer::updateFrameTime(); - - // Run ready runnables + LLEventTimer::updateClass(); mRunner.run(); } @@ -563,7 +563,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) else { // Don't log anything, even errors - this is because this signal could happen anywhere. - gErrorStream.setLevel(LLErrorStream::NONE); + LLError::setDefaultLevel(LLError::LEVEL_NONE); } // Change the signal that we reraise to SIGABRT, so we generate a core dump. diff --git a/linden/indra/llcommon/llapr.cpp b/linden/indra/llcommon/llapr.cpp index 665ee75..550a8d8 100644 --- a/linden/indra/llcommon/llapr.cpp +++ b/linden/indra/llcommon/llapr.cpp @@ -122,11 +122,13 @@ void ll_apr_assert_status(apr_status_t status) llassert(ll_apr_warn_status(status) == false); } -apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep) +// File I/O +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep, apr_pool_t* pool) { apr_file_t* apr_file; apr_status_t s; - s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp); + if (pool == NULL) pool = gAPRPoolp; + s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, pool); if (s != APR_SUCCESS) { if (sizep) @@ -142,6 +144,7 @@ apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* s apr_off_t offset = 0; if (apr_file_seek(apr_file, APR_END, &offset) == APR_SUCCESS) { + llassert_always(offset <= 0x7fffffff); file_size = (S32)offset; offset = 0; apr_file_seek(apr_file, APR_SET, &offset); @@ -151,6 +154,18 @@ apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* s return apr_file; } +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep) +{ + return ll_apr_file_open(filename, flags, sizep, NULL); +} +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, apr_pool_t* pool) +{ + return ll_apr_file_open(filename, flags, NULL, pool); +} +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags) +{ + return ll_apr_file_open(filename, flags, NULL, NULL); +} S32 ll_apr_file_read(apr_file_t* apr_file, void *buf, S32 nbytes) { @@ -162,10 +177,37 @@ S32 ll_apr_file_read(apr_file_t* apr_file, void *buf, S32 nbytes) } else { + llassert_always(sz <= 0x7fffffff); return (S32)sz; } } +S32 ll_apr_file_read_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes) +{ + if (pool == NULL) pool = gAPRPoolp; + apr_file_t* filep = ll_apr_file_open(filename, APR_READ|APR_BINARY, pool); + if (!filep) + { + return 0; + } + S32 off; + if (offset < 0) + off = ll_apr_file_seek(filep, APR_END, 0); + else + off = ll_apr_file_seek(filep, APR_SET, offset); + S32 bytes_read; + if (off < 0) + { + bytes_read = 0; + } + else + { + bytes_read = ll_apr_file_read(filep, buf, nbytes ); + } + apr_file_close(filep); + + return bytes_read; +} S32 ll_apr_file_write(apr_file_t* apr_file, const void *buf, S32 nbytes) { @@ -177,28 +219,73 @@ S32 ll_apr_file_write(apr_file_t* apr_file, const void *buf, S32 nbytes) } else { + llassert_always(sz <= 0x7fffffff); return (S32)sz; } } +S32 ll_apr_file_write_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes) +{ + if (pool == NULL) pool = gAPRPoolp; + apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; + if (offset < 0) + { + flags |= APR_APPEND; + offset = 0; + } + apr_file_t* filep = ll_apr_file_open(filename, flags, pool); + if (!filep) + { + return 0; + } + if (offset > 0) + { + offset = ll_apr_file_seek(filep, APR_SET, offset); + } + S32 bytes_written; + if (offset < 0) + { + bytes_written = 0; + } + else + { + bytes_written = ll_apr_file_write(filep, buf, nbytes ); + } + apr_file_close(filep); + + return bytes_written; +} + S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset) { - apr_off_t apr_offset = offset; - apr_status_t s = apr_file_seek(apr_file, where, &apr_offset); + apr_status_t s; + apr_off_t apr_offset; + if (offset >= 0) + { + apr_offset = (apr_off_t)offset; + s = apr_file_seek(apr_file, where, &apr_offset); + } + else + { + apr_offset = 0; + s = apr_file_seek(apr_file, APR_END, &apr_offset); + } if (s != APR_SUCCESS) { return -1; } else { + llassert_always(apr_offset <= 0x7fffffff); return (S32)apr_offset; } } -bool ll_apr_file_remove(const LLString& filename) +bool ll_apr_file_remove(const LLString& filename, apr_pool_t* pool) { apr_status_t s; - s = apr_file_remove(filename.c_str(), gAPRPoolp); + if (pool == NULL) pool = gAPRPoolp; + s = apr_file_remove(filename.c_str(), pool); if (s != APR_SUCCESS) { llwarns << "ll_apr_file_remove failed on file: " << filename << llendl; @@ -207,10 +294,11 @@ bool ll_apr_file_remove(const LLString& filename) return true; } -bool ll_apr_file_rename(const LLString& filename, const LLString& newname) +bool ll_apr_file_rename(const LLString& filename, const LLString& newname, apr_pool_t* pool) { apr_status_t s; - s = apr_file_rename(filename.c_str(), newname.c_str(), gAPRPoolp); + if (pool == NULL) pool = gAPRPoolp; + s = apr_file_rename(filename.c_str(), newname.c_str(), pool); if (s != APR_SUCCESS) { llwarns << "ll_apr_file_rename failed on file: " << filename << llendl; @@ -218,3 +306,73 @@ bool ll_apr_file_rename(const LLString& filename, const LLString& newname) } return true; } + +bool ll_apr_file_exists(const LLString& filename, apr_pool_t* pool) +{ + apr_file_t* apr_file; + apr_status_t s; + if (pool == NULL) pool = gAPRPoolp; + s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool); + if (s != APR_SUCCESS || !apr_file) + { + return false; + } + else + { + apr_file_close(apr_file); + return true; + } +} + +S32 ll_apr_file_size(const LLString& filename, apr_pool_t* pool) +{ + apr_file_t* apr_file; + apr_finfo_t info; + apr_status_t s; + if (pool == NULL) pool = gAPRPoolp; + s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, pool); + if (s != APR_SUCCESS || !apr_file) + { + return 0; + } + else + { + apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file); + apr_file_close(apr_file); + if (s == APR_SUCCESS) + { + return (S32)info.size; + } + else + { + return 0; + } + } +} + +bool ll_apr_dir_make(const LLString& dirname, apr_pool_t* pool) +{ + apr_status_t s; + if (pool == NULL) pool = gAPRPoolp; + s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, pool); + if (s != APR_SUCCESS) + { + llwarns << "ll_apr_file_remove failed on file: " << dirname << llendl; + return false; + } + return true; +} + +bool ll_apr_dir_remove(const LLString& dirname, apr_pool_t* pool) +{ + apr_status_t s; + if (pool == NULL) pool = gAPRPoolp; + s = apr_file_remove(dirname.c_str(), pool); + if (s != APR_SUCCESS) + { + llwarns << "ll_apr_file_remove failed on file: " << dirname << llendl; + return false; + } + return true; +} + diff --git a/linden/indra/llcommon/llapr.h b/linden/indra/llcommon/llapr.h index a5c217c..be6fc6c 100644 --- a/linden/indra/llcommon/llapr.h +++ b/linden/indra/llcommon/llapr.h @@ -125,14 +125,24 @@ typedef LLAtomic32 LLAtomicS32; #define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb" #define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b" #define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b" -apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep = NULL); +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep, apr_pool_t* pool); +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, S32* sizep); +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags, apr_pool_t* pool); +apr_file_t* ll_apr_file_open(const LLString& filename, apr_int32_t flags); // Returns actual offset, -1 if seek fails S32 ll_apr_file_seek(apr_file_t* apr_file, apr_seek_where_t where, S32 offset); -// Returns bytes read/written, 0 if read/write fails +// Returns bytes read/written, 0 if read/write fails: S32 ll_apr_file_read(apr_file_t* apr_file, void* buf, S32 nbytes); +S32 ll_apr_file_read_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes); S32 ll_apr_file_write(apr_file_t* apr_file, const void* buf, S32 nbytes); -bool ll_apr_file_remove(const LLString& filename); -bool ll_apr_file_rename(const LLString& filename, const LLString& newname); +S32 ll_apr_file_write_ex(const LLString& filename, apr_pool_t* pool, void *buf, S32 offset, S32 nbytes); +// returns false if failure: +bool ll_apr_file_remove(const LLString& filename, apr_pool_t* pool = NULL); +bool ll_apr_file_rename(const LLString& filename, const LLString& newname, apr_pool_t* pool = NULL); +bool ll_apr_file_exists(const LLString& filename, apr_pool_t* pool = NULL); +S32 ll_apr_file_size(const LLString& filename, apr_pool_t* pool = NULL); +bool ll_apr_dir_make(const LLString& dirname, apr_pool_t* pool = NULL); +bool ll_apr_dir_remove(const LLString& dirname, apr_pool_t* pool = NULL); /** * @brief Function which approprately logs error or remains quiet on diff --git a/linden/indra/llcommon/llassettype.cpp b/linden/indra/llcommon/llassettype.cpp index 051092e..df00af8 100644 --- a/linden/indra/llcommon/llassettype.cpp +++ b/linden/indra/llcommon/llassettype.cpp @@ -203,6 +203,20 @@ const char* LLAssetType::lookupHumanReadable(LLAssetType::EType type) } } +// static +LLAssetType::EType LLAssetType::lookupHumanReadable( const char* name ) +{ + for( S32 i = 0; i < AT_COUNT; i++ ) + { + if( 0 == strcmp(name, mAssetTypeHumanNames[i]) ) + { + // match + return (EType)i; + } + } + return AT_NONE; +} + EDragAndDropType LLAssetType::lookupDragAndDropType( EType asset ) { switch( asset ) diff --git a/linden/indra/llcommon/llassettype.h b/linden/indra/llcommon/llassettype.h index 67dc3ef..da4cf0b 100644 --- a/linden/indra/llcommon/llassettype.h +++ b/linden/indra/llcommon/llassettype.h @@ -145,6 +145,7 @@ public: static const char* lookup(EType type); // translation from a type to a human readable form. + static EType lookupHumanReadable( const char* name ); static const char* lookupHumanReadable(EType type); static EDragAndDropType lookupDragAndDropType( EType ); diff --git a/linden/indra/llcommon/llavatarconstants.h b/linden/indra/llcommon/llavatarconstants.h index 3335949..1eb5b05 100644 --- a/linden/indra/llcommon/llavatarconstants.h +++ b/linden/indra/llcommon/llavatarconstants.h @@ -39,16 +39,16 @@ const char* const BLACKLIST_PROFILE_WEB_URL = "http://secondlife.com/app/webdisa // Maximum number of avatar picks const S32 MAX_AVATAR_PICKS = 10; -// For Flags in AvatarPropertiesReply -const U32 AVATAR_ALLOW_PUBLISH = 0x1 << 0; // whether profile is externally visible or not -const U32 AVATAR_MATURE_PUBLISH = 0x1 << 1; // profile is "mature" -const U32 AVATAR_IDENTIFIED = 0x1 << 2; // whether avatar has provided payment info +// For Flags in AvatarPropertiesReply +const U32 AVATAR_ALLOW_PUBLISH = 0x1 << 0; // whether profile is externally visible or not +const U32 AVATAR_MATURE_PUBLISH = 0x1 << 1; // profile is "mature" +const U32 AVATAR_IDENTIFIED = 0x1 << 2; // whether avatar has provided payment info const U32 AVATAR_TRANSACTED = 0x1 << 3; // whether avatar has actively used payment info const U32 AVATAR_ONLINE = 0x1 << 4; // the online status of this avatar, if known. -static const std::string VISIBILITY_DEFAULT("default"); +static const std::string VISIBILITY_DEFAULT("default"); static const std::string VISIBILITY_HIDDEN("hidden"); -static const std::string VISIBILITY_VISIBLE("visible"); +static const std::string VISIBILITY_VISIBLE("visible"); static const std::string VISIBILITY_INVISIBLE("invisible"); #endif diff --git a/linden/indra/llcommon/llbase32.cpp b/linden/indra/llcommon/llbase32.cpp new file mode 100644 index 0000000..711ba63 --- /dev/null +++ b/linden/indra/llcommon/llbase32.cpp @@ -0,0 +1,214 @@ +/** + * @file llbase32.cpp + * @brief base32 encoding that returns a std::string + * @author James Cook + * + * Based on code from bitter + * http://ghostwhitecrab.com/bitter/ + * + * Copyright (c) 2006 Christian Biere + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the authors nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "linden_common.h" + +#include "llbase32.h" + +#include + +// bitter - base32.c starts here + +/* + * See RFC 3548 for details about Base 32 encoding: + * http://www.faqs.org/rfcs/rfc3548.html + */ + +static const char base32_alphabet[32] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', '2', '3', '4', '5', '6', '7' +}; + +size_t +base32_encode(char *dst, size_t size, const void *data, size_t len) +{ + size_t i = 0; + const U8 *p = (const U8*)data; + const char *end = &dst[size]; + char *q = dst; + + do { + size_t j, k; + U8 x[5]; + char s[8]; + + switch (len - i) { + case 4: k = 7; break; + case 3: k = 5; break; + case 2: k = 3; break; + case 1: k = 2; break; + default: + k = 8; + } + + for (j = 0; j < 5; j++) + x[j] = i < len ? p[i++] : 0; + +/* + +-------+-----------+--------+ + | target| source | source | + | byte | bits | byte | + +-------+-----------+--------+ + | 0 | 7 6 5 4 3 | 0 | + | 1 | 2 1 0 7 6 | 0-1 | + | 2 | 5 4 3 2 1 | 1 | + | 3 | 0 7 6 5 4 | 1-2 | + | 4 | 3 2 1 0 7 | 2-3 | + | 5 | 6 5 4 3 2 | 3 | + | 6 | 1 0 7 6 5 | 3-4 | + | 7 | 4 3 2 1 0 | 4 | + +-------+-----------+--------+ + +*/ + + s[0] = (x[0] >> 3); + s[1] = ((x[0] & 0x07) << 2) | (x[1] >> 6); + s[2] = (x[1] >> 1) & 0x1f; + s[3] = ((x[1] & 0x01) << 4) | (x[2] >> 4); + s[4] = ((x[2] & 0x0f) << 1) | (x[3] >> 7); + s[5] = (x[3] >> 2) & 0x1f; + s[6] = ((x[3] & 0x03) << 3) | (x[4] >> 5); + s[7] = x[4] & 0x1f; + + for (j = 0; j < k && q != end; j++) + *q++ = base32_alphabet[(U8) s[j]]; + + } while (i < len); + + return q - dst; +} + +/* *TODO: Implement base32 encode. + +#define ARRAY_LEN(a) (sizeof (a) / sizeof((a)[0])) + +static inline int +ascii_toupper(int c) +{ + return c >= 97 && c <= 122 ? c - 32 : c; +} + +static inline int +ascii_tolower(int c) +{ + return c >= 65 && c <= 90 ? c + 32 : c; +} + + +static char base32_map[(unsigned char) -1]; + +size_t +base32_decode(char *dst, size_t size, const void *data, size_t len) +{ + const char *end = &dst[size]; + const unsigned char *p = data; + char *q = dst; + size_t i; + unsigned max_pad = 3; + + if (0 == base32_map[0]) { + for (i = 0; i < ARRAY_LEN(base32_map); i++) { + const char *x; + + x = memchr(base32_alphabet, ascii_toupper(i), sizeof base32_alphabet); + base32_map[i] = x ? (x - base32_alphabet) : (unsigned char) -1; + } + } + + for (i = 0; i < len && max_pad > 0; i++) { + unsigned char c; + char s[8]; + size_t j; + + c = p[i]; + if ('=' == c) { + max_pad--; + c = 0; + } else { + c = base32_map[c]; + if ((unsigned char) -1 == c) { + return -1; + } + } + + j = i % ARRAY_LEN(s); + s[j] = c; + + if (7 == j) { + char b[5]; + + b[0] = ((s[0] << 3) & 0xf8) | ((s[1] >> 2) & 0x07); + b[1] = ((s[1] & 0x03) << 6) | ((s[2] & 0x1f) << 1) | ((s[3] >> 4) & 1); + b[2] = ((s[3] & 0x0f) << 4) | ((s[4] >> 1) & 0x0f); + b[3] = ((s[4] & 1) << 7) | ((s[5] & 0x1f) << 2) | ((s[6] >> 3) & 0x03); + b[4] = ((s[6] & 0x07) << 5) | (s[7] & 0x1f); + + for (j = 0; j < ARRAY_LEN(b); j++) { + if (q != end) + *q = b[j]; + q++; + } + } + } + + return q - dst; +} +*/ + + +// static +std::string LLBase32::encode(const U8* input, size_t input_size) +{ + std::string output; + if (input) + { + // Each 5 byte chunk of input is represented by an + // 8 byte chunk of output. + size_t input_chunks = (input_size + 4) / 5; + size_t output_size = input_chunks * 8; + + output.resize(output_size); + + size_t encoded = base32_encode(&output[0], output_size, input, input_size); + + llinfos << "encoded " << encoded << " into buffer of size " << output_size + << llendl; + } + return output; +} diff --git a/linden/indra/llcommon/llbase32.h b/linden/indra/llcommon/llbase32.h new file mode 100644 index 0000000..eaf3efc --- /dev/null +++ b/linden/indra/llcommon/llbase32.h @@ -0,0 +1,38 @@ +/** + * @file llbase32.h + * @brief base32 encoding that returns a std::string + * @author James Cook + * + * Copyright (c) 2007-2007, Linden Research, Inc. + * + * 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. + */ + +#ifndef LLBASE32_H +#define LLBASE32_h + +class LLBase32 +{ +public: + static std::string encode(const U8* input, size_t input_size); +}; + +#endif diff --git a/linden/indra/llcommon/llbase64.cpp b/linden/indra/llcommon/llbase64.cpp new file mode 100644 index 0000000..0869d3f --- /dev/null +++ b/linden/indra/llcommon/llbase64.cpp @@ -0,0 +1,62 @@ +/** + * @file llbase64.cpp + * @brief Wrapper for apr base64 encoding that returns a std::string + * @author James Cook + * + * Copyright (c) 2007-2007, Linden Research, Inc. + * + * 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. + */ + +#include "linden_common.h" + +#include "llbase64.h" + +#include + +#include "apr-1/apr_base64.h" + + +// static +std::string LLBase64::encode(const U8* input, size_t input_size) +{ + std::string output; + if (input + && input_size > 0) + { + // Yes, it returns int. + int b64_buffer_length = apr_base64_encode_len(input_size); + char* b64_buffer = new char[b64_buffer_length]; + + // This is faster than apr_base64_encode() if you know + // you're not on an EBCDIC machine. Also, the output is + // null terminated, even though the documentation doesn't + // specify. See apr_base64.c for details. JC + b64_buffer_length = apr_base64_encode_binary( + b64_buffer, + input, + input_size); + output.assign(b64_buffer); + delete[] b64_buffer; + } + return output; +} + diff --git a/linden/indra/llcommon/llbase64.h b/linden/indra/llcommon/llbase64.h new file mode 100644 index 0000000..d8b4acc --- /dev/null +++ b/linden/indra/llcommon/llbase64.h @@ -0,0 +1,38 @@ +/** + * @file llbase64.h + * @brief Wrapper for apr base64 encoding that returns a std::string + * @author James Cook + * + * Copyright (c) 2007-2007, Linden Research, Inc. + * + * 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. + */ + +#ifndef LLBASE64_H +#define LLBASE64_h + +class LLBase64 +{ +public: + static std::string encode(const U8* input, size_t input_size); +}; + +#endif diff --git a/linden/indra/llcommon/llcommon.cpp b/linden/indra/llcommon/llcommon.cpp index 50b9849..49675e1 100644 --- a/linden/indra/llcommon/llcommon.cpp +++ b/linden/indra/llcommon/llcommon.cpp @@ -27,6 +27,7 @@ #include "linden_common.h" #include "llcommon.h" +#include "llthread.h" //static BOOL LLCommon::sAprInitialized = FALSE; diff --git a/linden/indra/llcommon/llcommon.h b/linden/indra/llcommon/llcommon.h index 5d5264c..8b57579 100644 --- a/linden/indra/llcommon/llcommon.h +++ b/linden/indra/llcommon/llcommon.h @@ -31,7 +31,6 @@ #include "llapr.h" // #include "llframecallbackmanager.h" #include "lltimer.h" -#include "llworkerthread.h" #include "llfile.h" class LLCommon diff --git a/linden/indra/llcommon/llcommon.vcproj b/linden/indra/llcommon/llcommon.vcproj index 5cfbc64..403b8c5 100644 --- a/linden/indra/llcommon/llcommon.vcproj +++ b/linden/indra/llcommon/llcommon.vcproj @@ -167,22 +167,22 @@ RelativePath=".\llassettype.cpp"> + RelativePath=".\llbase32.cpp"> + RelativePath=".\llbase64.cpp"> + RelativePath=".\llcommon.cpp"> + RelativePath=".\llcriticaldamp.cpp"> + RelativePath=".\lldate.cpp"> + RelativePath=".\llerror.cpp"> @@ -200,9 +200,15 @@ RelativePath=".\llfixedbuffer.cpp"> + + + + + + + + - - + RelativePath=".\llerrorcontrol.h"> @@ -385,6 +394,9 @@ RelativePath=".\llfixedbuffer.h"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linden/indra/llcommon/llerror.cpp b/linden/indra/llcommon/llerror.cpp index 29f4500..57e098e 100644 --- a/linden/indra/llcommon/llerror.cpp +++ b/linden/indra/llcommon/llerror.cpp @@ -1,8 +1,9 @@ /** * @file llerror.cpp - * @brief Function to crash. + * @date December 2006 + * @brief error message system * - * Copyright (c) 2001-2007, Linden Research, Inc. + * Copyright (c) 2006-2007, Linden Research, Inc. * * 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 @@ -24,36 +25,1048 @@ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. */ + #include "linden_common.h" #include "llerror.h" +#include "llerrorcontrol.h" + +#include "llapp.h" +#include "llapr.h" +extern apr_thread_mutex_t *gLogMutexp; +#include "llfile.h" +#include "llfixedbuffer.h" +#include "lllivefile.h" +#include "llsd.h" +#include "llsdserialize.h" + +#include +#include +#include +#include +#if !LL_WINDOWS +#include +#include +#endif +#include +#if LL_WINDOWS +#include +#endif +#include + + +#ifdef __GNUC__ +#include +#endif + +namespace { +#if !LL_WINDOWS + class RecordToSyslog : public LLError::Recorder + { + public: + RecordToSyslog(const std::string& identity) + : mIdentity(identity) + { + openlog(mIdentity.c_str(), LOG_CONS|LOG_PID, LOG_LOCAL0); + // we need to set the string from a local copy of the string + // since apparanetly openlog expects the const char* to remain + // valid even after it returns (presumably until closelog) + } + + ~RecordToSyslog() + { + closelog(); + } + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) + { + int syslogPriority = LOG_CRIT; + switch (level) { + case LLError::LEVEL_DEBUG: syslogPriority = LOG_DEBUG; break; + case LLError::LEVEL_INFO: syslogPriority = LOG_INFO; break; + case LLError::LEVEL_WARN: syslogPriority = LOG_WARNING; break; + case LLError::LEVEL_ERROR: syslogPriority = LOG_CRIT; break; + default: syslogPriority = LOG_CRIT; + } + + syslog(syslogPriority, "%s", message.c_str()); + } + private: + std::string mIdentity; + }; +#endif + + class RecordToFile : public LLError::Recorder + { + public: + RecordToFile(const std::string& filename) + { + mFile.open(filename.c_str(), llofstream::out | llofstream::app); + if (!mFile) + { + llinfos << "Error setting log file to " << filename << llendl; + } + } + + ~RecordToFile() + { + mFile.close(); + } + + bool okay() { return mFile; } + + virtual bool wantsTime() { return true; } + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) + { + mFile << message << std::endl; + // mFile.flush(); + // *FIX: should we do this? + } + + private: + llofstream mFile; + }; + + + class RecordToStderr : public LLError::Recorder + { + public: + RecordToStderr(bool timestamp) : mTimestamp(timestamp) { } -LLErrorBuffer gErrorBuffer; -LLErrorStream gErrorStream(&gErrorBuffer); + virtual bool wantsTime() { return mTimestamp; } + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) + { + fprintf(stderr, "%s\n", message.c_str()); + } + + private: + bool mTimestamp; + }; + class RecordToFixedBuffer : public LLError::Recorder + { + public: + RecordToFixedBuffer(LLFixedBuffer& buffer) : mBuffer(buffer) { } + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) + { + mBuffer.addLine(message.c_str()); + } + + private: + LLFixedBuffer& mBuffer; + }; -void _llcrash_and_loop() +#if LL_WINDOWS + class RecordToWinDebug: public LLError::Recorder + { + public: + virtual void recordMessage(LLError::ELevel level, + const std::string& message) + { + llutf16string utf16str = + wstring_to_utf16str(utf8str_to_wstring(message)); + utf16str += '\n'; + OutputDebugString(utf16str.c_str()); + } + }; +#endif +} + + +namespace { - // Now, we go kaboom! - U32* crash = NULL; + std::string className(const std::type_info& type) + { +#ifdef __GNUC__ + // GCC: type_info::name() returns a mangled class name, must demangle + + static size_t abi_name_len = 100; + static char* abi_name_buf = (char*)malloc(abi_name_len); + // warning: above is voodoo inferred from the GCC manual, + // do NOT change + + int status; + // We don't use status, and shouldn't have to pass apointer to it + // but gcc 3.3 libstc++'s implementation of demangling is broken + // and fails without. + + char* name = abi::__cxa_demangle(type.name(), + abi_name_buf, &abi_name_len, &status); + // this call can realloc the abi_name_buf pointer (!) + + return name ? name : type.name(); - *crash = 0; +#elif LL_WINDOWS + // DevStudio: type_info::name() includes the text "class " at the start - while(TRUE) + static const std::string class_prefix = "class "; + + std::string name = type.name(); + std::string::size_type p = name.find(class_prefix); + if (p == std::string::npos) + { + return name; + } + + return name.substr(p + class_prefix.size()); + +#else + return type.name(); +#endif + } + + std::string functionName(const std::string& preprocessor_name) { +#if LL_WINDOWS + // DevStudio: the __FUNCTION__ macro string includes + // the type and/or namespace prefixes + + std::string::size_type p = preprocessor_name.rfind(':'); + if (p == std::string::npos) + { + return preprocessor_name; + } + return preprocessor_name.substr(p + 1); + +#else + return preprocessor_name; +#endif + } + + + class LogControlFile : public LLLiveFile + { + LOG_CLASS(LogControlFile); + + public: + static LogControlFile& fromDirectory(const std::string& dir); + + virtual void loadFile(); + + private: + LogControlFile(const std::string &filename) + : LLLiveFile(filename) + { } + }; + + LogControlFile& LogControlFile::fromDirectory(const std::string& dir) + { + std::string dirBase = dir + "/"; + // NB: We have no abstraction in llcommon for the "proper" + // delimiter but it turns out that "/" works on all three platforms + + std::string file = dirBase + "logcontrol-dev.xml"; + + llstat stat_info; + if (LLFile::stat(file.c_str(), &stat_info)) { + // NB: stat returns non-zero if it can't read the file, for example + // if it doesn't exist. LLFile has no better abstraction for + // testing for file existence. + + file = dirBase + "logcontrol.xml"; + } + return * new LogControlFile(file); + // NB: This instance is never freed + } + + void LogControlFile::loadFile() + { + LLSD configuration; + + { + llifstream file(filename().c_str()); + if (file.is_open()) + { + LLSDSerialize::fromXML(configuration, file); + } + + if (configuration.isUndefined()) + { + llwarns << filename() << " missing, ill-formed," + " or simply undefined; not changing configuration" + << llendl; + return; + } + } + + LLError::configure(configuration); + llinfos << "logging reconfigured from " << filename() << llendl; + } + + + typedef std::map LevelMap; + typedef std::vector Recorders; + typedef std::vector CallSiteVector; + + class Globals + { + public: + std::ostringstream messageStream; + bool messageStreamInUse; + + void addCallSite(LLError::CallSite&); + void invalidateCallSites(); + + static Globals& get(); + // return the one instance of the globals + + private: + CallSiteVector callSites; + + Globals() + : messageStreamInUse(false) + { } + + }; + + void Globals::addCallSite(LLError::CallSite& site) + { + callSites.push_back(&site); + } - // Loop forever, in case the crash didn't work? + void Globals::invalidateCallSites() + { + for (CallSiteVector::const_iterator i = callSites.begin(); + i != callSites.end(); + ++i) + { + (*i)->invalidate(); + } + + callSites.clear(); + } + + Globals& Globals::get() + { + /* This pattern, of returning a reference to a static function + variable, is to ensure that this global is constructed before + it is used, no matter what the global initializeation sequence + is. + See C++ FAQ Lite, sections 10.12 through 10.14 + */ + static Globals* globals = new Globals; + return *globals; } } -LLScopedErrorLevel::LLScopedErrorLevel(LLErrorBuffer::ELevel error_level) +namespace LLError { - mOrigErrorLevel = gErrorStream.getErrorLevel(); - gErrorStream.setErrorLevel(error_level); + class Settings + { + public: + bool printLocation; + + LLError::ELevel defaultLevel; + + LevelMap functionLevelMap; + LevelMap classLevelMap; + LevelMap fileLevelMap; + + LLError::FatalFunction crashFunction; + LLError::TimeFunction timeFunction; + + Recorders recorders; + Recorder* fileRecorder; + Recorder* fixedBufferRecorder; + std::string fileRecorderFileName; + + int shouldLogCallCounter; + + static Settings& get(); + + static void reset(); + static Settings* saveAndReset(); + static void restore(Settings*); + + private: + Settings() + : printLocation(false), + defaultLevel(LLError::LEVEL_DEBUG), + crashFunction(NULL), + timeFunction(NULL), + fileRecorder(NULL), + fixedBufferRecorder(NULL), + shouldLogCallCounter(0) + { } + + static Settings*& getPtr(); + }; + + Settings& Settings::get() + { + Settings* p = getPtr(); + if (!p) + { + reset(); + p = getPtr(); + } + return *p; + } + + void Settings::reset() + { + Globals::get().invalidateCallSites(); + + Settings*& p = getPtr(); + delete p; + p = new Settings(); + } + + Settings* Settings::saveAndReset() + { + Globals::get().invalidateCallSites(); + + Settings*& p = getPtr(); + Settings* originalSettings = p; + p = new Settings(); + return originalSettings; + } + + void Settings::restore(Settings* originalSettings) + { + Globals::get().invalidateCallSites(); + + Settings*& p = getPtr(); + delete p; + p = originalSettings; + } + + Settings*& Settings::getPtr() + { + static Settings* currentSettings = NULL; + return currentSettings; + } } +namespace LLError +{ + CallSite::CallSite(ELevel level, + const char* file, int line, + const std::type_info& class_info, const char* function) + : mLevel(level), mFile(file), mLine(line), + mClassInfo(class_info), mFunction(function), + mCached(false), mShouldLog(false) + { } + + + void CallSite::invalidate() + { mCached = false; } +} + +namespace +{ + bool shouldLogToStderr() + { +#if LL_DARWIN + // On Mac OS X, stderr from apps launched from the Finder goes to the + // console log. It's generally considered bad form to spam too much + // there. + + // If stdin is a tty, assume the user launched from the command line and + // therefore wants to see stderr. Otherwise, assume we've been launched + // from the finder and shouldn't spam stderr. + return isatty(0); +#else + return true; +#endif + } + + bool stderrLogWantsTime() + { +#if LL_WINDOWS + return false; +#else + return true; +#endif + } + + + void commonInit(const std::string& dir) + { + LLError::Settings::reset(); + + LLError::setDefaultLevel(LLError::LEVEL_INFO); + LLError::setFatalFunction(LLError::crashAndLoop); + LLError::setTimeFunction(LLError::utcTime); + + if (shouldLogToStderr()) + { + LLError::addRecorder(new RecordToStderr(stderrLogWantsTime())); + } + +#if LL_WINDOWS + LLError::addRecorder(new RecordToWinDebug); +#endif -LLScopedErrorLevel::~LLScopedErrorLevel() + LogControlFile& e = LogControlFile::fromDirectory(dir); + e.addToEventTimer(); + } +} + +namespace LLError { - gErrorStream.setErrorLevel(mOrigErrorLevel); + void initForServer(const std::string& identity) + { + std::string dir = LLApp::instance()->getOption("configdir"); + commonInit(dir); +#if !LL_WINDOWS + addRecorder(new RecordToSyslog(identity)); +#endif + } + + void initForApplication(const std::string& dir) + { + commonInit(dir); + } + + void setPrintLocation(bool print) + { + Settings& s = Settings::get(); + s.printLocation = print; + } + + void setFatalFunction(FatalFunction f) + { + Settings& s = Settings::get(); + s.crashFunction = f; + } + + void setTimeFunction(TimeFunction f) + { + Settings& s = Settings::get(); + s.timeFunction = f; + } + + void setDefaultLevel(ELevel level) + { + Globals& g = Globals::get(); + Settings& s = Settings::get(); + g.invalidateCallSites(); + s.defaultLevel = level; + } + + void setFunctionLevel(const std::string& function_name, ELevel level) + { + Globals& g = Globals::get(); + Settings& s = Settings::get(); + g.invalidateCallSites(); + s.functionLevelMap[function_name] = level; + } + + void setClassLevel(const std::string& class_name, ELevel level) + { + Globals& g = Globals::get(); + Settings& s = Settings::get(); + g.invalidateCallSites(); + s.classLevelMap[class_name] = level; + } + + void setFileLevel(const std::string& file_name, ELevel level) + { + Globals& g = Globals::get(); + Settings& s = Settings::get(); + g.invalidateCallSites(); + s.fileLevelMap[file_name] = level; + } } + +namespace { + LLError::ELevel decodeLevel(std::string name) + { + static LevelMap level_names; + if (level_names.empty()) + { + level_names["ALL"] = LLError::LEVEL_ALL; + level_names["DEBUG"] = LLError::LEVEL_DEBUG; + level_names["INFO"] = LLError::LEVEL_INFO; + level_names["WARN"] = LLError::LEVEL_WARN; + level_names["ERROR"] = LLError::LEVEL_ERROR; + level_names["NONE"] = LLError::LEVEL_NONE; + } + + std::transform(name.begin(), name.end(), name.begin(), toupper); + + LevelMap::const_iterator i = level_names.find(name); + if (i == level_names.end()) + { + llwarns << "unrecognized logging level: '" << name << "'" << llendl; + return LLError::LEVEL_INFO; + } + + return i->second; + } + + void setLevels(LevelMap& map, const LLSD& list, LLError::ELevel level) + { + LLSD::array_const_iterator i, end; + for (i = list.beginArray(), end = list.endArray(); i != end; ++i) + { + map[*i] = level; + } + } +} + +namespace LLError +{ + void configure(const LLSD& config) + { + Globals& g = Globals::get(); + Settings& s = Settings::get(); + + g.invalidateCallSites(); + s.functionLevelMap.clear(); + s.classLevelMap.clear(); + s.fileLevelMap.clear(); + + setPrintLocation(config["print-location"]); + setDefaultLevel(decodeLevel(config["default-level"])); + + LLSD sets = config["settings"]; + LLSD::array_const_iterator a, end; + for (a = sets.beginArray(), end = sets.endArray(); a != end; ++a) + { + const LLSD& entry = *a; + + ELevel level = decodeLevel(entry["level"]); + + setLevels(s.functionLevelMap, entry["functions"], level); + setLevels(s.classLevelMap, entry["classes"], level); + setLevels(s.fileLevelMap, entry["files"], level); + } + } +} + + +namespace LLError +{ + Recorder::~Recorder() + { } + + // virtual + bool Recorder::wantsTime() + { return false; } + + + + void addRecorder(Recorder* recorder) + { + if (recorder == NULL) + { + return; + } + Settings& s = Settings::get(); + s.recorders.push_back(recorder); + } + + void removeRecorder(Recorder* recorder) + { + if (recorder == NULL) + { + return; + } + Settings& s = Settings::get(); + s.recorders.erase( + std::remove(s.recorders.begin(), s.recorders.end(), recorder), + s.recorders.end()); + } +} + +namespace LLError +{ + void logToFile(const std::string& file_name) + { + LLError::Settings& s = LLError::Settings::get(); + + removeRecorder(s.fileRecorder); + delete s.fileRecorder; + s.fileRecorder = NULL; + s.fileRecorderFileName.clear(); + + if (file_name.empty()) + { + return; + } + + RecordToFile* f = new RecordToFile(file_name); + if (!f->okay()) + { + delete f; + return; + } + + s.fileRecorderFileName = file_name; + s.fileRecorder = f; + addRecorder(f); + } + + void logToFixedBuffer(LLFixedBuffer* fixedBuffer) + { + LLError::Settings& s = LLError::Settings::get(); + + removeRecorder(s.fixedBufferRecorder); + delete s.fixedBufferRecorder; + s.fixedBufferRecorder = NULL; + + if (!fixedBuffer) + { + return; + } + + s.fixedBufferRecorder = new RecordToFixedBuffer(*fixedBuffer); + addRecorder(s.fixedBufferRecorder); + } + + std::string logFileName() + { + LLError::Settings& s = LLError::Settings::get(); + return s.fileRecorderFileName; + } +} + +namespace +{ + void writeToRecorders(LLError::ELevel level, const std::string& message) + { + LLError::Settings& s = LLError::Settings::get(); + + std::string messageWithTime; + + for (Recorders::const_iterator i = s.recorders.begin(); + i != s.recorders.end(); + ++i) + { + LLError::Recorder* r = *i; + + if (r->wantsTime() && s.timeFunction != NULL) + { + if (messageWithTime.empty()) + { + messageWithTime = s.timeFunction() + " " + message; + } + + r->recordMessage(level, messageWithTime); + } + else + { + r->recordMessage(level, message); + } + } + } +} + + +/* +Recorder formats: + +$type = "ERROR" | "WARNING" | "ALERT" | "INFO" | "DEBUG" +$loc = "$file($line)" +$msg = "$loc : " if FATAL or printing loc + "" otherwise +$msg += "$type: " +$msg += contents of stringstream + +$time = "%Y-%m-%dT%H:%M:%SZ" if UTC + or "%Y-%m-%dT%H:%M:%S %Z" if local + +syslog: "$msg" +file: "$time $msg\n" +stderr: "$time $msg\n" except on windows, "$msg\n" +fixedbuf: "$msg" +winddebug: "$msg\n" + +Note: if FATAL, an additional line gets logged first, with $msg set to + "$loc : error" + +You get: + llfoo.cpp(42) : error + llfoo.cpp(42) : ERROR: something + +*/ + +namespace { + bool checkLevelMap(const LevelMap& map, const std::string& key, + LLError::ELevel& level) + { + LevelMap::const_iterator i = map.find(key); + if (i == map.end()) + { + return false; + } + + level = i->second; + return true; + } + + class LogLock + { + public: + LogLock(); + ~LogLock(); + bool ok() const { return mOK; } + private: + bool mLocked; + bool mOK; + }; + + LogLock::LogLock() + : mLocked(false), mOK(false) + { + if (!gLogMutexp) + { + mOK = true; + return; + } + + const int MAX_RETRIES = 5; + for (int attempts = 0; attempts < MAX_RETRIES; ++attempts) + { + apr_status_t s = apr_thread_mutex_trylock(gLogMutexp); + if (!APR_STATUS_IS_EBUSY(s)) + { + mLocked = true; + mOK = true; + return; + } + + ms_sleep(1); + //apr_thread_yield(); + // Just yielding won't necessarily work, I had problems with + // this on Linux - doug 12/02/04 + } + + // We're hosed, we can't get the mutex. Blah. + std::cerr << "LogLock::LogLock: failed to get mutex for log" + << std::endl; + } + + LogLock::~LogLock() + { + if (mLocked) + { + apr_thread_mutex_unlock(gLogMutexp); + } + } +} + +namespace LLError +{ + bool Log::shouldLog(CallSite& site) + { + LogLock lock; + if (!lock.ok()) + { + return false; + } + + Globals& g = Globals::get(); + Settings& s = Settings::get(); + + s.shouldLogCallCounter += 1; + + std::string class_name = className(site.mClassInfo); + std::string function_name = functionName(site.mFunction); + if (site.mClassInfo != typeid(NoClassInfo)) + { + function_name = class_name + "::" + function_name; + } + + ELevel compareLevel = s.defaultLevel; + + checkLevelMap(s.functionLevelMap, function_name, compareLevel) + || checkLevelMap(s.classLevelMap, class_name, compareLevel) + || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel); + + site.mCached = true; + g.addCallSite(site); + return site.mShouldLog = site.mLevel >= compareLevel; + } + + + std::ostringstream* Log::out() + { + LogLock lock; + if (lock.ok()) + { + Globals& g = Globals::get(); + + if (!g.messageStreamInUse) + { + g.messageStreamInUse = true; + return &g.messageStream; + } + } + + return new std::ostringstream; + } + + void Log::flush(std::ostringstream* out, const CallSite& site) + { + LogLock lock; + if (!lock.ok()) + { + return; + } + + Globals& g = Globals::get(); + Settings& s = Settings::get(); + + std::string message = out->str(); + if (out == &g.messageStream) + { + g.messageStream.clear(); + g.messageStream.str(""); + g.messageStreamInUse = false; + } + else + { + delete out; + } + + if (site.mLevel == LEVEL_ERROR) + { + std::ostringstream fatalMessage; + fatalMessage << abbreviateFile(site.mFile) + << "(" << site.mLine << ") : error"; + + writeToRecorders(site.mLevel, fatalMessage.str()); + } + + + std::ostringstream prefix; + + switch (site.mLevel) + { + case LEVEL_DEBUG: prefix << "DEBUG: "; break; + case LEVEL_INFO: prefix << "INFO: "; break; + case LEVEL_WARN: prefix << "WARNING: "; break; + case LEVEL_ERROR: prefix << "ERROR: "; break; + default: prefix << "XXX: "; break; + }; + + if (s.printLocation) + { + prefix << abbreviateFile(site.mFile) + << "(" << site.mLine << ") : "; + } + + if (message.find(functionName(site.mFunction)) == std::string::npos) + { + #if LL_WINDOWS + // DevStudio: __FUNCTION__ already includes the full class name + #else + if (site.mClassInfo != typeid(NoClassInfo)) + { + prefix << className(site.mClassInfo) << "::"; + } + #endif + prefix << site.mFunction << ": "; + } + + prefix << message; + message = prefix.str(); + + writeToRecorders(site.mLevel, message); + + if (site.mLevel == LEVEL_ERROR && s.crashFunction) + { + s.crashFunction(message); + } + } +} + + + + +namespace LLError +{ + Settings* saveAndResetSettings() + { + return Settings::saveAndReset(); + } + + void restoreSettings(Settings* s) + { + return Settings::restore(s); + } + + std::string removePrefix(std::string& s, const std::string& p) + { + std::string::size_type where = s.find(p); + if (where == std::string::npos) + { + return s; + } + + return std::string(s, where + p.size()); + } + + void replaceChar(std::string& s, char old, char replacement) + { + std::string::size_type i = 0; + std::string::size_type len = s.length(); + for ( ; i < len; i++ ) + { + if (s[i] == old) + { + s[i] = replacement; + } + } + } + + std::string abbreviateFile(const std::string& filePath) + { + std::string f = filePath; +#if LL_WINDOWS + replaceChar(f, '\\', '/'); +#endif + static std::string indra_prefix = "indra/"; + f = removePrefix(f, indra_prefix); + +#if LL_DARWIN + static std::string newview_prefix = "newview/../"; + f = removePrefix(f, newview_prefix); +#endif + + return f; + } + + int shouldLogCallCount() + { + Settings& s = Settings::get(); + return s.shouldLogCallCounter; + } + + void crashAndLoop(const std::string& message) + { + // Now, we go kaboom! + int* crash = NULL; + + *crash = 0; + + while(true) + { + // Loop forever, in case the crash didn't work? + } + } + + std::string utcTime() + { + time_t now = time(NULL); + const size_t BUF_SIZE = 64; + char time_str[BUF_SIZE]; /* Flawfinder: ignore */ + + int chars = strftime(time_str, BUF_SIZE, + "%Y-%m-%dT%H:%M:%SZ", + gmtime(&now)); + + return chars ? time_str : "time error"; + } +} + diff --git a/linden/indra/llcommon/llerror.h b/linden/indra/llcommon/llerror.h index 04e8eee..1285491 100644 --- a/linden/indra/llcommon/llerror.h +++ b/linden/indra/llcommon/llerror.h @@ -1,8 +1,9 @@ /** * @file llerror.h - * @brief Constants, functions, and macros for logging and runtime errors. + * @date December 2006 + * @brief error message system * - * Copyright (c) 2001-2007, Linden Research, Inc. + * Copyright (c) 2006-2007, Linden Research, Inc. * * 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 @@ -29,209 +30,208 @@ #define LL_LLERROR_H #include -#include -#include - -#include "llerrorstream.h" -#include "llerrorbuffer.h" - -// Specific error codes -const S32 LL_ERR_NOERR = 0; -const S32 LL_ERR_ASSET_REQUEST_FAILED = -1; -//const S32 LL_ERR_ASSET_REQUEST_INVALID = -2; -const S32 LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3; -const S32 LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4; -const S32 LL_ERR_INSUFFICIENT_PERMISSIONS = -5; -const S32 LL_ERR_EOF = -39; -const S32 LL_ERR_CANNOT_OPEN_FILE = -42; -const S32 LL_ERR_FILE_NOT_FOUND = -43; -const S32 LL_ERR_FILE_EMPTY = -44; -const S32 LL_ERR_TCP_TIMEOUT = -23016; -const S32 LL_ERR_CIRCUIT_GONE = -23017; - -// Error types - -#define LLERR_IMAGE (1 << 1) // Image requests -#define LLERR_MESSAGE (1 << 2) // Messaging -#define LLERR_PERF (1 << 3) // Performance -#define LLERR_SQL (1 << 4) // SQL statements -#define LLERR_DOUG (1 << 5) // Doug's debugging -#define LLERR_USER_INPUT (1 << 6) // Keyboard and mouse -#define LLERR_TIMING (1 << 7) // Verbose time info -#define LLERR_TASK (1 << 8) // Tracking tasks -#define LLERR_MSG_HANDLER (1 << 9) // -#define LLERR_CIRCUIT_INFO (1 << 10) // Message system circuit info -#define LLERR_PHYSICS (1 << 11) // physics -#define LLERR_VFS (1 << 12) // VFS -const U32 LLERR_ALL = 0xffff; -const U32 LLERR_NONE = 0x0; - -// Define one of these for different error levels in release... -// #define RELEASE_SHOW_DEBUG // Define this if you want your release builds to show lldebug output. -#define RELEASE_SHOW_INFO // Define this if you want your release builds to show llinfo output -#define RELEASE_SHOW_WARN // Define this if you want your release builds to show llwarn output. - - -////////////////////////////////////////// -// -// Implementation - ignore -// -// -#ifdef _DEBUG -#define SHOW_DEBUG -#define SHOW_WARN -#define SHOW_INFO -#define SHOW_ASSERT -#else // _DEBUG - -#ifdef RELEASE_SHOW_DEBUG -#define SHOW_DEBUG -#endif - -#ifdef RELEASE_SHOW_WARN -#define SHOW_WARN -#endif - -#ifdef RELEASE_SHOW_INFO -#define SHOW_INFO -#endif - -#ifdef RELEASE_SHOW_ASSERT -#define SHOW_ASSERT -#endif - -#endif // _DEBUG - - -extern LLErrorStream gErrorStream; - - -// LL Error macros -// -// Usage: -// -// llerrs << "An error, oh my!" << variable << endl; -// llwarns << "Another error, fuck me!" << variable << endl; -// llwarnst(LLERR_IMAGE) << "Debug, mother fucker" << endl; -// -// NOTE: The output format of filename(lineno): is so that MS DevStudio -// can parse the output and automatically jump to that location - -inline std::string llerrno_string(int errnum) +#include + +#include "llerrorlegacy.h" + + +/* Error Logging Facility + + Information for most users: + + Code can log messages with constuctions like this: + + llinfos << "request to fizzbip agent " << agent_id + << " denied due to timeout" << llendl; + + Messages can be logged to one of four increasing levels of concern, + using one of four "streams": + + lldebugs - debug messages that are normally supressed + llinfos - informational messages that are normall shown + llwarns - warning messages that singal a problem + llerrs - error messages that are major, unrecoverable failures + + The later (llerrs) automatically crashes the process after the message + is logged. + + Note that these "streams" are actually #define magic. Rules for use: + * they cannot be used as normal streams, only to start a message + * messages written to them MUST be terminated with llendl + * between the opening and closing, the << operator is indeed + writing onto a std::ostream, so all conversions and stream + formating are available + + These messages are automatically logged with function name, and (if enabled) + file and line of the message. (Note: Existing messages that already include + the function name don't get name printed twice.) + + If you have a class, adding LOG_CLASS line to the declaration will cause + all messages emitted from member functions (normal and static) to be tagged + with the proper class name as well as the function name: + + class LLFoo + { + LOG_CLASS(LLFoo); + public: + ... + }; + + void LLFoo::doSomething(int i) + { + if (i > 100) + { + llwanrs << "called with a big value for i: " << i << llendl; + } + ... + } + + will result in messages like: + + WARN: LLFoo::doSomething: called with a big value for i: 283 + + Which messages are logged and which are supressed can be controled at run + time from the live file logcontrol.xml based on function, class and/or + source file. See etc/logcontrol-dev.xml for details. + + Lastly, logging is now very efficient in both compiled code and execution + when skipped. There is no need to wrap messages, even debugging ones, in + #ifdef _DEBUG constructs. lldebugs messages are compiled into all builds, + even release. Which means you can use them to help debug even when deployed + to a real grid. +*/ + +namespace LLError { - std::stringstream res; - res << "error(" << errnum << "):" << strerror(errnum) << " "; - return res.str(); + enum ELevel + { + LEVEL_ALL = 0, + // used to indicate that all messagess should be logged + + LEVEL_DEBUG = 0, + LEVEL_INFO = 1, + LEVEL_WARN = 2, + LEVEL_ERROR = 3, // used to be called FATAL + + LEVEL_NONE = 4 + // not really a level + // used to indicate that no messages should be logged + }; + + /* Macro support + The classes CallSite and Log are used by the logging macros below. + They are not intended for general use. + */ + + class CallSite; + + class Log + { + public: + static bool shouldLog(CallSite&); + static std::ostringstream* out(); + static void flush(std::ostringstream*, const CallSite&); + }; + + class CallSite + { + // Represents a specific place in the code where a message is logged + // This is public because it is used by the macros below. It is not + // intended for public use. + public: + CallSite(ELevel, const char* file, int line, + const std::type_info& class_info, const char* function); + + bool shouldLog() + { return mCached ? mShouldLog : Log::shouldLog(*this); } + // this member function needs to be in-line for efficiency + + void invalidate(); + + private: + // these describe the call site and never change + const ELevel mLevel; + const char* const mFile; + const int mLine; + const std::type_info& mClassInfo; + const char* const mFunction; + + // these implement a cache of the call to shouldLog() + bool mCached; + bool mShouldLog; + + friend class Log; + }; + + + class End { }; + inline std::ostream& operator<<(std::ostream& s, const End&) + { return s; } + // used to indicate the end of a message + + class NoClassInfo { }; + // used to indicate no class info known for logging } -inline std::string llerror_file_line(const char* file, S32 line) -{ - std::stringstream res; - res << file << "(" < -#include - -#if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include -# include // for OutputDebugString -#else -# include -# include -#endif - -#include - -// In order to compile in Visual C++ 6.0, you must use std:: in the header, and then -// use the std namespace in the cpp. Otherwise, you'll break the (very) fragile C++ parser. -using namespace std; - -LLErrorBuffer::LLErrorBuffer() -: streambuf(), - mFile(NULL), - mBuf(), - mFixedBuf(NULL), - mErrorActive(TRUE), - mErrorTimestamp(TRUE), - mFileActive(FALSE), - mSyslogActive(TRUE), - mWinDebugActive(TRUE), - mElevatedRemote(FALSE), - mIsUTC(TRUE), - mLevel(DEBUG), - mPriority(DEBUG) -{ - mFilename[0] = '\0'; -#if LL_WINDOWS - // by default, turn off timestamps in the debug log on windows - mErrorTimestamp = FALSE; -#endif -} - -LLErrorBuffer::~LLErrorBuffer() -{ - delete mFile; - mFile = NULL; -} - -#if !LL_WINDOWS -int LLErrorBuffer::ELevelToSyslogPriority(const ELevel l) -{ - switch(l) - { - case DEBUG: - return LOG_DEBUG; - case INFO: - switch(mElevatedRemote) - { - case TRUE: return LOG_NOTICE; - default: return LOG_INFO; - } - case WARN: - return LOG_WARNING; - case FATAL: - return LOG_CRIT; - default: - return LOG_CRIT; - } - return LOG_CRIT; -} -#endif // LL_WINDOWS - -BOOL LLErrorBuffer::setFile(const char *filename) -{ - if (mFile == NULL) - { - mFile = new llofstream(); - } - if (mFile->is_open()) - { - mFile->close(); - } - if (filename == NULL) - { - llwarns << "Input filename is NULL!!" << llendl; - return FALSE; - } - mFile->open(filename, llofstream::out | llofstream::app); /* Flawfinder: ignore */ - if (mFile->is_open()) - { - mFileActive = TRUE; - } - else - { - mFileActive = FALSE; - delete mFile; - mFile = NULL; - } - snprintf(mFilename, sizeof(mFilename), filename); /* Flawfinder: ignore */ - return mFileActive; -} - -void LLErrorBuffer::closeFile() -{ - if (mFile && mFile->is_open()) - { - mFile->close(); - mFileActive = FALSE; - delete mFile; - mFile = NULL; - } -} - -const char * LLErrorBuffer::getFilename() const -{ - return mFilename; -} - -void LLErrorBuffer::setUTCTimestamp(BOOL utc) -{ - mIsUTC = utc; -} - -void LLErrorBuffer::enableError(BOOL active) -{ - mErrorActive = active; -} - -void LLErrorBuffer::enableErrorTimestamp(BOOL active) -{ - mErrorTimestamp = active; -} - -void LLErrorBuffer::enableFile(BOOL active) -{ - if (mFile != NULL) - { - if (mFile->is_open()) - mFileActive = active; - } - else - mFileActive = FALSE; -} - -#if !LL_WINDOWS -void LLErrorBuffer::enableSyslog(BOOL active) -{ - mSyslogActive = active; -} -#endif // LL_WINDOWS - -#if LL_WINDOWS -void LLErrorBuffer::enableWinDebug(BOOL active) -{ - mWinDebugActive = active; -} -#endif // LL_WINDOWS - -int LLErrorBuffer::overflow(int c) -{ - if (EOF != c) - { - if ('\n' == c) - { - // If we're not supposed to print anything, don't, but - // pretend that we did so taht the iostream doesn't think - // there's been a failure - if (mPriority < mLevel) - { - // Flush our message buffer - mBuf = ""; - return 0; - } -#if !LL_WINDOWS - if (mSyslogActive) - { - int pri = ELevelToSyslogPriority(mPriority); - syslog(pri, "%s", mBuf.c_str()); - } -#endif // LL_WINDOWS - const S32 BUF_SIZE = 64; - char time_str[BUF_SIZE]; /* Flawfinder: ignore */ - if (mFileActive || mErrorActive) - { - time_t now; - time(&now); - S32 chars; - if(mIsUTC) - { - chars = (S32)strftime(time_str, BUF_SIZE, - "%Y-%m-%dT%H:%M:%SZ", - gmtime(&now)); - } - else - { - chars = (S32)strftime(time_str, BUF_SIZE, - "%Y-%m-%dT%H:%M:%S %Z", - localtime(&now)); - } - if (0 == chars) - { - strcpy(time_str, "time error"); /* Flawfinder: ignore */ - } - } - if (mFileActive) - { - *mFile << time_str << " " << mBuf << std::endl; - } - if (mErrorActive) - { - if (mErrorTimestamp) - { - fprintf(stderr, "%s %s\n", time_str, mBuf.c_str()); - } - else - { - fprintf(stderr, "%s\n", mBuf.c_str()); - } - - // std::cerr goes into the void on the viewer - //std::cerr << time_str << ' ' << mBuf << std::endl; - } - if (mFixedBuf) - { - mFixedBuf->addLine(mBuf.c_str()); - } -#if LL_WINDOWS - if (mWinDebugActive) - { - llutf16string utf16str = wstring_to_utf16str(utf8str_to_wstring(mBuf)); - utf16str += '\n'; - OutputDebugString(utf16str.c_str()); - } -#endif // LL_WINDOWS - // Is there a better way to truncate a string? - mBuf.erase(0, mBuf.length()); // Hack, Linux doesn't implement clear()! - } - else - { - mBuf += c; - } - } - return 0; -} - -LLErrorBuffer::ELevel LLErrorBuffer::mergeLevel(const LLErrorBuffer::ELevel l) -{ - mLevel = llmin(mLevel, l); - return mLevel; -} diff --git a/linden/indra/llcommon/llerrorbuffer.h b/linden/indra/llcommon/llerrorbuffer.h deleted file mode 100644 index b52de3a..0000000 --- a/linden/indra/llcommon/llerrorbuffer.h +++ /dev/null @@ -1,117 +0,0 @@ -/** - * @file llerrorbuffer.h - * @brief Buffer implementation for logging. - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * - * 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. - */ - -#ifndef LL_LLERRORBUFFER_H -#define LL_LLERRORBUFFER_H - -#include -#include -#include - -#include "lldefs.h" -#include "stdtypes.h" -#include "llfile.h" - -// A streambuf that sends it's output into a file, stderr, or syslog. -// -// Each output can be enabled/disabled, and a priority can be set. - -class LLFixedBuffer; - -class LLErrorBuffer : public std::streambuf -{ - public: - - // Specify error levels - enum ELevel - { - DEBUG = 0, - INFO = 1, - WARN = 2, - FATAL = 3, - NONE = 4 // Do NO error logging (for use in signal handlers) - }; - - LLErrorBuffer(); - ~LLErrorBuffer(); - BOOL setFile(const char *filename); - void closeFile(); - const char *getFilename() const; - void setFixedBuffer(LLFixedBuffer *b) { mFixedBuf = b; }; - - // Sets the priority of the current message - void setPriority(const ELevel l) { mPriority = l; } - - // Only display messages >= to this level - void setLevel(const ELevel l) { mLevel = l; } - ELevel getLevel() { return mLevel; } - // Display messages >= to level l, if l < current level - ELevel mergeLevel(const ELevel l); - - // on linux, this sets syslog info to be a LOG_NOTICE which will - // be centrally logged. *NOTE: This is very - // linux/syslog/configuration dependent. - void setElevatedRemote(BOOL b) { mElevatedRemote = b; } - - // logs are in utc rather than local - void setUTCTimestamp(BOOL utc); - - // Turn on or off logging outputs - void enableError(BOOL active); - void enableErrorTimestamp(BOOL active); - void enableFile(BOOL active); - void enableSyslog(BOOL active); -#if LL_WINDOWS - void enableWinDebug(BOOL active); -#endif // LL_WINDOWS - - protected: - int overflow(int c = EOF); - - private: - char mFilename[LL_MAX_PATH]; /* Flawfinder: ignore */ - int ELevelToSyslogPriority(const ELevel l); - - llofstream *mFile; - std::string mBuf; - LLFixedBuffer *mFixedBuf; - - BOOL mErrorActive; - BOOL mErrorTimestamp; - BOOL mFileActive; - BOOL mSyslogActive; - BOOL mWinDebugActive; - BOOL mElevatedRemote; - BOOL mIsUTC; - - // If priority < level, output is thrown away - ELevel mLevel; - // Current message priority - ELevel mPriority; -}; - -#endif // LL_LLERRORBUFFER_H diff --git a/linden/indra/llcommon/llerrorcontrol.h b/linden/indra/llcommon/llerrorcontrol.h new file mode 100644 index 0000000..f2c8755 --- /dev/null +++ b/linden/indra/llcommon/llerrorcontrol.h @@ -0,0 +1,142 @@ +/** + * @file llerrorcontrol.h + * @date December 2006 + * @brief error message system control + * + * Copyright (c) 2007-2007, Linden Research, Inc. + * + * 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. + */ + +#ifndef LL_LLERRORCONTROL_H +#define LL_LLERRORCONTROL_H + +#include "llerror.h" + +#include + +class LLFixedBuffer; +class LLSD; + +/* + This is the part of the LLError namespace that manages the messages + produced by the logging. The logging support is defined in llerror.h. + Most files do not need to include this. + + These implementations are in llerror.cpp. +*/ + + +namespace LLError +{ + void initForServer(const std::string& identity); + // resets all logging settings to defaults needed by server processes + // logs to stderr, syslog, and windows debug log + // the identity string is used for in the syslog + + void initForApplication(const std::string& dir); + // resets all logging settings to defaults needed by applicaitons + // logs to stderr and windows debug log + // sets up log configuration from the file logcontrol.xml in dir + + + /* + Settings that control what is logged. + Setting a level means log messages at that level or above. + */ + + void setPrintLocation(bool); + void setDefaultLevel(LLError::ELevel); + void setFunctionLevel(const std::string& function_name, LLError::ELevel); + void setClassLevel(const std::string& class_name, LLError::ELevel); + void setFileLevel(const std::string& file_name, LLError::ELevel); + + void configure(const LLSD&); + // the LLSD can configure all of the settings + // usually read automatically from the live errorlog.xml file + + + /* + Control functions. + */ + + typedef void (*FatalFunction)(const std::string& message); + void crashAndLoop(const std::string& message); + // Default fatal funtion: divides by zero and loops forever + + void setFatalFunction(FatalFunction); + // The fatal function will be called when an message of LEVEL_ERROR + // is logged. Note: supressing a LEVEL_ERROR message from being logged + // (by, for example, setting a class level to LEVEL_NONE), will keep + // the that message from causing the fatal funciton to be invoked. + + typedef std::string (*TimeFunction)(); + std::string utcTime(); + + void setTimeFunction(TimeFunction); + // The function is use to return the current time, formatted for + // display by those error recorders that want the time included. + + + + class Recorder + { + // An object that handles the actual output or error messages. + public: + virtual ~Recorder(); + + virtual void recordMessage(LLError::ELevel, const std::string& message) = 0; + // use the level for better display, not for filtering + + virtual bool wantsTime(); // default returns false + // override and return true if the recorder wants the time string + // included in the text of the message + }; + + void addRecorder(Recorder*); + void removeRecorder(Recorder*); + // each error message is passed to each recorder via recordMessage() + + void logToFile(const std::string& filename); + void logToFixedBuffer(LLFixedBuffer*); + // Utilities to add recorders for logging to a file or a fixed buffer + // A second call to the same function will remove the logger added + // with the first. + // Passing the empty string or NULL to just removes any prior. + std::string logFileName(); + // returns name of current logging file, empty string if none + + + /* + Utilities for use by the unit tests of LLError itself. + */ + + class Settings; + Settings* saveAndResetSettings(); + void restoreSettings(Settings *); + + std::string abbreviateFile(const std::string& filePath); + int shouldLogCallCount(); + +}; + +#endif // LL_LLERRORCONTROL_H + diff --git a/linden/indra/llcommon/llerrorlegacy.h b/linden/indra/llcommon/llerrorlegacy.h new file mode 100644 index 0000000..5438a21 --- /dev/null +++ b/linden/indra/llcommon/llerrorlegacy.h @@ -0,0 +1,117 @@ +/** + * @file llerrorlegacy.h + * @date January 2007 + * @brief old things from the older error system + * + * Copyright (c) 2007-2007, Linden Research, Inc. + * + * 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. + */ + +#ifndef LL_LLERRORLEGACY_H +#define LL_LLERRORLEGACY_H + + + +/* + LEGACY -- DO NOT USE THIS STUFF ANYMORE +*/ + +// Specific error codes +const int LL_ERR_NOERR = 0; +const int LL_ERR_ASSET_REQUEST_FAILED = -1; +//const int LL_ERR_ASSET_REQUEST_INVALID = -2; +const int LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3; +const int LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4; +const int LL_ERR_INSUFFICIENT_PERMISSIONS = -5; +const int LL_ERR_EOF = -39; +const int LL_ERR_CANNOT_OPEN_FILE = -42; +const int LL_ERR_FILE_NOT_FOUND = -43; +const int LL_ERR_FILE_EMPTY = -44; +const int LL_ERR_TCP_TIMEOUT = -23016; +const int LL_ERR_CIRCUIT_GONE = -23017; + + + +// Define one of these for different error levels in release... +// #define RELEASE_SHOW_DEBUG // Define this if you want your release builds to show lldebug output. +#define RELEASE_SHOW_INFO // Define this if you want your release builds to show llinfo output +#define RELEASE_SHOW_WARN // Define this if you want your release builds to show llwarn output. + + +////////////////////////////////////////// +// +// Implementation - ignore +// +// +#ifdef _DEBUG +#define SHOW_DEBUG +#define SHOW_WARN +#define SHOW_INFO +#define SHOW_ASSERT +#else // _DEBUG + +#ifdef RELEASE_SHOW_DEBUG +#define SHOW_DEBUG +#endif + +#ifdef RELEASE_SHOW_WARN +#define SHOW_WARN +#endif + +#ifdef RELEASE_SHOW_INFO +#define SHOW_INFO +#endif + +#ifdef RELEASE_SHOW_ASSERT +#define SHOW_ASSERT +#endif + +#endif // _DEBUG + + + +#define lldebugst(type) lldebugs +#define llendflush llendl + + +#define llerror(msg, num) llerrs << "Error # " << num << ": " << msg << llendl; + +#define llwarning(msg, num) llwarns << "Warning # " << num << ": " << msg << llendl; + +#ifdef SHOW_ASSERT +#define llassert(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl; +#else +#define llassert(func) +#endif +#define llassert_always(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl; + +#ifdef SHOW_ASSERT +#define llverify(func) if (!(func)) llerrs << "ASSERT (" << #func << ")" << llendl; +#else +#define llverify(func) (func); // get rid of warning C4189 +#endif + +// handy compile-time assert - enforce those template parameters! +#define cassert(expn) typedef char __C_ASSERT__[(expn)?1:-1] /* Flawfinder: ignore */ + //XXX: used in two places in llcommon/llskipmap.h + +#endif // LL_LLERRORLEGACY_H diff --git a/linden/indra/llcommon/llerrorstream.cpp b/linden/indra/llcommon/llerrorstream.cpp deleted file mode 100644 index ed54d88..0000000 --- a/linden/indra/llcommon/llerrorstream.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/** - * @file llerrorstream.cpp - * @brief Implementation of c++ log straming. - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * - * 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. - */ - -#include "linden_common.h" - -#include "llerrorstream.h" -#include "llerrorbuffer.h" -#include "llerror.h" - -using namespace std; - -// Define this if we're using APR mutexes. -#include "llapr.h" -extern apr_thread_mutex_t *gLogMutexp; - -// In order to compile in Visual C++ 6.0, you must use std:: in the header, and then -// use the std namespace in the cpp. Otherwise, you'll break the (very) fragile C++ parser. -LLErrorStream::LLErrorStream(LLErrorBuffer *eb): - ostream(eb), - mErrorBuffer(eb), - mKill(FALSE), - mErrorCallback(NULL) -{ -#ifdef SHOW_DEBUG - setErrorLevel(LLErrorBuffer::DEBUG); -#else -#ifdef SHOW_INFO - setErrorLevel(LLErrorBuffer::INFO); -#else -#ifdef SHOW_WARN - setErrorLevel(LLErrorBuffer::WARN); -#else - setErrorLevel(LLErrorBuffer::FATAL); -#endif // SHOW_WARN -#endif // SHOW_INFO -#endif // SHOW_DEBUG - - setDebugMask(LLERR_NONE); - setPrintLocation(FALSE); -} - -LLErrorBuffer::ELevel LLErrorStream::ELevelToBufferELevel(const ELevel l) -{ - switch (l) - { - case DEBUG: - return LLErrorBuffer::DEBUG; - case INFO: - return LLErrorBuffer::INFO; - case WARN: - return LLErrorBuffer::WARN; - case FATAL: - return LLErrorBuffer::FATAL; - default: - return LLErrorBuffer::FATAL; - } -} - -LLErrorStream::ELevel LLErrorStream::BufferELevelToELevel(const LLErrorBuffer::ELevel l) -{ - switch(l) - { - case LLErrorBuffer::DEBUG: - return DEBUG; - case LLErrorBuffer::INFO: - return INFO; - case LLErrorBuffer::WARN: - return WARN; - case LLErrorBuffer::FATAL: - return FATAL; - default: - return FATAL; - } -} - - -BOOL LLErrorStream::isEnabledFor(const LLErrorBuffer::ELevel l) -{ - if (l == LLErrorBuffer::FATAL) - { - if (LLErrorBuffer::FATAL < getErrorLevel()) - { - // Fatal error, but we're at log level NONE (used by signal handlers) - // We want to crash this process now instead of logging - _llcrash_and_loop(); - } - } - // Always returns false if not safe (recursive call) - return (getErrorLevel() <= l); -} - - -BOOL LLErrorStream::isEnabledFor(const LLErrorBuffer::ELevel l, const U32 type) -{ - // Always returns false if not safe (recursive call) - return (getErrorLevel() <= l) && (mDebugMask & type); -} - - - -void LLErrorStream::crashOnError(std::ostringstream &oss, LLErrorBuffer::ELevel l) -{ - if (gLogMutexp) - { - const S32 MAX_RETRIES = 5; - S32 attempts = 0; - while (attempts < MAX_RETRIES) - { - apr_status_t s = apr_thread_mutex_trylock(gLogMutexp); - if (!APR_STATUS_IS_EBUSY(s)) - { - break; - } - else - { - attempts++; - ms_sleep(1); - - // - // Just yielding won't necessarily work, I had problems with this on Linux - doug 12/02/04 - //apr_thread_yield(); - } - } - if (attempts == MAX_RETRIES) - { - // We're hosed, we can't get the mutex. - // I guess we just won't log, then. Blah. - fprintf(stderr, "LLErrorStream::crashOnError() failed to get mutex for log\n"); - return; - } - } - - mErrorBuffer->setPriority(l); - if (LLErrorBuffer::FATAL == l) - { - setError(); - } - - *this << oss.str(); - - if (mKill) - { - // We want to flush this stream. - flush(); - } - - BOOL crashme = FALSE; - if (mKill) - { - crashme = TRUE; - } - mKill = FALSE; - - if (gLogMutexp) - { - apr_thread_mutex_unlock(gLogMutexp); - } - - if (crashme) - { - mErrorCallback(oss.str()); - _llcrash_and_loop(); - } -} diff --git a/linden/indra/llcommon/llerrorstream.h b/linden/indra/llcommon/llerrorstream.h deleted file mode 100644 index 4028583..0000000 --- a/linden/indra/llcommon/llerrorstream.h +++ /dev/null @@ -1,126 +0,0 @@ -/** - * @file llerrorstream.h - * @brief Declaration of c++ log straming. - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * - * 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. - */ - -#ifndef LL_LLERRORSTREAM_H -#define LL_LLERRORSTREAM_H - -// Usage: -// LLErrorStream gErrorStream(gErrorBuffer); -// -// gErrorStream << debug << "This is a debug message" << endl; -// -// gErrorStream << fatal << "This message will cause a crash!" << endl; - -#include -#include "llerrorbuffer.h" -#include "stdtypes.h" - -class LLFixedBuffer; - -class LLErrorStream : public std::ostream -{ - public: - LLErrorStream(LLErrorBuffer *eb); - - // Specify error levels-- Use LLErrorBuffer::ELevel instead - enum ELevel - { - DEBUG = 0, - INFO = 1, - WARN = 2, - FATAL = 3, - NONE = 4 // Don't log anything - }; - - LLErrorBuffer *mErrorBuffer; - - // This is used to specify if we need to merge the DebugMask - // or replace it - enum EControl - { - REPLACE = 0, - MERGE = 1 - }; - - void setDebugMask(U32 mask) { mDebugMask = mask; } - void mergeDebugMask(U32 mask) { mDebugMask |= mask; } - U32 getDebugMask() { return mDebugMask; } - void setDebugFlag(U32 flag) { mDebugMask |= flag; } - void clearDebugFlag(U32 flag) { mDebugMask &= ~flag; } - BOOL setFile(const char *path) { return mErrorBuffer->setFile(path); } - void closeFile() { mErrorBuffer->closeFile(); } - const char *getFilename() const { return mErrorBuffer->getFilename(); } - void setFixedBuffer(LLFixedBuffer *b) { mErrorBuffer->setFixedBuffer(b); } - void setErrorLevel(const LLErrorBuffer::ELevel l) { mErrorBuffer->setLevel(l); } - LLErrorBuffer::ELevel getErrorLevel() { return mErrorBuffer->getLevel(); } - void mergeErrorLevel(const LLErrorBuffer::ELevel l) { mErrorBuffer->mergeLevel(l); } - void setError() { mKill = TRUE; }; - void crashOnError(std::ostringstream &ss, LLErrorBuffer::ELevel l); - - BOOL isEnabledFor(const LLErrorBuffer::ELevel l); - BOOL isEnabledFor(const LLErrorBuffer::ELevel l, const U32 type); - - - void mergeLevel(const LLErrorBuffer::ELevel l) { mErrorBuffer->mergeLevel(l); } - - void setPrintLocation(BOOL b) { mPrintLocation = b; } - BOOL getPrintLocation() { return mPrintLocation; } - - void setElevatedRemote(BOOL b) { mErrorBuffer->setElevatedRemote(b); } - void setUTCTimestamp(BOOL utc) { mErrorBuffer->setUTCTimestamp(utc); } - - // Deprecated - void setLevel(const ELevel l) { setErrorLevel(ELevelToBufferELevel(l)); } - ELevel getLevel() { return BufferELevelToELevel(getErrorLevel()); } - void mergeLevel(const ELevel l) { mergeErrorLevel(ELevelToBufferELevel(l)); } - - - // Backwards compatilibity cruft. Should be removed - void mergeTime(BOOL b) { } // NOP - void mergeLocation(BOOL b) { } // NOP - void setTime(BOOL b) { } // NOP - char *getTime() { return ""; } // NOP - - typedef void(*LLErrorCallback)(const std::string &error_string); - void setErrorCallback(LLErrorCallback callback) {mErrorCallback = callback;} - -private: - // This maintains the existing ELevel interface, but new code should use - // LLErrorBuffer::ELevel instead. - LLErrorBuffer::ELevel ELevelToBufferELevel(const ELevel l); - ELevel BufferELevelToELevel(const LLErrorBuffer::ELevel l); - U32 mDebugMask; // Mask for debugst() output - - BOOL mPrintLocation; - - S32 mSafeDepth; // Counter so we can safely do recursive calls, 0 means we're OK - BOOL mKill; - LLErrorCallback mErrorCallback; -}; - - -#endif // LL_LLERRORSTREAM_H diff --git a/linden/indra/llcommon/llevent.cpp b/linden/indra/llcommon/llevent.cpp index e9b6a51..bbb37c5 100644 --- a/linden/indra/llcommon/llevent.cpp +++ b/linden/indra/llcommon/llevent.cpp @@ -186,16 +186,14 @@ void LLSimpleDispatcher::addListener(LLEventListener* listener, LLSD filter, con void LLSimpleDispatcher::removeListener(LLEventListener* listener) { - std::vector::iterator itor; - for (itor=mListeners.begin(); itor!=mListeners.end();) + std::vector::iterator itor = mListeners.begin(); + std::vector::iterator end = mListeners.end(); + for (; itor != end; ++itor) { if ((*itor).listener == listener) { mListeners.erase(itor); - } - else - { - ++itor; + break; } } listener->handleDetach(mParent); diff --git a/linden/indra/llcommon/llevent.h b/linden/indra/llcommon/llevent.h index c48817e..bcb6ee9 100644 --- a/linden/indra/llcommon/llevent.h +++ b/linden/indra/llcommon/llevent.h @@ -31,6 +31,7 @@ #include "llsd.h" #include "llmemory.h" +#include "llthread.h" class LLEventListener; class LLEvent; @@ -128,6 +129,7 @@ public: // Adds a listener to this dispatcher, with a given user data // that will be passed to the listener when an event is fired. + // Duplicate pointers are removed on addtion. void addListener(LLEventListener *listener, LLSD filter, const LLSD& userdata); // Removes a listener from this dispatcher diff --git a/linden/indra/llcommon/llfasttimer.h b/linden/indra/llcommon/llfasttimer.h index b5e0734..47634ac 100644 --- a/linden/indra/llcommon/llfasttimer.h +++ b/linden/indra/llcommon/llfasttimer.h @@ -44,6 +44,7 @@ public: FTM_UPDATE, FTM_RENDER, FTM_SWAP, + FTM_CLIENT_COPY, FTM_IDLE, FTM_SLEEP, @@ -56,13 +57,23 @@ public: FTM_UPDATE_TERRAIN, FTM_UPDATE_PRIMITIVES, FTM_UPDATE_PARTICLES, + FTM_SIMULATE_PARTICLES, FTM_UPDATE_SKY, FTM_UPDATE_TEXTURES, + FTM_UPDATE_WATER, + FTM_UPDATE_CLOUDS, + FTM_UPDATE_GRASS, + FTM_UPDATE_TREE, + FTM_UPDATE_AVATAR, // common render components FTM_RENDER_GEOMETRY, FTM_RENDER_TERRAIN, FTM_RENDER_SIMPLE, + FTM_RENDER_FULLBRIGHT, + FTM_RENDER_GLOW, + FTM_RENDER_GRASS, + FTM_RENDER_INVISIBLE, FTM_RENDER_SHINY, FTM_RENDER_BUMP, FTM_RENDER_TREES, @@ -81,6 +92,20 @@ public: FTM_MESSAGES, FTM_REBUILD, FTM_STATESORT, + FTM_STATESORT_DRAWABLE, + FTM_STATESORT_POSTSORT, + FTM_REBUILD_VBO, + FTM_REBUILD_VOLUME_VB, + FTM_REBUILD_BRIDGE_VB, + FTM_REBUILD_HUD_VB, + FTM_REBUILD_TERRAIN_VB, + FTM_REBUILD_WATER_VB, + FTM_REBUILD_TREE_VB, + FTM_REBUILD_PARTICLE_VB, + FTM_REBUILD_CLOUD_VB, + FTM_REBUILD_GRASS_VB, + FTM_REBUILD_NONE_VB, + FTM_REBUILD_OCCLUSION_VB, FTM_POOLS, FTM_POOLRENDER, FTM_IDLE_CB, @@ -90,6 +115,7 @@ public: FTM_UPDATE_LIGHTS, FTM_CULL, FTM_CULL_REBOUND, + FTM_FRUSTUM_CULL, FTM_GEO_UPDATE, FTM_GEO_RESERVE, FTM_GEO_LIGHT, @@ -116,6 +142,7 @@ public: FTM_IMAGE_UPDATE, FTM_IMAGE_CREATE, FTM_IMAGE_DECODE, + FTM_IMAGE_MARK_DIRTY, FTM_PIPELINE, FTM_VFILE_WAIT, FTM_FLEXIBLE_UPDATE, diff --git a/linden/indra/llcommon/llfile.cpp b/linden/indra/llcommon/llfile.cpp index d9fd360..feac28f 100644 --- a/linden/indra/llcommon/llfile.cpp +++ b/linden/indra/llcommon/llfile.cpp @@ -48,6 +48,19 @@ int LLFile::mkdir(const char* dirname, int perms) } // static +int LLFile::rmdir(const char* dirname) +{ +#if LL_WINDOWS + // permissions are ignored on Windows + std::string utf8dirname = dirname; + llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname); + return _wrmdir(utf16dirname.c_str()); +#else + return ::rmdir(dirname); +#endif +} + +// static LLFILE* LLFile::fopen(const char* filename, const char* mode) /* Flawfinder: ignore */ { #if LL_WINDOWS @@ -184,9 +197,9 @@ void llifstream::close() } } -void llifstream::open(const char *_Filename, +void llifstream::open(const char* _Filename, /* Flawfinder: ignore */ ios_base::openmode _Mode, - int _Prot) /* Flawfinder: ignore */ + int _Prot) { // open a C stream with specified mode FILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::in, _Prot); @@ -197,6 +210,7 @@ void llifstream::open(const char *_Filename, } llassert(_Filebuffer == NULL); _Filebuffer = new _Myfb(filep); + _ShouldClose = true; _Myios::init(_Filebuffer); } @@ -208,13 +222,17 @@ bool llifstream::is_open() const } llifstream::~llifstream() { + if (_ShouldClose) + { + close(); + } delete _Filebuffer; } llifstream::llifstream(const char *_Filename, ios_base::openmode _Mode, int _Prot) - : std::basic_istream< char , std::char_traits< char > >(NULL,true),_Filebuffer(NULL) + : std::basic_istream< char , std::char_traits< char > >(NULL,true),_Filebuffer(NULL),_ShouldClose(false) { // construct with named file and specified mode open(_Filename, _Mode | ios_base::in, _Prot); /* Flawfinder: ignore */ @@ -230,9 +248,9 @@ bool llofstream::is_open() const return false; } -void llofstream::open(const char *_Filename, +void llofstream::open(const char* _Filename, /* Flawfinder: ignore */ ios_base::openmode _Mode, - int _Prot) /* Flawfinder: ignore */ + int _Prot) { // open a C stream with specified mode FILE* filep = LLFile::_Fiopen(_Filename,_Mode | ios_base::out, _Prot); diff --git a/linden/indra/llcommon/llfile.h b/linden/indra/llcommon/llfile.h index 554308f..5034cf7 100644 --- a/linden/indra/llcommon/llfile.h +++ b/linden/indra/llcommon/llfile.h @@ -69,6 +69,7 @@ public: // be overridden by the user's umask. It is ignored on Windows. static int mkdir(const char* filename, int perms = 0700); + static int rmdir(const char* filename); static int remove(const char* filename); static int rename(const char* filename,const char* newname); static int stat(const char* filename,llstat* file_status); @@ -87,7 +88,7 @@ public: typedef std::basic_ios > _Myios; llifstream() - : std::basic_istream >(NULL,true),_Filebuffer(NULL) + : std::basic_istream >(NULL,true),_Filebuffer(NULL),_ShouldClose(false) { // construct unopened } @@ -97,7 +98,8 @@ public: explicit llifstream(_Filet *_File) : std::basic_istream >(NULL,true), - _Filebuffer(new _Myfb(_File)) + _Filebuffer(new _Myfb(_File)), + _ShouldClose(false) { // construct with specified C stream } virtual ~llifstream(); @@ -107,13 +109,14 @@ public: return _Filebuffer; } bool is_open() const; - void open(const char *_Filename, + void open(const char* _Filename, /* Flawfinder: ignore */ ios_base::openmode _Mode = ios_base::in, - int _Prot = (int)ios_base::_Openprot); /* Flawfinder: ignore */ + int _Prot = (int)ios_base::_Openprot); void close(); private: _Myfb* _Filebuffer; // the file buffer + bool _ShouldClose; }; diff --git a/linden/indra/llcommon/llformat.cpp b/linden/indra/llcommon/llformat.cpp new file mode 100644 index 0000000..f088bc6 --- /dev/null +++ b/linden/indra/llcommon/llformat.cpp @@ -0,0 +1,47 @@ +/** + * @file llformat.cpp + * @date January 2007 + * @brief string formatting utility + * + * Copyright (c) 2007-2007, Linden Research, Inc. + * + * 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. + */ + +#include "linden_common.h" + +#include "llformat.h" + +#include + +std::string llformat(const char *fmt, ...) +{ + char tstr[1024]; /* Flawfinder: ignore */ + va_list va; + va_start(va, fmt); +#if LL_WINDOWS + _vsnprintf(tstr, 1024, fmt, va); +#else + vsnprintf(tstr, 1024, fmt, va); /* Flawfinder: ignore */ +#endif + va_end(va); + return std::string(tstr); +} diff --git a/linden/indra/llcommon/llformat.h b/linden/indra/llcommon/llformat.h new file mode 100644 index 0000000..135f9d2 --- /dev/null +++ b/linden/indra/llcommon/llformat.h @@ -0,0 +1,42 @@ +/** + * @file llformat.h + * @date January 2007 + * @brief string formatting utility + * + * Copyright (c) 2007-2007, Linden Research, Inc. + * + * 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. + */ + +#ifndef LL_LLFORMAT_H +#define LL_LLFORMAT_H + +#include + +// Use as follows: +// llinfos << llformat("Test:%d (%.2f %.2f)", idx, x, y) << llendl; +// +// *NOTE: buffer limited to 1024, (but vsnprintf prevents overrun) +// should perhaps be replaced with boost::format. + +std::string llformat(const char *fmt, ...); + +#endif // LL_LLFORMAT_H diff --git a/linden/indra/llcommon/llliveappconfig.cpp b/linden/indra/llcommon/llliveappconfig.cpp new file mode 100644 index 0000000..bcffa7c --- /dev/null +++ b/linden/indra/llcommon/llliveappconfig.cpp @@ -0,0 +1,65 @@ +/** + * @file llliveappconfig.cpp + * @brief Configuration information for an LLApp that overrides indra.xml + * + * Copyright (c) 2003-2007, Linden Research, Inc. + * + * 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. + */ + +#include "linden_common.h" + +#include "llliveappconfig.h" + +#include "llapp.h" +#include "llsd.h" +#include "llsdserialize.h" + +LLLiveAppConfig::LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period) +: LLLiveFile(filename, refresh_period), + mApp(app) +{ } + + +LLLiveAppConfig::~LLLiveAppConfig() +{ } + +// virtual +void LLLiveAppConfig::loadFile() +{ + llinfos << "LLLiveAppConfig::loadFile(): reading from " + << filename() << llendl; + llifstream file(filename().c_str()); + LLSD config; + if (file.is_open()) + { + LLSDSerialize::fromXML(config, file); + if(!config.isMap()) + { + llinfos << "LLDataserverConfig::loadFile(): not an map!" + << " Ignoring the data." << llendl; + return; + } + file.close(); + } + mApp->setOptionData( + LLApp::PRIORITY_SPECIFIC_CONFIGURATION, config); +} diff --git a/linden/indra/llcommon/llliveappconfig.h b/linden/indra/llcommon/llliveappconfig.h new file mode 100644 index 0000000..822410f --- /dev/null +++ b/linden/indra/llcommon/llliveappconfig.h @@ -0,0 +1,52 @@ +/** + * @file llliveappconfig.h + * @brief Configuration information for an LLApp that overrides indra.xml + * + * Copyright (c) 2003-2007, Linden Research, Inc. + * + * 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. + */ + +#ifndef LLLIVEAPPCONFIG_H +#define LLLIVEAPPCONFIG_H + +#include "lllivefile.h" + +class LLApp; + +class LLLiveAppConfig : public LLLiveFile +{ +public: + // To use this, instantiate a LLLiveAppConfig object inside your main loop. + // The traditional name for it is live_config. + // Be sure to call live_config.checkAndReload() periodically. + + LLLiveAppConfig(LLApp* app, const std::string& filename, F32 refresh_period); + ~LLLiveAppConfig(); + +protected: + /*virtual*/ void loadFile(); + +private: + LLApp* mApp; +}; + +#endif diff --git a/linden/indra/llcommon/lllivefile.cpp b/linden/indra/llcommon/lllivefile.cpp index 33e2014..d289671 100644 --- a/linden/indra/llcommon/lllivefile.cpp +++ b/linden/indra/llcommon/lllivefile.cpp @@ -27,24 +27,56 @@ #include "linden_common.h" #include "lllivefile.h" +#include "llframetimer.h" +#include "lltimer.h" +class LLLiveFile::Impl +{ +public: + Impl(const std::string &filename, const F32 refresh_period); + ~Impl(); + + bool check(); + + + bool mForceCheck; + F32 mRefreshPeriod; + LLFrameTimer mRefreshTimer; -LLLiveFile::LLLiveFile(const std::string &filename, const F32 refresh_period) : -mForceCheck(true), -mRefreshPeriod(refresh_period), -mFilename(filename), -mLastModTime(0), -mLastExists(false) + std::string mFilename; + time_t mLastModTime; + bool mLastExists; + + LLEventTimer* mEventTimer; +}; + +LLLiveFile::Impl::Impl(const std::string &filename, const F32 refresh_period) + : mForceCheck(true), + mRefreshPeriod(refresh_period), + mFilename(filename), + mLastModTime(0), + mLastExists(false), + mEventTimer(NULL) { } +LLLiveFile::Impl::~Impl() +{ + delete mEventTimer; +} + +LLLiveFile::LLLiveFile(const std::string &filename, const F32 refresh_period) + : impl(* new Impl(filename, refresh_period)) +{ +} LLLiveFile::~LLLiveFile() { + delete &impl; } -bool LLLiveFile::checkAndReload() +bool LLLiveFile::Impl::check() { if (!mForceCheck && mRefreshTimer.getElapsedTimeF32() < mRefreshPeriod) { @@ -65,9 +97,8 @@ bool LLLiveFile::checkAndReload() // broken somehow. Clear flags and return. if (mLastExists) { - loadFile(); // Load the file, even though it's missing to allow it to clear state. mLastExists = false; - return true; + return true; // no longer existing is a change! } return false; } @@ -87,7 +118,44 @@ bool LLLiveFile::checkAndReload() mLastExists = true; mLastModTime = stat_data.st_mtime; - loadFile(); return true; } +bool LLLiveFile::checkAndReload() +{ + bool changed = impl.check(); + if (changed) + { + loadFile(); + } + return changed; +} + +std::string LLLiveFile::filename() const +{ + return impl.mFilename; +} + +namespace +{ + class LiveFileEventTimer : public LLEventTimer + { + public: + LiveFileEventTimer(LLLiveFile& f, F32 refresh) + : LLEventTimer(refresh), mLiveFile(f) + { } + + void tick() + { mLiveFile.checkAndReload(); } + + private: + LLLiveFile& mLiveFile; + }; + +} + +void LLLiveFile::addToEventTimer() +{ + impl.mEventTimer = new LiveFileEventTimer(*this, impl.mRefreshPeriod); +} + diff --git a/linden/indra/llcommon/lllivefile.h b/linden/indra/llcommon/lllivefile.h index b305531..fbf2bdf 100644 --- a/linden/indra/llcommon/lllivefile.h +++ b/linden/indra/llcommon/lllivefile.h @@ -28,7 +28,6 @@ #ifndef LL_LLLIVEFILE_H #define LL_LLLIVEFILE_H -#include "llframetimer.h" class LLLiveFile { @@ -36,18 +35,22 @@ public: LLLiveFile(const std::string &filename, const F32 refresh_period = 5.f); virtual ~LLLiveFile(); - bool checkAndReload(); // Returns true if the file changed in any way + bool checkAndReload(); + // Returns true if the file changed in any way + // Call this before using anything that was read & cached from the file + + std::string filename() const; + + void addToEventTimer(); + // Normally, just calling checkAndReload() is enough. In some cases + // though, you may need to let the live file periodically check itself. protected: virtual void loadFile() = 0; // Implement this to load your file if it changed - bool mForceCheck; - F32 mRefreshPeriod; - LLFrameTimer mRefreshTimer; - - std::string mFilename; - time_t mLastModTime; - bool mLastExists; +private: + class Impl; + Impl& impl; }; #endif //LL_LLLIVEFILE_H diff --git a/linden/indra/llcommon/lllslconstants.h b/linden/indra/llcommon/lllslconstants.h index 52d2858..08c63e3 100644 --- a/linden/indra/llcommon/lllslconstants.h +++ b/linden/indra/llcommon/lllslconstants.h @@ -155,4 +155,8 @@ const S32 LIST_STAT_SUM_SQUARES = 7; const S32 LIST_STAT_NUM_COUNT = 8; const S32 LIST_STAT_GEO_MEAN = 9; +const S32 STRING_TRIM_HEAD = 0x01; +const S32 STRING_TRIM_TAIL = 0x02; +const S32 STRING_TRIM = STRING_TRIM_HEAD | STRING_TRIM_TAIL; + #endif diff --git a/linden/indra/llcommon/llmemory.cpp b/linden/indra/llcommon/llmemory.cpp index 9bfbf88..8528433 100644 --- a/linden/indra/llcommon/llmemory.cpp +++ b/linden/indra/llcommon/llmemory.cpp @@ -28,6 +28,12 @@ #include "linden_common.h" #include "llmemory.h" +#include "llmemtype.h" + +// not defining nullfunc will currently crash when trying to use a LLHandle +template< typename _Ty > + const typename LLHandle< _Ty >::NullFunc + LLHandle< _Ty >::sNullFunc = LLHandle< _Ty >::defaultNullFunc; //---------------------------------------------------------------------------- @@ -258,43 +264,6 @@ void operator delete[] (void *p) //---------------------------------------------------------------------------- -//static -LLMutex* LLThreadSafeRefCount::sMutex = 0; - -//static -void LLThreadSafeRefCount::initClass() -{ - if (!sMutex) - { - sMutex = new LLMutex(0); - } -} - -//static -void LLThreadSafeRefCount::cleanupClass() -{ - delete sMutex; - sMutex = NULL; -} - - -//---------------------------------------------------------------------------- - -LLThreadSafeRefCount::LLThreadSafeRefCount() : - mRef(0) -{ -} - -LLThreadSafeRefCount::~LLThreadSafeRefCount() -{ - if (mRef != 0) - { - llerrs << "deleting non-zero reference" << llendl; - } -} - -//---------------------------------------------------------------------------- - LLRefCount::LLRefCount() : mRef(0) { diff --git a/linden/indra/llcommon/llmemory.h b/linden/indra/llcommon/llmemory.h index b40ab79..7a7996b 100644 --- a/linden/indra/llcommon/llmemory.h +++ b/linden/indra/llcommon/llmemory.h @@ -31,8 +31,6 @@ #include #include "llerror.h" -#include "llthread.h" -#include "llmemtype.h" extern S32 gTotalDAlloc; extern S32 gTotalDAUse; @@ -61,53 +59,7 @@ private: // LLPointer x = new LLFoo; // constructor does not do anything interesting // x->instantiate(); // does stuff like place x into an update queue -class LLThreadSafeRefCount -{ -public: - static void initClass(); // creates sMutex - static void cleanupClass(); // destroys sMutex - -private: - static LLMutex* sMutex; - -private: - LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented - LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented - -protected: - virtual ~LLThreadSafeRefCount(); // use unref() - -public: - LLThreadSafeRefCount(); - - void ref() - { - if (sMutex) sMutex->lock(); - mRef++; - if (sMutex) sMutex->unlock(); - } - - S32 unref() - { - llassert(mRef >= 1); - if (sMutex) sMutex->lock(); - S32 res = --mRef; - if (sMutex) sMutex->unlock(); - if (0 == res) - { - delete this; - res = 0; - } - return res; - } - S32 getNumRefs() const - { - return mRef; - } - -private: - S32 mRef; -}; +// see llthread.h for LLThreadSafeRefCount //---------------------------------------------------------------------------- @@ -139,6 +91,7 @@ public: } return mRef; } + S32 getNumRefs() const { return mRef; @@ -150,6 +103,7 @@ private: //---------------------------------------------------------------------------- +// Note: relies on Type having ref() and unref() methods template class LLPointer { public: @@ -268,6 +222,154 @@ protected: Type* mPointer; }; +//template +//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 LLHandle. +// + +template +class LLHandle +{ +public: + LLHandle() : + mPointer(sNullFunc()) + { + ref(); + } + + LLHandle(Type* ptr) : + mPointer(nonNull(ptr)) + { + ref(); + } + + LLHandle(const LLHandle& ptr) : + mPointer(ptr.mPointer) + { + ref(); + } + + // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template + LLHandle(const LLHandle& ptr) : + mPointer(ptr.get()) + { + ref(); + } + + ~LLHandle() + { + 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 != sNullFunc()); } + operator bool() const { return (mPointer != sNullFunc()); } + bool operator!() const { return (mPointer == sNullFunc()); } + bool isNull() const { return (mPointer == sNullFunc()); } + bool notNull() const { return (mPointer != sNullFunc()); } + + + operator Type*() const { return mPointer; } + operator const Type*() const { return mPointer; } + bool operator !=(Type* ptr) const { return (mPointer != nonNull(ptr)); } + bool operator ==(Type* ptr) const { return (mPointer == nonNull(ptr)); } + bool operator ==(const LLHandle& ptr) const { return (mPointer == ptr.mPointer); } + bool operator < (const LLHandle& ptr) const { return (mPointer < ptr.mPointer); } + bool operator > (const LLHandle& ptr) const { return (mPointer > ptr.mPointer); } + + LLHandle& operator =(Type* ptr) + { + if( mPointer != ptr ) + { + unref(); + mPointer = nonNull(ptr); + ref(); + } + + return *this; + } + + LLHandle& operator =(const LLHandle& 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 + LLHandle& operator =(const LLHandle& ptr) + { + if( mPointer != ptr.get() ) + { + unref(); + mPointer = ptr.get(); + ref(); + } + 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 = sNullFunc(); + tempp->unref(); + if (mPointer != sNullFunc()) + { + llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; + unref(); + } + } + } + + static Type* nonNull(Type* ptr) + { + return ptr == NULL ? sNullFunc() : ptr; + } + + static Type* defaultNullFunc() + { + llerrs << "No null value provided for LLHandle" << llendl; + return NULL; + } + +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 > diff --git a/linden/indra/llcommon/llmemtype.h b/linden/indra/llcommon/llmemtype.h index 15ef924..0af1ed3 100644 --- a/linden/indra/llcommon/llmemtype.h +++ b/linden/indra/llcommon/llmemtype.h @@ -71,6 +71,7 @@ public: MTYPE_DRAWABLE, MTYPE_OBJECT, + MTYPE_VERTEX_DATA, MTYPE_SPACE_PARTITION, MTYPE_PIPELINE, MTYPE_AVATAR, diff --git a/linden/indra/llcommon/llpreprocessor.h b/linden/indra/llcommon/llpreprocessor.h index f03fe89..9db0108 100644 --- a/linden/indra/llcommon/llpreprocessor.h +++ b/linden/indra/llcommon/llpreprocessor.h @@ -51,7 +51,9 @@ #define LL_LIBXUL_ENABLED 1 #elif LL_LINUX #define LL_QUICKTIME_ENABLED 0 - #define LL_LIBXUL_ENABLED 0 + #ifndef LL_LIBXUL_ENABLED + #define LL_LIBXUL_ENABLED 1 + #endif // def LL_LIBXUL_ENABLED #endif #if LL_LIBXUL_ENABLED && !defined(MOZILLA_INTERNAL_API) @@ -80,7 +82,7 @@ // Deal with the differeneces on Windows #if defined(LL_WINDOWS) -#define snprintf _snprintf +#define snprintf _snprintf /*Flawfinder: ignore*/ #endif // LL_WINDOWS // Static linking with apr on windows needs to be declared. @@ -110,6 +112,7 @@ #pragma warning( disable : 4284 ) // silly MS warning deep inside their include file #pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation. #pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) +#pragma warning( disable : 4996 ) // warning: deprecated #endif // LL_WINDOWS #endif // not LL_LINDEN_PREPROCESSOR_H diff --git a/linden/indra/llcommon/llprocessor.cpp b/linden/indra/llcommon/llprocessor.cpp index b811678..3408cb1 100644 --- a/linden/indra/llcommon/llprocessor.cpp +++ b/linden/indra/llcommon/llprocessor.cpp @@ -604,7 +604,7 @@ bool CProcessor::AnalyzeIntelProcessor() mov sig3, edx } // Then we convert the data to a readable string - snprintf( + snprintf( /* Flawfinder: ignore */ CPUInfo.strProcessorSerial, sizeof(CPUInfo.strProcessorSerial), "%04lX-%04lX-%04lX-%04lX-%04lX-%04lX", @@ -612,15 +612,15 @@ bool CProcessor::AnalyzeIntelProcessor() sig1 & 0xFFFF, sig3 >> 16, sig3 & 0xFFFF, - sig2 >> 16, sig2 & 0xFFFF); /* Flawfinder: ignore */ + sig2 >> 16, sig2 & 0xFFFF); } else { // If there's no serial number support we just put "No serial number" - snprintf( + snprintf( /* Flawfinder: ignore */ CPUInfo.strProcessorSerial, sizeof(CPUInfo.strProcessorSerial), - "No Processor Serial Number"); /* Flawfinder: ignore */ + "No Processor Serial Number"); } // Now we get the standard processor extensions @@ -854,7 +854,7 @@ bool CProcessor::AnalyzeAMDProcessor() break; case 0xD: // Model = 0xD: K6-2+ / K6-III+ strcpy(CPUInfo.strModel, "AMD K6-2+ or K6-III+ (0.18 micron)"); /* Flawfinder: ignore */ - strncat(strCPUName, "AMD K6-2+ or K6-III+ (0.18 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); + strncat(strCPUName, "AMD K6-2+ or K6-III+ (0.18 micron)", sizeof(strCPUName) - strlen(strCPUName) -1); /* Flawfinder: ignore */ break; default: // ... strcpy(CPUInfo.strModel, "Unknown AMD K5 or K6 model"); /* Flawfinder: ignore */ diff --git a/linden/indra/llcommon/llqueuedthread.cpp b/linden/indra/llcommon/llqueuedthread.cpp index 565836b..2e4324b 100644 --- a/linden/indra/llcommon/llqueuedthread.cpp +++ b/linden/indra/llcommon/llqueuedthread.cpp @@ -31,10 +31,9 @@ //============================================================================ // MAIN THREAD -LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool runalways) : +LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) : LLThread(name), mThreaded(threaded), - mRunAlways(runalways), mIdleThread(TRUE), mNextHandle(0) { @@ -47,6 +46,12 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool runa // MAIN THREAD LLQueuedThread::~LLQueuedThread() { + shutdown(); + // ~LLThread() will be called here +} + +void LLQueuedThread::shutdown() +{ setQuitting(); unpause(); // MAIN THREAD @@ -73,61 +78,69 @@ LLQueuedThread::~LLQueuedThread() } QueuedRequest* req; + S32 active_count = 0; while ( (req = (QueuedRequest*)mRequestHash.pop_element()) ) { + if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS) + { + ++active_count; + } req->deleteRequest(); } - - // ~LLThread() will be called here + if (active_count) + { + llwarns << "~LLQueuedThread() called with active requests: " << active_count << llendl; + } } //---------------------------------------------------------------------------- // MAIN THREAD -void LLQueuedThread::update(U32 ms_elapsed) +// virtual +S32 LLQueuedThread::update(U32 max_time_ms) { - updateQueue(0); + return updateQueue(max_time_ms); } -void LLQueuedThread::updateQueue(S32 inc) +S32 LLQueuedThread::updateQueue(U32 max_time_ms) { - // If mRunAlways == TRUE, unpause the thread whenever we put something into the queue. - // If mRunAlways == FALSE, we only unpause the thread when updateQueue() is called from the main loop (i.e. between rendered frames) - - if (inc == 0) // Frame Update + F64 max_time = (F64)max_time_ms * .001; + LLTimer timer; + S32 pending = 1; + + // Frame Update + if (mThreaded) { - if (mThreaded) - { - unpause(); - wake(); // Wake the thread up if necessary. - } - else + pending = getPending(); + unpause(); + } + else + { + while (pending > 0) { - while (processNextRequest() > 0) - ; + pending = processNextRequest(); + if (max_time && timer.getElapsedTimeF64() > max_time) + break; } } - else + return pending; +} + +void LLQueuedThread::incQueue() +{ + // Something has been added to the queue + if (!isPaused()) { - // Something has been added to the queue - if (mRunAlways) + if (mThreaded) { - if (mThreaded) - { - wake(); // Wake the thread up if necessary. - } - else - { - while(processNextRequest() > 0) - ; - } + wake(); // Wake the thread up if necessary. } } } //virtual // May be called from any thread -S32 LLQueuedThread::getPending(bool child_thread) +S32 LLQueuedThread::getPending() { S32 res; lockData(); @@ -141,7 +154,7 @@ void LLQueuedThread::waitOnPending() { while(1) { - updateQueue(0); + update(0); if (mIdleThread) { @@ -200,7 +213,7 @@ bool LLQueuedThread::addRequest(QueuedRequest* req) #endif unlockData(); - updateQueue(1); + incQueue(); return true; } @@ -214,7 +227,7 @@ bool LLQueuedThread::waitForResult(LLQueuedThread::handle_t handle, bool auto_co bool done = false; while(!done) { - updateQueue(0); // unpauses + update(0); // unpauses lockData(); QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); if (!req) @@ -272,51 +285,47 @@ LLQueuedThread::status_t LLQueuedThread::getRequestStatus(handle_t handle) return res; } -LLQueuedThread::status_t LLQueuedThread::abortRequest(handle_t handle, U32 flags) +void LLQueuedThread::abortRequest(handle_t handle, bool autocomplete) { - status_t res = STATUS_EXPIRED; lockData(); QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); if (req) { - res = req->abortRequest(flags); - if ((flags & AUTO_COMPLETE) && (res == STATUS_COMPLETE)) - { - mRequestHash.erase(handle); - req->deleteRequest(); -// check(); - } -#if _DEBUG -// llinfos << llformat("LLQueuedThread::Aborted req [%08d]",handle) << llendl; -#endif + req->setFlags(FLAG_ABORT | (autocomplete ? FLAG_AUTO_COMPLETE : 0)); } unlockData(); - return res; } // MAIN thread -LLQueuedThread::status_t LLQueuedThread::setFlags(handle_t handle, U32 flags) +void LLQueuedThread::setFlags(handle_t handle, U32 flags) { - status_t res = STATUS_EXPIRED; lockData(); QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); if (req) { - res = req->setFlags(flags); + req->setFlags(flags); } unlockData(); - return res; } void LLQueuedThread::setPriority(handle_t handle, U32 priority) { lockData(); QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); - if (req && (req->getStatus() == STATUS_QUEUED)) + if (req) { - llverify(mRequestQueue.erase(req) == 1); - req->setPriority(priority); - mRequestQueue.insert(req); + if(req->getStatus() == STATUS_INPROGRESS) + { + // not in list + req->setPriority(priority); + } + else if(req->getStatus() == STATUS_QUEUED) + { + // remove from list then re-insert + llverify(mRequestQueue.erase(req) == 1); + req->setPriority(priority); + mRequestQueue.insert(req); + } } unlockData(); } @@ -328,9 +337,10 @@ bool LLQueuedThread::completeRequest(handle_t handle) QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); if (req) { - llassert(req->getStatus() != STATUS_QUEUED && req->getStatus() != STATUS_ABORT); + llassert_always(req->getStatus() != STATUS_QUEUED); + llassert_always(req->getStatus() != STATUS_INPROGRESS); #if _DEBUG -// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl; +// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl; #endif mRequestHash.erase(handle); req->deleteRequest(); @@ -364,28 +374,34 @@ bool LLQueuedThread::check() //============================================================================ // Runs on its OWN thread -int LLQueuedThread::processNextRequest() +S32 LLQueuedThread::processNextRequest() { - QueuedRequest *req = 0; + QueuedRequest *req; // Get next request from pool lockData(); while(1) { - if (!mRequestQueue.empty()) + req = NULL; + if (mRequestQueue.empty()) { - req = *mRequestQueue.begin(); - mRequestQueue.erase(mRequestQueue.begin()); + break; } - if (req && req->getStatus() == STATUS_ABORT) + req = *mRequestQueue.begin(); + mRequestQueue.erase(mRequestQueue.begin()); + if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING)) { req->setStatus(STATUS_ABORTED); - req = 0; - } - else - { - llassert (!req || req->getStatus() == STATUS_QUEUED) - break; + req->finishRequest(false); + if (req->getFlags() & FLAG_AUTO_COMPLETE) + { + mRequestHash.erase(req); + req->deleteRequest(); +// check(); + } + continue; } + llassert_always(req->getStatus() == STATUS_QUEUED); + break; } if (req) { @@ -393,22 +409,22 @@ int LLQueuedThread::processNextRequest() } unlockData(); - // This is the only place we will cal req->setStatus() after + // This is the only place we will call req->setStatus() after // it has initially been seet to STATUS_QUEUED, so it is // safe to access req. if (req) { // process request - bool complete = processRequest(req); + bool complete = req->processRequest(); if (complete) { lockData(); req->setStatus(STATUS_COMPLETE); - req->finishRequest(); - if (req->getFlags() & AUTO_COMPLETE) + req->finishRequest(true); + if (req->getFlags() & FLAG_AUTO_COMPLETE) { - llverify(mRequestHash.erase(req)) + mRequestHash.erase(req); req->deleteRequest(); // check(); } @@ -419,12 +435,18 @@ int LLQueuedThread::processNextRequest() lockData(); req->setStatus(STATUS_QUEUED); mRequestQueue.insert(req); + U32 priority = req->getPriority(); unlockData(); + if (priority < PRIORITY_NORMAL) + { + ms_sleep(1); // sleep the thread a little + } } } - int res; - if (getPending(true) == 0) + S32 res; + S32 pending = getPending(); + if (pending == 0) { if (isQuitting()) { @@ -437,7 +459,7 @@ int LLQueuedThread::processNextRequest() } else { - res = 1; + res = pending; } return res; } @@ -445,13 +467,14 @@ int LLQueuedThread::processNextRequest() bool LLQueuedThread::runCondition() { // mRunCondition must be locked here - return (mRequestQueue.empty() && mIdleThread) ? FALSE : TRUE; + if (mRequestQueue.empty() && mIdleThread) + return false; + else + return true; } void LLQueuedThread::run() { - llinfos << "QUEUED THREAD STARTING" << llendl; - while (1) { // this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state. @@ -474,6 +497,8 @@ void LLQueuedThread::run() { break; } + + //LLThread::yield(); // thread should yield after each request } llinfos << "QUEUED THREAD " << mName << " EXITING." << llendl; @@ -491,20 +516,18 @@ LLQueuedThread::QueuedRequest::QueuedRequest(LLQueuedThread::handle_t handle, U3 LLQueuedThread::QueuedRequest::~QueuedRequest() { - if (mStatus != STATUS_DELETE) - { - llerrs << "Attemt to directly delete a LLQueuedThread::QueuedRequest; use deleteRequest()" << llendl; - } + llassert_always(mStatus == STATUS_DELETE); } //virtual -void LLQueuedThread::QueuedRequest::finishRequest() +void LLQueuedThread::QueuedRequest::finishRequest(bool completed) { } //virtual void LLQueuedThread::QueuedRequest::deleteRequest() { + llassert_always(mStatus != STATUS_INPROGRESS); setStatus(STATUS_DELETE); delete this; } diff --git a/linden/indra/llcommon/llqueuedthread.h b/linden/indra/llcommon/llqueuedthread.h index cc21b3b..7231285 100644 --- a/linden/indra/llcommon/llqueuedthread.h +++ b/linden/indra/llcommon/llqueuedthread.h @@ -52,7 +52,8 @@ public: PRIORITY_HIGH = 0x30000000, PRIORITY_NORMAL = 0x20000000, PRIORITY_LOW = 0x10000000, - PRIORITY_LOWBITS = 0x0FFFFFFF + PRIORITY_LOWBITS = 0x0FFFFFFF, + PRIORITY_HIGHBITS = 0x70000000 }; enum status_t { STATUS_EXPIRED = -1, @@ -60,13 +61,13 @@ public: STATUS_QUEUED = 1, STATUS_INPROGRESS = 2, STATUS_COMPLETE = 3, - STATUS_ABORT = 4, - STATUS_ABORTED = 5, - STATUS_DELETE = 6 + STATUS_ABORTED = 4, + STATUS_DELETE = 5 }; enum flags_t { - AUTO_COMPLETE = 1, - AUTO_DELETE = 2 // child-class dependent + FLAG_AUTO_COMPLETE = 1, + FLAG_AUTO_DELETE = 2, // child-class dependent + FLAG_ABORT = 4 }; typedef U32 handle_t; @@ -79,7 +80,7 @@ public: friend class LLQueuedThread; protected: - ~QueuedRequest(); // use deleteRequest() + virtual ~QueuedRequest(); // use deleteRequest() public: QueuedRequest(handle_t handle, U32 priority, U32 flags = 0); @@ -111,26 +112,14 @@ public: mStatus = newstatus; return oldstatus; } - status_t abortRequest(U32 flags) + void setFlags(U32 flags) { // NOTE: flags are |'d - if (mStatus == STATUS_QUEUED) - { - setStatus(STATUS_ABORT); - } mFlags |= flags; - status_t status = mStatus; - return status; - } - status_t setFlags(U32 flags) - { - // NOTE: flags are |'d - mFlags |= flags; - status_t status = mStatus; - return status; } - virtual void finishRequest(); // Always called when after has been processed + virtual bool processRequest() = 0; // Return true when request has completed + virtual void finishRequest(bool completed); // Always called from thread after request has completed or aborted virtual void deleteRequest(); // Only method to delete a request void setPriority(U32 pri) @@ -160,9 +149,10 @@ public: static handle_t nullHandle() { return handle_t(0); } public: - LLQueuedThread(const std::string& name, bool threaded = TRUE, bool runalways = TRUE); + LLQueuedThread(const std::string& name, bool threaded = true); virtual ~LLQueuedThread(); - + virtual void shutdown(); + private: // No copy constructor or copy assignment LLQueuedThread(const LLQueuedThread&); @@ -174,26 +164,25 @@ private: protected: handle_t generateHandle(); bool addRequest(QueuedRequest* req); - int processNextRequest(void); + S32 processNextRequest(void); + void incQueue(); - virtual bool processRequest(QueuedRequest* req) = 0; - public: bool waitForResult(handle_t handle, bool auto_complete = true); - void update(U32 ms_elapsed); - void updateQueue(S32 inc); + virtual S32 update(U32 max_time_ms); + S32 updateQueue(U32 max_time_ms); + void waitOnPending(); void printQueueStats(); - S32 getPending(bool child_thread = false); + S32 getPending(); bool getThreaded() { return mThreaded ? true : false; } - bool getRunAlways() { return mRunAlways ? true : false; } // Request accessors status_t getRequestStatus(handle_t handle); - status_t abortRequest(handle_t handle, U32 flags = 0); - status_t setFlags(handle_t handle, U32 flags); + void abortRequest(handle_t handle, bool autocomplete); + void setFlags(handle_t handle, U32 flags); void setPriority(handle_t handle, U32 priority); bool completeRequest(handle_t handle); // This is public for support classes like LLWorkerThread, @@ -205,7 +194,6 @@ public: protected: BOOL mThreaded; // if false, run on main thread and do updates during update() - BOOL mRunAlways; // if false, only wake the threads when updateClass() is called LLAtomic32 mIdleThread; // request queue is empty (or we are quitting) and the thread is idle typedef std::set request_queue_t; diff --git a/linden/indra/llcommon/llsd.cpp b/linden/indra/llcommon/llsd.cpp index 7a0ff9d..342e356 100644 --- a/linden/indra/llcommon/llsd.cpp +++ b/linden/indra/llcommon/llsd.cpp @@ -27,8 +27,12 @@ #include "llsd.h" +#include #include + +#include "llerror.h" #include "../llmath/llmath.h" +#include "llformat.h" namespace { class ImplMap; @@ -251,7 +255,7 @@ namespace { public: ImplUUID(const LLSD::UUID& v) : Base(v) { } - virtual LLSD::String asString() const{ return mValue.getString(); } + virtual LLSD::String asString() const{ return mValue.asString(); } virtual LLSD::UUID asUUID() const { return mValue; } }; diff --git a/linden/indra/llcommon/llsdserialize.cpp b/linden/indra/llcommon/llsdserialize.cpp index 4c00c98..653fc66 100644 --- a/linden/indra/llcommon/llsdserialize.cpp +++ b/linden/indra/llcommon/llsdserialize.cpp @@ -804,7 +804,7 @@ S32 LLSDBinaryParser::parse(std::istream& istr, LLSD& data) const // the size, and read it. // *FIX: Should we set a maximum size? U32 size_nbo = 0; - istr.read((char*)&size_nbo, sizeof(U32)); + istr.read((char*)&size_nbo, sizeof(U32)); /*Flawfinder: ignore*/ S32 size = (S32)ntohl(size_nbo); std::vector value; if(size) @@ -944,7 +944,7 @@ void LLSDFormatter::realFormat(const std::string& format) void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const { char buffer[MAX_STRING]; /* Flawfinder: ignore */ - snprintf(buffer, MAX_STRING, mRealFormat.c_str(), real); + snprintf(buffer, MAX_STRING, mRealFormat.c_str(), real); /* Flawfinder: ignore */ ostr << buffer; } diff --git a/linden/indra/llcommon/llsdserialize_xml.cpp b/linden/indra/llcommon/llsdserialize_xml.cpp index 892f454..bb36fa7 100644 --- a/linden/indra/llcommon/llsdserialize_xml.cpp +++ b/linden/indra/llcommon/llsdserialize_xml.cpp @@ -190,6 +190,7 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, U32 opti else { // *FIX: memory inefficient. + // *TODO: convert to use LLBase64 ostr << pre << ""; int b64_buffer_length = apr_base64_encode_len(buffer.size()); char* b64_buffer = new char[b64_buffer_length]; diff --git a/linden/indra/llcommon/llsecondlifeurls.cpp b/linden/indra/llcommon/llsecondlifeurls.cpp index 6050d7f..4372373 100644 --- a/linden/indra/llcommon/llsecondlifeurls.cpp +++ b/linden/indra/llcommon/llsecondlifeurls.cpp @@ -76,7 +76,5 @@ const char LSL_DOC_URL[] = const char SL_KB_URL[] = "http://secondlife.com/knowledgebase/"; -const char ACCOUNT_TRANSACTIONS_URL[] = - "https://secondlife.com/account/transactions.php"; - const char RELEASE_NOTES[] = "releasenotes.txt"; + diff --git a/linden/indra/llcommon/llsecondlifeurls.h b/linden/indra/llcommon/llsecondlifeurls.h index f338bc3..1f7d359 100644 --- a/linden/indra/llcommon/llsecondlifeurls.h +++ b/linden/indra/llcommon/llsecondlifeurls.h @@ -50,18 +50,9 @@ extern const char UPGRADE_TO_PREMIUM_URL[]; // How to get DirectX 9 extern const char DIRECTX_9_URL[]; -// On AMD with bad AGP controller -extern const char AMD_AGP_URL[]; - // Out of date VIA chipset extern const char VIA_URL[]; -// Out of date intel chipset driver -extern const char INTEL_CHIPSET_URL[]; - -// Out of date SiS chipset driver -extern const char SIS_CHIPSET_URL[]; - // Linden Blogs page extern const char BLOGS_URL[]; @@ -74,9 +65,6 @@ extern const char LSL_DOC_URL[]; // SL KnowledgeBase page extern const char SL_KB_URL[]; -// Account transactions -extern const char ACCOUNT_TRANSACTIONS_URL[]; - // Local Url Release Notes extern const char RELEASE_NOTES[]; diff --git a/linden/indra/llcommon/llstreamtools.cpp b/linden/indra/llcommon/llstreamtools.cpp index b68edd3..2c78e05 100644 --- a/linden/indra/llcommon/llstreamtools.cpp +++ b/linden/indra/llcommon/llstreamtools.cpp @@ -553,7 +553,7 @@ std::istream& fullread(std::istream& str, char *buf, std::streamsize requested) std::istream& operator>>(std::istream& str, const char *tocheck) { - char c; + char c = '\0'; const char *p; p = tocheck; while (*p && !str.bad()) diff --git a/linden/indra/llcommon/llstrider.h b/linden/indra/llcommon/llstrider.h index 07b8c48..efc2ae4 100644 --- a/linden/indra/llcommon/llstrider.h +++ b/linden/indra/llcommon/llstrider.h @@ -51,6 +51,7 @@ public: Object* operator->() { return mObjectp; } Object& operator *() { return *mObjectp; } 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)); } }; diff --git a/linden/indra/llcommon/llstring.cpp b/linden/indra/llcommon/llstring.cpp index 5cb42cc..c9f684f 100644 --- a/linden/indra/llcommon/llstring.cpp +++ b/linden/indra/llcommon/llstring.cpp @@ -195,6 +195,7 @@ llutf16string utf8str_to_utf16str ( const LLString& utf8str ) LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len) { LLWString wout; + if((len <= 0) || utf16str.empty()) return wout; S32 i = 0; // craziness to make gcc happy (llutf16string.c_str() is tweaked on linux): diff --git a/linden/indra/llcommon/llstring.h b/linden/indra/llcommon/llstring.h index a83b7cf..0485a1e 100644 --- a/linden/indra/llcommon/llstring.h +++ b/linden/indra/llcommon/llstring.h @@ -30,6 +30,7 @@ #include "stdtypes.h" #include "llerror.h" +#include "llfile.h" #include #include #include @@ -101,7 +102,7 @@ struct char_traits static char_type* copy(char_type* __s1, const char_type* __s2, size_t __n) - { return static_cast(memcpy(__s1, __s2, __n * sizeof(char_type))); } + { return static_cast(memcpy(__s1, __s2, __n * sizeof(char_type))); } /* Flawfinder: ignore */ static char_type* assign(char_type* __s, size_t __n, char_type __a) @@ -922,7 +923,7 @@ void LLStringBase::replaceNonstandardASCII( std::basic_string& string, T r //static template -void LLStringBase::replaceTabsWithSpaces( std::basic_string& string, size_type spaces_per_tab ) +void LLStringBase::replaceTabsWithSpaces( std::basic_string& str, size_type spaces_per_tab ) { llassert( spaces_per_tab >= 0 ); @@ -931,19 +932,19 @@ void LLStringBase::replaceTabsWithSpaces( std::basic_string& string, size_ LLStringBase out_str; // Replace tabs with spaces - for (size_type i = 0; i < string.length(); i++) + for (size_type i = 0; i < str.length(); i++) { - if (string[i] == TAB) + if (str[i] == TAB) { for (size_type j = 0; j < spaces_per_tab; j++) out_str += SPACE; } else { - out_str += string[i]; + out_str += str[i]; } } - string = out_str; + str = out_str; } //static diff --git a/linden/indra/llcommon/llstringtable.h b/linden/indra/llcommon/llstringtable.h index d53c0e1..ddfef88 100644 --- a/linden/indra/llcommon/llstringtable.h +++ b/linden/indra/llcommon/llstringtable.h @@ -29,14 +29,15 @@ #ifndef LL_STRING_TABLE_H #define LL_STRING_TABLE_H +#include "lldefs.h" +#include "llformat.h" #include "llstl.h" #include #include #if LL_WINDOWS -# if (_MSC_VER >= 1300) +# if (_MSC_VER >= 1300 && _MSC_VER < 1400) # define STRING_TABLE_HASH_MAP 1 -# pragma warning(disable : 4996) # endif #else //# define STRING_TABLE_HASH_MAP 1 diff --git a/linden/indra/llcommon/llsys.cpp b/linden/indra/llcommon/llsys.cpp index 148e4de..906bc65 100644 --- a/linden/indra/llcommon/llsys.cpp +++ b/linden/indra/llcommon/llsys.cpp @@ -132,23 +132,23 @@ LLOSInfo::LLOSInfo() : char tmp[MAX_STRING]; /* Flawfinder: ignore */ if(osvi.dwMajorVersion <= 4) { - snprintf( + snprintf( /* Flawfinder: ignore */ tmp, sizeof(tmp), "version %d.%d %s (Build %d)", osvi.dwMajorVersion, osvi.dwMinorVersion, csdversion.c_str(), - (osvi.dwBuildNumber & 0xffff)); /* Flawfinder: ignore */ + (osvi.dwBuildNumber & 0xffff)); } else { - snprintf( + snprintf( /* Flawfinder: ignore */ tmp, sizeof(tmp), "%s (Build %d)", csdversion.c_str(), - (osvi.dwBuildNumber & 0xffff)); /*Flawfinder: ignore*/ + (osvi.dwBuildNumber & 0xffff)); } mOSString += tmp; } @@ -250,7 +250,7 @@ U32 LLOSInfo::getProcessVirtualSizeKB() #if LL_WINDOWS #endif #if LL_LINUX - FILE *status_filep = LLFile::fopen("/proc/self/status", "r"); + FILE* status_filep = LLFile::fopen("/proc/self/status", "r"); /* Flawfinder: ignore */ S32 numRead = 0; char buff[STATUS_SIZE]; /* Flawfinder: ignore */ bzero(buff, STATUS_SIZE); @@ -276,7 +276,7 @@ U32 LLOSInfo::getProcessResidentSizeKB() #if LL_WINDOWS #endif #if LL_LINUX - FILE *status_filep = LLFile::fopen("/proc/self/status", "r"); + FILE* status_filep = LLFile::fopen("/proc/self/status", "r"); /* Flawfinder: ignore */ if (status_filep != NULL) { S32 numRead = 0; diff --git a/linden/indra/llcommon/llthread.cpp b/linden/indra/llcommon/llthread.cpp index 290879d..d6b52f7 100644 --- a/linden/indra/llcommon/llthread.cpp +++ b/linden/indra/llcommon/llthread.cpp @@ -100,6 +100,11 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : LLThread::~LLThread() { + shutdown(); +} + +void LLThread::shutdown() +{ // Warning! If you somehow call the thread destructor from itself, // the thread will die in an unclean fashion! if (mAPRThreadp) @@ -205,18 +210,6 @@ void LLThread::checkPause() //============================================================================ -bool LLThread::isQuitting() const -{ - return (QUITTING == mStatus); -} - - -bool LLThread::isStopped() const -{ - return (STOPPED == mStatus); -} - - void LLThread::setQuitting() { mRunCondition->lock(); @@ -347,3 +340,49 @@ void LLCondition::broadcast() apr_thread_cond_broadcast(mAPRCondp); } +//============================================================================ + +//---------------------------------------------------------------------------- + +//static +LLMutex* LLThreadSafeRefCount::sMutex = 0; + +//static +void LLThreadSafeRefCount::initClass() +{ + if (!sMutex) + { + sMutex = new LLMutex(0); + } +} + +//static +void LLThreadSafeRefCount::cleanupClass() +{ + delete sMutex; + sMutex = NULL; +} + + +//---------------------------------------------------------------------------- + +LLThreadSafeRefCount::LLThreadSafeRefCount() : + mRef(0) +{ +} + +LLThreadSafeRefCount::~LLThreadSafeRefCount() +{ + if (mRef != 0) + { + llerrs << "deleting non-zero reference" << llendl; + } +} + +//============================================================================ + +LLResponder::~LLResponder() +{ +} + +//============================================================================ diff --git a/linden/indra/llcommon/llthread.h b/linden/indra/llcommon/llthread.h index 2a13d72..cdf1d33 100644 --- a/linden/indra/llcommon/llthread.h +++ b/linden/indra/llcommon/llthread.h @@ -30,6 +30,7 @@ #include "llapr.h" #include "llapp.h" +#include "llmemory.h" #include "apr-1/apr_thread_cond.h" @@ -49,19 +50,20 @@ public: LLThread(const std::string& name, apr_pool_t *poolp = NULL); virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state. - + virtual void shutdown(); // stops the thread + static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure. - bool isQuitting() const; - bool isStopped() const; + bool isQuitting() const { return (QUITTING == mStatus); } + bool isStopped() const { return (STOPPED == mStatus); } // PAUSE / RESUME functionality. See source code for important usage notes. public: // Called from MAIN THREAD. void pause(); void unpause(); - bool isPaused() { return mPaused ? true : false; } + bool isPaused() { return isStopped() || mPaused == TRUE; } // Cause the thread to wake up and check its condition void wake(); @@ -79,7 +81,7 @@ public: private: BOOL mPaused; - + // static function passed to APR thread creation routine static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap); @@ -180,4 +182,67 @@ void LLThread::unlockData() //============================================================================ +// see llmemory.h for LLPointer<> definition + +class LLThreadSafeRefCount +{ +public: + static void initClass(); // creates sMutex + static void cleanupClass(); // destroys sMutex + +private: + static LLMutex* sMutex; + +private: + LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented + LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented + +protected: + virtual ~LLThreadSafeRefCount(); // use unref() + +public: + LLThreadSafeRefCount(); + + void ref() + { + if (sMutex) sMutex->lock(); + mRef++; + if (sMutex) sMutex->unlock(); + } + + S32 unref() + { + llassert(mRef >= 1); + if (sMutex) sMutex->lock(); + S32 res = --mRef; + if (sMutex) sMutex->unlock(); + if (0 == res) + { + delete this; + res = 0; + } + return res; + } + S32 getNumRefs() const + { + return mRef; + } + +private: + S32 mRef; +}; + +//============================================================================ + +// Simple responder for self destructing callbacks +// Pure virtual class +class LLResponder : public LLThreadSafeRefCount +{ +public: + virtual ~LLResponder(); + virtual void completed(bool success) = 0; +}; + +//============================================================================ + #endif // LL_LLTHREAD_H diff --git a/linden/indra/llcommon/lluri.cpp b/linden/indra/llcommon/lluri.cpp index e697ec1..bc3540e 100644 --- a/linden/indra/llcommon/lluri.cpp +++ b/linden/indra/llcommon/lluri.cpp @@ -32,273 +32,86 @@ #include "llapp.h" #include "lluri.h" #include "llsd.h" - +#include + #include "../llmath/lluuid.h" -// uric = reserved | unreserved | escaped -// reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | "," -// unreserved = alphanum | mark -// mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" -// escaped = "%" hex hex -static const char* ESCAPED_CHARACTERS[256] = + +// static +std::string LLURI::escape(const std::string& str, const std::string & allowed) { - "%00", // 0 - "%01", // 1 - "%02", // 2 - "%03", // 3 - "%04", // 4 - "%05", // 5 - "%06", // 6 - "%07", // 7 - "%08", // 8 - "%09", // 9 - "%0a", // 10 - "%0b", // 11 - "%0c", // 12 - "%0d", // 13 - "%0e", // 14 - "%0f", // 15 - "%10", // 16 - "%11", // 17 - "%12", // 18 - "%13", // 19 - "%14", // 20 - "%15", // 21 - "%16", // 22 - "%17", // 23 - "%18", // 24 - "%19", // 25 - "%1a", // 26 - "%1b", // 27 - "%1c", // 28 - "%1d", // 29 - "%1e", // 30 - "%1f", // 31 - "%20", // 32 - "!", // 33 - "%22", // 34 - "%23", // 35 - "$", // 36 - "%25", // 37 - "&", // 38 - "'", // 39 - "(", // 40 - ")", // 41 - "*", // 42 - "+", // 43 - ",", // 44 - "-", // 45 - ".", // 46 - "/", // 47 - "0", // 48 - "1", // 49 - "2", // 50 - "3", // 51 - "4", // 52 - "5", // 53 - "6", // 54 - "7", // 55 - "8", // 56 - "9", // 57 - ":", // 58 - ";", // 59 - "%3c", // 60 - "=", // 61 - "%3e", // 62 - "?", // 63 - "@", // 64 - "A", // 65 - "B", // 66 - "C", // 67 - "D", // 68 - "E", // 69 - "F", // 70 - "G", // 71 - "H", // 72 - "I", // 73 - "J", // 74 - "K", // 75 - "L", // 76 - "M", // 77 - "N", // 78 - "O", // 79 - "P", // 80 - "Q", // 81 - "R", // 82 - "S", // 83 - "T", // 84 - "U", // 85 - "V", // 86 - "W", // 87 - "X", // 88 - "Y", // 89 - "Z", // 90 - "%5b", // 91 - "%5c", // 92 - "%5d", // 93 - "%5e", // 94 - "_", // 95 - "%60", // 96 - "a", // 97 - "b", // 98 - "c", // 99 - "d", // 100 - "e", // 101 - "f", // 102 - "g", // 103 - "h", // 104 - "i", // 105 - "j", // 106 - "k", // 107 - "l", // 108 - "m", // 109 - "n", // 110 - "o", // 111 - "p", // 112 - "q", // 113 - "r", // 114 - "s", // 115 - "t", // 116 - "u", // 117 - "v", // 118 - "w", // 119 - "x", // 120 - "y", // 121 - "z", // 122 - "%7b", // 123 - "%7c", // 124 - "%7d", // 125 - "~", // 126 - "%7f", // 127 - "%80", // 128 - "%81", // 129 - "%82", // 130 - "%83", // 131 - "%84", // 132 - "%85", // 133 - "%86", // 134 - "%87", // 135 - "%88", // 136 - "%89", // 137 - "%8a", // 138 - "%8b", // 139 - "%8c", // 140 - "%8d", // 141 - "%8e", // 142 - "%8f", // 143 - "%90", // 144 - "%91", // 145 - "%92", // 146 - "%93", // 147 - "%94", // 148 - "%95", // 149 - "%96", // 150 - "%97", // 151 - "%98", // 152 - "%99", // 153 - "%9a", // 154 - "%9b", // 155 - "%9c", // 156 - "%9d", // 157 - "%9e", // 158 - "%9f", // 159 - "%a0", // 160 - "%a1", // 161 - "%a2", // 162 - "%a3", // 163 - "%a4", // 164 - "%a5", // 165 - "%a6", // 166 - "%a7", // 167 - "%a8", // 168 - "%a9", // 169 - "%aa", // 170 - "%ab", // 171 - "%ac", // 172 - "%ad", // 173 - "%ae", // 174 - "%af", // 175 - "%b0", // 176 - "%b1", // 177 - "%b2", // 178 - "%b3", // 179 - "%b4", // 180 - "%b5", // 181 - "%b6", // 182 - "%b7", // 183 - "%b8", // 184 - "%b9", // 185 - "%ba", // 186 - "%bb", // 187 - "%bc", // 188 - "%bd", // 189 - "%be", // 190 - "%bf", // 191 - "%c0", // 192 - "%c1", // 193 - "%c2", // 194 - "%c3", // 195 - "%c4", // 196 - "%c5", // 197 - "%c6", // 198 - "%c7", // 199 - "%c8", // 200 - "%c9", // 201 - "%ca", // 202 - "%cb", // 203 - "%cc", // 204 - "%cd", // 205 - "%ce", // 206 - "%cf", // 207 - "%d0", // 208 - "%d1", // 209 - "%d2", // 210 - "%d3", // 211 - "%d4", // 212 - "%d5", // 213 - "%d6", // 214 - "%d7", // 215 - "%d8", // 216 - "%d9", // 217 - "%da", // 218 - "%db", // 219 - "%dc", // 220 - "%dd", // 221 - "%de", // 222 - "%df", // 223 - "%e0", // 224 - "%e1", // 225 - "%e2", // 226 - "%e3", // 227 - "%e4", // 228 - "%e5", // 229 - "%e6", // 230 - "%e7", // 231 - "%e8", // 232 - "%e9", // 233 - "%ea", // 234 - "%eb", // 235 - "%ec", // 236 - "%ed", // 237 - "%ee", // 238 - "%ef", // 239 - "%f0", // 240 - "%f1", // 241 - "%f2", // 242 - "%f3", // 243 - "%f4", // 244 - "%f5", // 245 - "%f6", // 246 - "%f7", // 247 - "%f8", // 248 - "%f9", // 249 - "%fa", // 250 - "%fb", // 251 - "%fc", // 252 - "%fd", // 253 - "%fe", // 254 - "%ff" // 255 -}; + std::ostringstream ostr; + + std::string::const_iterator it = str.begin(); + std::string::const_iterator end = str.end(); + for(; it != end; ++it) + { + std::string::value_type c = *it; + if(allowed.find(c) == std::string::npos) + { + ostr << "%" + << std::uppercase << std::hex << std::setw(2) << std::setfill('0') + << static_cast(c); + } + else + { + ostr << c; + } + } + return ostr.str(); +} + +// static +std::string LLURI::unescape(const std::string& str) +{ + std::ostringstream ostr; + std::string::const_iterator it = str.begin(); + std::string::const_iterator end = str.end(); + for(; it != end; ++it) + { + if((*it) == '%') + { + ++it; + if(it == end) break; + U8 c = hex_as_nybble(*it++); + c = c << 4; + if (it == end) break; + c |= hex_as_nybble(*it); + ostr.put((char)c); + } + else + { + ostr.put(*it); + } + } + return ostr.str(); +} + +namespace +{ + const std::string unreserved() + { + static const std::string s = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789" + "-._~"; + return s; + } + const std::string sub_delims() + { + static const std::string s = "!$&'()*+,;="; + return s; + } + + std::string escapeHostAndPort(const std::string& s) + { return LLURI::escape(s, unreserved() + sub_delims() +":"); } + std::string escapePathComponent(const std::string& s) + { return LLURI::escape(s, unreserved() + sub_delims() + ":@"); } + std::string escapeQueryVariable(const std::string& s) + { return LLURI::escape(s, unreserved() + ":@!$'()*+,"); } // sub_delims - "&;=" + ":@" + std::string escapeQueryValue(const std::string& s) + { return LLURI::escape(s, unreserved() + ":@!$'()*+,="); } // sub_delims - "&;" + ":@" +} LLURI::LLURI() { @@ -371,24 +184,23 @@ LLURI::~LLURI() { } - -LLURI LLURI::buildHTTP(const std::string& host_port, +// static +LLURI LLURI::buildHTTP(const std::string& prefix, const LLSD& path) { LLURI result; // TODO: deal with '/' '?' '#' in host_port - S32 index = host_port.find("://"); - if (index != host_port.npos) + if (prefix.find("://") != prefix.npos) { - // The scheme is part of the host_port - result.mScheme = ""; - result.mEscapedAuthority = escape(host_port); + // it is a prefix + result = LLURI(prefix); } else { - result.mScheme = "HTTP"; - result.mEscapedAuthority = "//" + escape(host_port); + // it is just a host and optional port + result.mScheme = "http"; + result.mEscapedAuthority = escapeHostAndPort(prefix); } if (path.isArray()) @@ -399,20 +211,20 @@ LLURI LLURI::buildHTTP(const std::string& host_port, ++it) { lldebugs << "PATH: inserting " << it->asString() << llendl; - result.mEscapedPath += "/" + escape(it->asString()); + result.mEscapedPath += "/" + escapePathComponent(it->asString()); } } - result.mEscapedOpaque = result.mEscapedAuthority + + result.mEscapedOpaque = "//" + result.mEscapedAuthority + result.mEscapedPath; return result; } // static -LLURI LLURI::buildHTTP(const std::string& host_port, +LLURI LLURI::buildHTTP(const std::string& prefix, const LLSD& path, const LLSD& query) { - LLURI result = buildHTTP(host_port, path); + LLURI result = buildHTTP(prefix, path); // break out and escape each query component if (query.isMap()) { @@ -420,8 +232,8 @@ LLURI LLURI::buildHTTP(const std::string& host_port, it != query.endMap(); it++) { - result.mEscapedQuery += escape(it->first) + - (it->second.isUndefined() ? "" : "=" + it->second.asString()) + + result.mEscapedQuery += escapeQueryVariable(it->first) + + (it->second.isUndefined() ? "" : "=" + escapeQueryValue(it->second.asString())) + "&"; } if (query.size() > 0) @@ -433,8 +245,61 @@ LLURI LLURI::buildHTTP(const std::string& host_port, } // static +LLURI LLURI::buildHTTP(const std::string& host, + const U32& port, + const LLSD& path) +{ + return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path); +} + +// static +LLURI LLURI::buildHTTP(const std::string& host, + const U32& port, + const LLSD& path, + const LLSD& query) +{ + return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path, query); +} + + +namespace { + LLURI buildBackboneURL(LLApp* app, + const std::string& p1 = "", + const std::string& p2 = "", + const std::string& p3 = "") + { + std::string host = "localhost:12040"; + + if (app) + { + host = app->getOption("backbone-host-port").asString(); + } + + LLSD path = LLSD::emptyArray(); + if (!p1.empty()) path.append(p1); + if (!p2.empty()) path.append(p2); + if (!p3.empty()) path.append(p3); + + return LLURI::buildHTTP(host, path); + } +} + + +// static LLURI LLURI::buildAgentPresenceURI(const LLUUID& agent_id, LLApp* app) { + return buildBackboneURL(app, "agent", agent_id.asString(), "presence"); +} + +// static +LLURI LLURI::buildBulkAgentPresenceURI(LLApp* app) +{ + return buildBackboneURL(app, "agent", "presence"); +} + +// static +LLURI LLURI::buildBulkAgentNamesURI(LLApp* app) +{ std::string host = "localhost:12040"; if (app) @@ -444,14 +309,19 @@ LLURI LLURI::buildAgentPresenceURI(const LLUUID& agent_id, LLApp* app) LLSD path = LLSD::emptyArray(); path.append("agent"); - path.append(agent_id); - path.append("presence"); + path.append("names"); return buildHTTP(host, path); } // static -LLURI LLURI::buildBulkAgentPresenceURI(LLApp* app) +LLURI LLURI::buildAgentSessionURI(const LLUUID& agent_id, LLApp* app) +{ + return buildBackboneURL(app, "agent", agent_id.asString(), "session"); +} + +// static +LLURI LLURI::buildInventoryHostURI(const LLUUID& agent_id, LLApp* app) { std::string host = "localhost:12040"; @@ -462,13 +332,15 @@ LLURI LLURI::buildBulkAgentPresenceURI(LLApp* app) LLSD path = LLSD::emptyArray(); path.append("agent"); - path.append("presence"); + path.append(agent_id); + path.append("inventory"); + path.append("host"); return buildHTTP(host, path); } // static -LLURI LLURI::buildAgentSessionURI(const LLUUID& agent_id, LLApp* app) +LLURI LLURI::buildAgentNameURI(const LLUUID& agent_id, LLApp* app) { std::string host = "localhost:12040"; @@ -480,7 +352,7 @@ LLURI LLURI::buildAgentSessionURI(const LLUUID& agent_id, LLApp* app) LLSD path = LLSD::emptyArray(); path.append("agent"); path.append(agent_id); - path.append("session"); + path.append("name"); return buildHTTP(host, path); } @@ -636,43 +508,3 @@ LLSD LLURI::queryMap(std::string escaped_query_string) return result; } -// static -std::string LLURI::escape(const std::string& str) -{ - std::ostringstream ostr; - std::string::const_iterator it = str.begin(); - std::string::const_iterator end = str.end(); - S32 c; - for(; it != end; ++it) - { - c = (S32)(*it); - ostr << ESCAPED_CHARACTERS[c]; - } - return ostr.str(); -} - -// static -std::string LLURI::unescape(const std::string& str) -{ - std::ostringstream ostr; - std::string::const_iterator it = str.begin(); - std::string::const_iterator end = str.end(); - for(; it != end; ++it) - { - if((*it) == '%') - { - ++it; - if(it == end) break; - U8 c = hex_as_nybble(*it++); - c = c << 4; - if (it == end) break; - c |= hex_as_nybble(*it); - ostr.put((char)c); - } - else - { - ostr.put(*it); - } - } - return ostr.str(); -} diff --git a/linden/indra/llcommon/lluri.h b/linden/indra/llcommon/lluri.h index f69472f..60b3d48 100644 --- a/linden/indra/llcommon/lluri.h +++ b/linden/indra/llcommon/lluri.h @@ -45,54 +45,70 @@ class LLApp; class LLURI { public: - LLURI(); - LLURI(const std::string& escaped_str); - // construct from escaped string, as would be transmitted on the net + LLURI(); + LLURI(const std::string& escaped_str); + // construct from escaped string, as would be transmitted on the net - ~LLURI(); + ~LLURI(); - static LLURI buildHTTP(const std::string& host_port, - const LLSD& path); - static LLURI buildHTTP(const std::string& host_port, - const LLSD& path, - const LLSD& query); - - std::string asString() const; - // the whole URI, escaped as needed + static LLURI buildHTTP(const std::string& prefix, + const LLSD& path); + static LLURI buildHTTP(const std::string& prefix, + const LLSD& path, + const LLSD& query); + // prefix is either a full URL prefix of the form "http://example.com:8080", + // or it can be simply a host and optional port like "example.com" or + // "example.com:8080", in these cases, the "http://" will be added - // Parts of a URI - // These functions return parts of the decoded URI. The returned - // strings are un-escaped as needed - - // for all schemes - std::string scheme() const; // ex.: "http", note lack of colon - std::string opaque() const; // everything after the colon + static LLURI buildHTTP(const std::string& host, + const U32& port, + const LLSD& path); + static LLURI buildHTTP(const std::string& host, + const U32& port, + const LLSD& path, + const LLSD& query); + + + std::string asString() const; + // the whole URI, escaped as needed + + // Parts of a URI + // These functions return parts of the decoded URI. The returned + // strings are un-escaped as needed + + // for all schemes + std::string scheme() const; // ex.: "http", note lack of colon + std::string opaque() const; // everything after the colon + + // for schemes that follow path like syntax (http, https, ftp) + std::string authority() const; // ex.: "host.com:80" + std::string hostName() const; // ex.: "host.com" + U16 hostPort() const; // ex.: 80, will include implicit port + std::string path() const; // ex.: "/abc/def", includes leading slash + // LLSD pathArray() const; // above decoded into an array of strings + std::string query() const; // ex.: "x=34", section after "?" + LLSD queryMap() const; // above decoded into a map + static LLSD queryMap(std::string escaped_query_string); - // for schemes that follow path like syntax (http, https, ftp) - std::string authority() const; // ex.: "bob@host.com:80" - std::string hostName() const; // ex.: "host.com" - U16 hostPort() const; // ex.: 80, will include implicit port - std::string path() const; // ex.: "/abc/def", includes leading slash -// LLSD pathArray() const; // above decoded into an array of strings - std::string query() const; // ex.: "x=34", section after "?" - LLSD queryMap() const; // above decoded into a map - static LLSD queryMap(std::string escaped_query_string); - - // Escaping Utilities - static std::string escape(const std::string& str); - static std::string unescape(const std::string& str); + // Escaping Utilities + // Escape a string by urlencoding all the characters that aren't in the allowed string. + static std::string escape(const std::string& str, const std::string & allowed); + static std::string unescape(const std::string& str); // Functions for building specific URIs for web services static LLURI buildAgentPresenceURI(const LLUUID& agent_id, LLApp* app); static LLURI buildBulkAgentPresenceURI(LLApp* app); + static LLURI buildBulkAgentNamesURI(LLApp* app); static LLURI buildAgentSessionURI(const LLUUID& agent_id, LLApp* app); static LLURI buildAgentLoginInfoURI(const LLUUID& agent_id, const std::string& dataserver); + static LLURI buildInventoryHostURI(const LLUUID& agent_id, LLApp* app); + static LLURI buildAgentNameURI(const LLUUID& agent_id, LLApp* app); private: - std::string mScheme; - std::string mEscapedOpaque; - std::string mEscapedAuthority; - std::string mEscapedPath; - std::string mEscapedQuery; + std::string mScheme; + std::string mEscapedOpaque; + std::string mEscapedAuthority; + std::string mEscapedPath; + std::string mEscapedQuery; }; #endif // LL_LLURI_H diff --git a/linden/indra/llcommon/llversion.h b/linden/indra/llcommon/llversion.h index af21f72..a3e5152 100644 --- a/linden/indra/llcommon/llversion.h +++ b/linden/indra/llcommon/llversion.h @@ -32,9 +32,9 @@ // MUST ALSO change version number in secondlife setup.nsi const S32 LL_VERSION_MAJOR = 1; -const S32 LL_VERSION_MINOR = 13; -const S32 LL_VERSION_PATCH = 3; -const S32 LL_VERSION_BUILD = 2; +const S32 LL_VERSION_MINOR = 14; +const S32 LL_VERSION_PATCH = 0; +const S32 LL_VERSION_BUILD = 0; diff --git a/linden/indra/llcommon/llworkerthread.cpp b/linden/indra/llcommon/llworkerthread.cpp index 3190046..4f99393 100644 --- a/linden/indra/llcommon/llworkerthread.cpp +++ b/linden/indra/llcommon/llworkerthread.cpp @@ -33,98 +33,86 @@ #endif //============================================================================ - -/*static*/ LLWorkerThread* LLWorkerThread::sLocal = NULL; -/*static*/ std::set LLWorkerThread::sThreadList; - -//============================================================================ // Run on MAIN thread -//static -void LLWorkerThread::initClass(bool local_is_threaded, bool local_run_always) +LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded) : + LLQueuedThread(name, threaded), + mWorkerAPRPoolp(NULL) { - if (!sLocal) - { - sLocal = new LLWorkerThread(local_is_threaded, local_run_always); - } + apr_pool_create(&mWorkerAPRPoolp, NULL); + mDeleteMutex = new LLMutex(getAPRPool()); } -//static -void LLWorkerThread::cleanupClass() +LLWorkerThread::~LLWorkerThread() { - if (sLocal) + // Delete any workers in the delete queue (should be safe - had better be!) + if (!mDeleteList.empty()) { - while (sLocal->getPending()) - { - sLocal->update(0); - } - delete sLocal; - sLocal = NULL; - llassert(sThreadList.size() == 0); + llwarns << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() + << " entries in delete list." << llendl; } -} -//static -S32 LLWorkerThread::updateClass(U32 ms_elapsed) -{ - for (std::set::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++) - { - (*iter)->update(ms_elapsed); - } - return getAllPending(); + delete mDeleteMutex; + + // ~LLQueuedThread() will be called here } -//static -S32 LLWorkerThread::getAllPending() +// virtual +S32 LLWorkerThread::update(U32 max_time_ms) { - S32 res = 0; - for (std::set::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++) + S32 res = LLQueuedThread::update(max_time_ms); + // Delete scheduled workers + std::vector delete_list; + std::vector abort_list; + mDeleteMutex->lock(); + for (delete_list_t::iterator iter = mDeleteList.begin(); + iter != mDeleteList.end(); ) { - res += (*iter)->getPending(); + delete_list_t::iterator curiter = iter++; + LLWorkerClass* worker = *curiter; + if (worker->deleteOK()) + { + if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED)) + { + delete_list.push_back(worker); + mDeleteList.erase(curiter); + } + else if (!worker->getFlags(LLWorkerClass::WCF_ABORT_REQUESTED)) + { + abort_list.push_back(worker); + } + } } - return res; -} - -//static -void LLWorkerThread::pauseAll() -{ - for (std::set::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++) + mDeleteMutex->unlock(); + // abort and delete after releasing mutex + for (std::vector::iterator iter = abort_list.begin(); + iter != abort_list.end(); ++iter) { - (*iter)->pause(); + (*iter)->abortWork(false); } -} - -//static -void LLWorkerThread::waitOnAllPending() -{ - for (std::set::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++) + for (std::vector::iterator iter = delete_list.begin(); + iter != delete_list.end(); ++iter) { - (*iter)->waitOnPending(); + LLWorkerClass* worker = *iter; + if (worker->mRequestHandle) + { + // Finished but not completed + completeRequest(worker->mRequestHandle); + worker->mRequestHandle = LLWorkerThread::nullHandle(); + worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK); + } + delete *iter; } + return res; } //---------------------------------------------------------------------------- -LLWorkerThread::LLWorkerThread(bool threaded, bool runalways) : - LLQueuedThread("Worker", threaded, runalways) -{ - sThreadList.insert(this); -} - -LLWorkerThread::~LLWorkerThread() -{ - llverify(sThreadList.erase(this) == 1); - // ~LLQueuedThread() will be called here -} - -//---------------------------------------------------------------------------- - - -LLWorkerThread::handle_t LLWorkerThread::add(LLWorkerClass* workerclass, S32 param, U32 priority) +LLWorkerThread::handle_t LLWorkerThread::addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority) { handle_t handle = generateHandle(); - Request* req = new Request(handle, priority, workerclass, param); + WorkRequest* req = new WorkRequest(handle, priority, workerclass, param); bool res = addRequest(req); if (!res) @@ -137,63 +125,80 @@ LLWorkerThread::handle_t LLWorkerThread::add(LLWorkerClass* workerclass, S32 par return handle; } -//============================================================================ -// Runs on its OWN thread - -bool LLWorkerThread::processRequest(QueuedRequest* qreq) +void LLWorkerThread::deleteWorker(LLWorkerClass* workerclass) { - Request *req = (Request*)qreq; - - req->getWorkerClass()->setWorking(true); - - bool complete = req->getWorkerClass()->doWork(req->getParam()); - - req->getWorkerClass()->setWorking(false); - - LLThread::yield(); // worker thread should yield after each request - - return complete; + mDeleteMutex->lock(); + mDeleteList.push_back(workerclass); + mDeleteMutex->unlock(); } //============================================================================ +// Runs on its OWN thread -LLWorkerThread::Request::Request(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param) : +LLWorkerThread::WorkRequest::WorkRequest(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param) : LLQueuedThread::QueuedRequest(handle, priority), mWorkerClass(workerclass), mParam(param) { } -void LLWorkerThread::Request::deleteRequest() +LLWorkerThread::WorkRequest::~WorkRequest() +{ +} + +// virtual (required for access by LLWorkerThread) +void LLWorkerThread::WorkRequest::deleteRequest() { LLQueuedThread::QueuedRequest::deleteRequest(); } +// virtual +bool LLWorkerThread::WorkRequest::processRequest() +{ + LLWorkerClass* workerclass = getWorkerClass(); + workerclass->setWorking(true); + bool complete = workerclass->doWork(getParam()); + workerclass->setWorking(false); + return complete; +} + +// virtual +void LLWorkerThread::WorkRequest::finishRequest(bool completed) +{ + LLWorkerClass* workerclass = getWorkerClass(); + workerclass->finishWork(getParam(), completed); + U32 flags = LLWorkerClass::WCF_WORK_FINISHED | (completed ? 0 : LLWorkerClass::WCF_WORK_ABORTED); + workerclass->setFlags(flags); +} + //============================================================================ // LLWorkerClass:: operates in main thread LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& name) : mWorkerThread(workerthread), mWorkerClassName(name), - mWorkHandle(LLWorkerThread::nullHandle()), + mRequestHandle(LLWorkerThread::nullHandle()), + mMutex(workerthread->getWorkerAPRPool()), mWorkFlags(0) { if (!mWorkerThread) { - mWorkerThread = LLWorkerThread::sLocal; + llerrs << "LLWorkerClass() called with NULL workerthread: " << name << llendl; } } + LLWorkerClass::~LLWorkerClass() { - if (mWorkHandle != LLWorkerThread::nullHandle()) + llassert_always(!(mWorkFlags & WCF_WORKING)); + llassert_always(mWorkFlags & WCF_DELETE_REQUESTED); + if (mRequestHandle != LLWorkerThread::nullHandle()) { - LLWorkerThread::Request* workreq = (LLWorkerThread::Request*)mWorkerThread->getRequest(mWorkHandle); + LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); if (!workreq) { llerrs << "LLWorkerClass destroyed with stale work handle" << llendl; } - if (workreq->getStatus() != LLWorkerThread::STATUS_ABORT && - workreq->getStatus() != LLWorkerThread::STATUS_ABORTED && + if (workreq->getStatus() != LLWorkerThread::STATUS_ABORTED && workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE) { llerrs << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << llendl; @@ -203,21 +208,58 @@ LLWorkerClass::~LLWorkerClass() void LLWorkerClass::setWorkerThread(LLWorkerThread* workerthread) { - if (mWorkHandle != LLWorkerThread::nullHandle()) + mMutex.lock(); + if (mRequestHandle != LLWorkerThread::nullHandle()) { llerrs << "LLWorkerClass attempt to change WorkerThread with active worker!" << llendl; } mWorkerThread = workerthread; + mMutex.unlock(); +} + +//---------------------------------------------------------------------------- + +//virtual +void LLWorkerClass::finishWork(S32 param, bool success) +{ +} + +//virtual +bool LLWorkerClass::deleteOK() +{ + return true; // default always OK +} + +//---------------------------------------------------------------------------- + +// Called from worker thread +void LLWorkerClass::setWorking(bool working) +{ + mMutex.lock(); + if (working) + { + llassert_always(!(mWorkFlags & WCF_WORKING)); + setFlags(WCF_WORKING); + } + else + { + llassert_always((mWorkFlags & WCF_WORKING)); + clearFlags(WCF_WORKING); + } + mMutex.unlock(); } //---------------------------------------------------------------------------- bool LLWorkerClass::yield() { - llassert(mWorkFlags & WCF_WORKING); LLThread::yield(); mWorkerThread->checkPause(); - return (getFlags() & WCF_ABORT_REQUESTED) ? true : false; + bool res; + mMutex.lock(); + res = (getFlags() & WCF_ABORT_REQUESTED) ? true : false; + mMutex.unlock(); + return res; } //---------------------------------------------------------------------------- @@ -225,7 +267,9 @@ bool LLWorkerClass::yield() // calls startWork, adds doWork() to queue void LLWorkerClass::addWork(S32 param, U32 priority) { - if (mWorkHandle != LLWorkerThread::nullHandle()) + mMutex.lock(); + llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK))); + if (mRequestHandle != LLWorkerThread::nullHandle()) { llerrs << "LLWorkerClass attempt to add work with active worker!" << llendl; } @@ -233,70 +277,93 @@ void LLWorkerClass::addWork(S32 param, U32 priority) // llinfos << "addWork: " << mWorkerClassName << " Param: " << param << llendl; #endif startWork(param); - mWorkHandle = mWorkerThread->add(this, param, priority); + clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED); + setFlags(WCF_HAVE_WORK); + mRequestHandle = mWorkerThread->addWorkRequest(this, param, priority); + mMutex.unlock(); } -void LLWorkerClass::abortWork() +void LLWorkerClass::abortWork(bool autocomplete) { + mMutex.lock(); #if _DEBUG -// LLWorkerThread::Request* workreq = mWorkerThread->getRequest(mWorkHandle); +// LLWorkerThread::WorkRequest* workreq = mWorkerThread->getRequest(mRequestHandle); // if (workreq) // llinfos << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << llendl; #endif - mWorkerThread->abortRequest(mWorkHandle); - setFlags(WCF_ABORT_REQUESTED); + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + mWorkerThread->abortRequest(mRequestHandle, autocomplete); + mWorkerThread->setPriority(mRequestHandle, LLQueuedThread::PRIORITY_IMMEDIATE); + setFlags(WCF_ABORT_REQUESTED); + } + mMutex.unlock(); } // if doWork is complete or aborted, call endWork() and return true -bool LLWorkerClass::checkWork() +bool LLWorkerClass::checkWork(bool aborting) { + LLMutexLock lock(&mMutex); bool complete = false, abort = false; - LLWorkerThread::Request* workreq = (LLWorkerThread::Request*)mWorkerThread->getRequest(mWorkHandle); - llassert(workreq); - if (getFlags(WCF_ABORT_REQUESTED) || workreq->getStatus() == LLWorkerThread::STATUS_ABORTED) + if (mRequestHandle != LLWorkerThread::nullHandle()) { - complete = true; - abort = true; + LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); + llassert_always(workreq); + LLQueuedThread::status_t status = workreq->getStatus(); + if (status == LLWorkerThread::STATUS_ABORTED) + { + complete = true; + abort = true; + } + else if (status == LLWorkerThread::STATUS_COMPLETE) + { + complete = true; + } + else + { + llassert_always(!aborting || (workreq->getFlags() & LLQueuedThread::FLAG_ABORT)); + } + if (complete) + { + llassert_always(!(getFlags(WCF_WORKING))); + endWork(workreq->getParam(), abort); + mWorkerThread->completeRequest(mRequestHandle); + mRequestHandle = LLWorkerThread::nullHandle(); + clearFlags(WCF_HAVE_WORK); + } } - else if (workreq->getStatus() == LLWorkerThread::STATUS_COMPLETE) + else { complete = true; } - if (complete) - { -#if _DEBUG -// llinfos << "endWork: " << mWorkerClassName << " Param: " << workreq->getParam() << llendl; -#endif - endWork(workreq->getParam(), abort); - mWorkerThread->completeRequest(mWorkHandle); - mWorkHandle = LLWorkerThread::nullHandle(); - } return complete; } -void LLWorkerClass::killWork() +void LLWorkerClass::scheduleDelete() { - if (haveWork()) + bool do_delete = false; + mMutex.lock(); + if (!(getFlags(WCF_DELETE_REQUESTED))) { - abortWork(); - bool paused = mWorkerThread->isPaused(); - while (!checkWork()) - { - mWorkerThread->updateQueue(0); - } - if (paused) - { - mWorkerThread->pause(); - } + setFlags(WCF_DELETE_REQUESTED); + do_delete = true; + } + mMutex.unlock(); + if (do_delete) + { + mWorkerThread->deleteWorker(this); } } void LLWorkerClass::setPriority(U32 priority) { - if (haveWork()) + mMutex.lock(); + if (mRequestHandle != LLWorkerThread::nullHandle()) { - mWorkerThread->setPriority(mWorkHandle, priority); + mRequestPriority = priority; + mWorkerThread->setPriority(mRequestHandle, priority); } + mMutex.unlock(); } //============================================================================ diff --git a/linden/indra/llcommon/llworkerthread.h b/linden/indra/llcommon/llworkerthread.h index f01e67b..17b7e7b 100644 --- a/linden/indra/llcommon/llworkerthread.h +++ b/linden/indra/llcommon/llworkerthread.h @@ -47,13 +47,13 @@ class LLWorkerClass; class LLWorkerThread : public LLQueuedThread { public: - class Request : public LLQueuedThread::QueuedRequest + class WorkRequest : public LLQueuedThread::QueuedRequest { protected: - ~Request() {}; // use deleteRequest() + virtual ~WorkRequest(); // use deleteRequest() public: - Request(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param); + WorkRequest(handle_t handle, U32 priority, LLWorkerClass* workerclass, S32 param); S32 getParam() { @@ -64,6 +64,8 @@ public: return mWorkerClass; } + /*virtual*/ bool processRequest(); + /*virtual*/ void finishRequest(bool completed); /*virtual*/ void deleteRequest(); private: @@ -71,26 +73,24 @@ public: S32 mParam; }; -public: - LLWorkerThread(bool threaded = true, bool runalways = true); - ~LLWorkerThread(); - -protected: - /*virtual*/ bool processRequest(QueuedRequest* req); +private: + typedef std::list delete_list_t; + delete_list_t mDeleteList; + LLMutex* mDeleteMutex; + apr_pool_t* mWorkerAPRPoolp; public: - handle_t add(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL); - - static void initClass(bool local_is_threaded = true, bool local_run_always = true); // Setup sLocal - static S32 updateClass(U32 ms_elapsed); - static S32 getAllPending(); - static void pauseAll(); - static void waitOnAllPending(); - static void cleanupClass(); // Delete sLocal + LLWorkerThread(const std::string& name, bool threaded = true); + ~LLWorkerThread(); -public: - static LLWorkerThread* sLocal; // Default worker thread - static std::set sThreadList; // array of threads (includes sLocal) + apr_pool_t* getWorkerAPRPool() { return mWorkerAPRPoolp; } + + /*virtual*/ S32 update(U32 max_time_ms); + + handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL); + + void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion + S32 getNumDeletes() { return mDeleteList.size(); } // debug }; //============================================================================ @@ -112,11 +112,17 @@ public: class LLWorkerClass { + friend class LLWorkerThread; + friend class LLWorkerThread::WorkRequest; public: typedef LLWorkerThread::handle_t handle_t; enum FLAGS { - WCF_WORKING = 0x01, + WCF_HAVE_WORK = 0x01, + WCF_WORKING = 0x02, + WCF_WORK_FINISHED = 0x10, + WCF_WORK_ABORTED = 0x20, + WCF_DELETE_REQUESTED = 0x40, WCF_ABORT_REQUESTED = 0x80 }; @@ -125,17 +131,29 @@ public: virtual ~LLWorkerClass(); // pure virtual, called from WORKER THREAD, returns TRUE if done - virtual bool doWork(S32 param)=0; // Called from LLWorkerThread::processRequest() - - // called from WORKER THREAD - void setWorking(bool working) { working ? setFlags(WCF_WORKING) : clearFlags(WCF_WORKING); } + virtual bool doWork(S32 param)=0; // Called from WorkRequest::processRequest() + // virtual, called from finishRequest() after completed or aborted + virtual void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD) + // virtual, returns true if safe to delete the worker + virtual bool deleteOK(); // called from update() (WORK THREAD) + // schedlueDelete(): schedules deletion once aborted or completed + void scheduleDelete(); + + bool haveWork() { return getFlags(WCF_HAVE_WORK); } // may still be true if aborted bool isWorking() { return getFlags(WCF_WORKING); } bool wasAborted() { return getFlags(WCF_ABORT_REQUESTED); } + + // setPriority(): changes the priority of a request + void setPriority(U32 priority); + U32 getPriority() { return mRequestPriority; } const std::string& getName() const { return mWorkerClassName; } protected: + // called from WORKER THREAD + void setWorking(bool working); + // Call from doWork only to avoid eating up cpu time. // Returns true if work has been aborted // yields the current thread and calls mWorkerThread->checkPause() @@ -147,20 +165,11 @@ protected: void addWork(S32 param, U32 priority = LLWorkerThread::PRIORITY_NORMAL); // abortWork(): requests that work be aborted - void abortWork(); + void abortWork(bool autocomplete); // checkWork(): if doWork is complete or aborted, call endWork() and return true - bool checkWork(); + bool checkWork(bool aborting = false); - // haveWork(): return true if mWorkHandle != null - bool haveWork() { return mWorkHandle != LLWorkerThread::nullHandle(); } - - // killWork(): aborts work and waits for the abort to process - void killWork(); - - // setPriority(): changes the priority of a request - void setPriority(U32 priority); - private: void setFlags(U32 flags) { mWorkFlags = mWorkFlags | flags; } void clearFlags(U32 flags) { mWorkFlags = mWorkFlags & ~flags; } @@ -175,9 +184,11 @@ private: protected: LLWorkerThread* mWorkerThread; std::string mWorkerClassName; - handle_t mWorkHandle; + handle_t mRequestHandle; + U32 mRequestPriority; // last priority set private: + LLMutex mMutex; LLAtomicU32 mWorkFlags; }; diff --git a/linden/indra/llcommon/metaproperty.cpp b/linden/indra/llcommon/metaproperty.cpp index e4983cc..312dd9d 100644 --- a/linden/indra/llcommon/metaproperty.cpp +++ b/linden/indra/llcommon/metaproperty.cpp @@ -44,7 +44,7 @@ const LLMetaClass& LLMetaProperty::getObjectMetaClass() const { return mObjectClass; } - + void LLMetaProperty::checkObjectClass(const LLReflective* object) const { if(! mObjectClass.isInstance(object)) diff --git a/linden/indra/llcommon/u64.cpp b/linden/indra/llcommon/u64.cpp index 45baa13..744e0ab 100644 --- a/linden/indra/llcommon/u64.cpp +++ b/linden/indra/llcommon/u64.cpp @@ -33,7 +33,7 @@ U64 str_to_U64(const char *str) { U64 result = 0; - char *aptr = strpbrk(str,"0123456789"); + const char *aptr = strpbrk(str,"0123456789"); if (!aptr) { @@ -66,27 +66,27 @@ char* U64_to_str(U64 value, char* result, S32 result_size) if (part1) { - snprintf( + snprintf( /* Flawfinder: ignore */ result, result_size, "%u%07u%07u", - part1,part2,part3); /* Flawfinder: ignore */ + part1,part2,part3); } else if (part2) { - snprintf( + snprintf( /* Flawfinder: ignore */ result, result_size, "%u%07u", - part2,part3); /* Flawfinder: ignore */ + part2,part3); } else { - snprintf( + snprintf( /* Flawfinder: ignore */ result, result_size, "%u", - part3); /* Flawfinder: ignore */ + part3); } return (result); } -- cgit v1.1