summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorSteven Bennetts <steve@lindenlab.com>2007-03-02 21:25:50 +0000
committerSteven Bennetts <steve@lindenlab.com>2007-03-02 21:25:50 +0000
commit4dabd9c0472deb49573fdafef2fa413e59703f19 (patch)
tree06c680d6a2047e03838d6548bccd26c7baf9d652 /indra/llcommon
parentd4462963c6ba5db2088723bbedc7b60f1184c594 (diff)
merge release@58699 beta-1-14-0@58707 -> release
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/imageids.h2
-rw-r--r--indra/llcommon/llapr.cpp174
-rw-r--r--indra/llcommon/llapr.h18
-rw-r--r--indra/llcommon/llcommon.cpp1
-rw-r--r--indra/llcommon/llcommon.h1
-rw-r--r--indra/llcommon/llerror.cpp1
-rw-r--r--indra/llcommon/llevent.h1
-rw-r--r--indra/llcommon/llfasttimer.h25
-rw-r--r--indra/llcommon/llfile.cpp13
-rw-r--r--indra/llcommon/llfile.h1
-rw-r--r--indra/llcommon/llmemory.cpp38
-rw-r--r--indra/llcommon/llmemory.h51
-rw-r--r--indra/llcommon/llmemtype.h1
-rw-r--r--indra/llcommon/llqueuedthread.cpp195
-rw-r--r--indra/llcommon/llqueuedthread.h56
-rw-r--r--indra/llcommon/llsecondlifeurls.h9
-rw-r--r--indra/llcommon/llstrider.h1
-rw-r--r--indra/llcommon/llthread.cpp63
-rw-r--r--indra/llcommon/llthread.h75
-rw-r--r--indra/llcommon/llworkerthread.cpp325
-rw-r--r--indra/llcommon/llworkerthread.h85
21 files changed, 724 insertions, 412 deletions
diff --git a/indra/llcommon/imageids.h b/indra/llcommon/imageids.h
index 8147183bec..9f57ec84c2 100644
--- a/indra/llcommon/imageids.h
+++ b/indra/llcommon/imageids.h
@@ -31,7 +31,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/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index a7fc6a40a7..bf6a4d1b21 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -103,11 +103,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)
@@ -123,6 +125,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);
@@ -132,6 +135,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)
{
@@ -143,10 +158,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)
{
@@ -158,28 +200,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;
@@ -188,10 +275,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;
@@ -199,3 +287,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/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 1e9e944eef..e89912279e 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -106,14 +106,24 @@ typedef LLAtomic32<S32> 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/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp
index ff810abfa9..52fcaa3c19 100644
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -8,6 +8,7 @@
#include "linden_common.h"
#include "llcommon.h"
+#include "llthread.h"
//static
BOOL LLCommon::sAprInitialized = FALSE;
diff --git a/indra/llcommon/llcommon.h b/indra/llcommon/llcommon.h
index c37d479ba9..e7fb5b84e4 100644
--- a/indra/llcommon/llcommon.h
+++ b/indra/llcommon/llcommon.h
@@ -12,7 +12,6 @@
#include "llapr.h"
// #include "llframecallbackmanager.h"
#include "lltimer.h"
-#include "llworkerthread.h"
#include "llfile.h"
class LLCommon
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 1ed25a0d17..bbff363f54 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -12,6 +12,7 @@
#include "llerror.h"
#include "llerrorcontrol.h"
+#include "llapp.h"
#include "llapr.h"
extern apr_thread_mutex_t *gLogMutexp;
#include "llfile.h"
diff --git a/indra/llcommon/llevent.h b/indra/llcommon/llevent.h
index 283f40f923..a3f6b0e942 100644
--- a/indra/llcommon/llevent.h
+++ b/indra/llcommon/llevent.h
@@ -12,6 +12,7 @@
#include "llsd.h"
#include "llmemory.h"
+#include "llthread.h"
class LLEventListener;
class LLEvent;
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 2fde728eaf..1a7e60656c 100644
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -37,13 +37,22 @@ 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_GRASS,
+ FTM_RENDER_INVISIBLE,
FTM_RENDER_SHINY,
FTM_RENDER_BUMP,
FTM_RENDER_TREES,
@@ -62,6 +71,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,
@@ -71,6 +94,7 @@ public:
FTM_UPDATE_LIGHTS,
FTM_CULL,
FTM_CULL_REBOUND,
+ FTM_FRUSTUM_CULL,
FTM_GEO_UPDATE,
FTM_GEO_RESERVE,
FTM_GEO_LIGHT,
@@ -97,6 +121,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/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index 4acd94f943..f43e57f467 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -29,6 +29,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
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index 2899f51a60..605918cd29 100644
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -50,6 +50,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);
diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index 0a21c3a2a7..1063de5a8c 100644
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -9,6 +9,7 @@
#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 >
@@ -244,43 +245,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/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 962a4aa5d5..d543d023ff 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -12,8 +12,6 @@
#include <cstdlib>
#include "llerror.h"
-#include "llthread.h"
-#include "llmemtype.h"
extern S32 gTotalDAlloc;
extern S32 gTotalDAUse;
@@ -42,53 +40,7 @@ private:
// LLPointer<LLFoo> 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
//----------------------------------------------------------------------------
@@ -132,6 +84,7 @@ private:
//----------------------------------------------------------------------------
+// Note: relies on Type having ref() and unref() methods
template <class Type> class LLPointer
{
public:
diff --git a/indra/llcommon/llmemtype.h b/indra/llcommon/llmemtype.h
index 17afaa6a8a..53f7f66285 100644
--- a/indra/llcommon/llmemtype.h
+++ b/indra/llcommon/llmemtype.h
@@ -52,6 +52,7 @@ public:
MTYPE_DRAWABLE,
MTYPE_OBJECT,
+ MTYPE_VERTEX_DATA,
MTYPE_SPACE_PARTITION,
MTYPE_PIPELINE,
MTYPE_AVATAR,
diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp
index bc41927d38..e6ac9ac11d 100644
--- a/indra/llcommon/llqueuedthread.cpp
+++ b/indra/llcommon/llqueuedthread.cpp
@@ -12,10 +12,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)
{
@@ -28,6 +27,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
@@ -54,61 +59,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();
@@ -122,7 +135,7 @@ void LLQueuedThread::waitOnPending()
{
while(1)
{
- updateQueue(0);
+ update(0);
if (mIdleThread)
{
@@ -181,7 +194,7 @@ bool LLQueuedThread::addRequest(QueuedRequest* req)
#endif
unlockData();
- updateQueue(1);
+ incQueue();
return true;
}
@@ -195,7 +208,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)
@@ -253,51 +266,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();
}
@@ -309,9 +318,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();
@@ -345,28 +355,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)
{
@@ -374,22 +390,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();
}
@@ -400,12 +416,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())
{
@@ -418,7 +440,7 @@ int LLQueuedThread::processNextRequest()
}
else
{
- res = 1;
+ res = pending;
}
return res;
}
@@ -426,13 +448,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.
@@ -455,6 +478,8 @@ void LLQueuedThread::run()
{
break;
}
+
+ //LLThread::yield(); // thread should yield after each request
}
llinfos << "QUEUED THREAD " << mName << " EXITING." << llendl;
@@ -472,20 +497,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/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h
index beff473f52..8b6a658333 100644
--- a/indra/llcommon/llqueuedthread.h
+++ b/indra/llcommon/llqueuedthread.h
@@ -33,7 +33,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,
@@ -41,13 +42,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;
@@ -60,7 +61,7 @@ public:
friend class LLQueuedThread;
protected:
- ~QueuedRequest(); // use deleteRequest()
+ virtual ~QueuedRequest(); // use deleteRequest()
public:
QueuedRequest(handle_t handle, U32 priority, U32 flags = 0);
@@ -92,26 +93,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)
@@ -141,9 +130,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&);
@@ -155,26 +145,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,
@@ -186,7 +175,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<BOOL> mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
typedef std::set<QueuedRequest*, queued_request_less> request_queue_t;
diff --git a/indra/llcommon/llsecondlifeurls.h b/indra/llcommon/llsecondlifeurls.h
index b07c18eb72..cbea60034f 100644
--- a/indra/llcommon/llsecondlifeurls.h
+++ b/indra/llcommon/llsecondlifeurls.h
@@ -31,18 +31,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[];
diff --git a/indra/llcommon/llstrider.h b/indra/llcommon/llstrider.h
index 0688e43940..c5fbf1282a 100644
--- a/indra/llcommon/llstrider.h
+++ b/indra/llcommon/llstrider.h
@@ -32,6 +32,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/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index bd2dd7c8f5..a92d553148 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -81,6 +81,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)
@@ -186,18 +191,6 @@ void LLThread::checkPause()
//============================================================================
-bool LLThread::isQuitting() const
-{
- return (QUITTING == mStatus);
-}
-
-
-bool LLThread::isStopped() const
-{
- return (STOPPED == mStatus);
-}
-
-
void LLThread::setQuitting()
{
mRunCondition->lock();
@@ -328,3 +321,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/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index f6f6bd210a..ce5daa938c 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -11,6 +11,7 @@
#include "llapr.h"
#include "llapp.h"
+#include "llmemory.h"
#include "apr-1/apr_thread_cond.h"
@@ -30,19 +31,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();
@@ -60,7 +62,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);
@@ -161,4 +163,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/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp
index a9370c8f6d..31f5c1cfcd 100644
--- a/indra/llcommon/llworkerthread.cpp
+++ b/indra/llcommon/llworkerthread.cpp
@@ -14,98 +14,86 @@
#endif
//============================================================================
-
-/*static*/ LLWorkerThread* LLWorkerThread::sLocal = NULL;
-/*static*/ std::set<LLWorkerThread*> 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<LLWorkerThread*>::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<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++)
+ S32 res = LLQueuedThread::update(max_time_ms);
+ // Delete scheduled workers
+ std::vector<LLWorkerClass*> delete_list;
+ std::vector<LLWorkerClass*> 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<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++)
+ mDeleteMutex->unlock();
+ // abort and delete after releasing mutex
+ for (std::vector<LLWorkerClass*>::iterator iter = abort_list.begin();
+ iter != abort_list.end(); ++iter)
{
- (*iter)->pause();
+ (*iter)->abortWork(false);
}
-}
-
-//static
-void LLWorkerThread::waitOnAllPending()
-{
- for (std::set<LLWorkerThread*>::iterator iter = sThreadList.begin(); iter != sThreadList.end(); iter++)
+ for (std::vector<LLWorkerClass*>::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)
@@ -118,63 +106,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;
@@ -184,21 +189,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;
}
//----------------------------------------------------------------------------
@@ -206,7 +248,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;
}
@@ -214,70 +258,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/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h
index bf5887e797..d466c35786 100644
--- a/indra/llcommon/llworkerthread.h
+++ b/indra/llcommon/llworkerthread.h
@@ -28,13 +28,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()
{
@@ -45,6 +45,8 @@ public:
return mWorkerClass;
}
+ /*virtual*/ bool processRequest();
+ /*virtual*/ void finishRequest(bool completed);
/*virtual*/ void deleteRequest();
private:
@@ -52,26 +54,24 @@ public:
S32 mParam;
};
-public:
- LLWorkerThread(bool threaded = true, bool runalways = true);
- ~LLWorkerThread();
-
-protected:
- /*virtual*/ bool processRequest(QueuedRequest* req);
+private:
+ typedef std::list<LLWorkerClass*> 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<LLWorkerThread*> 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
};
//============================================================================
@@ -93,11 +93,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
};
@@ -106,17 +112,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()
@@ -128,20 +146,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; }
@@ -156,9 +165,11 @@ private:
protected:
LLWorkerThread* mWorkerThread;
std::string mWorkerClassName;
- handle_t mWorkHandle;
+ handle_t mRequestHandle;
+ U32 mRequestPriority; // last priority set
private:
+ LLMutex mMutex;
LLAtomicU32 mWorkFlags;
};