Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions indra/cmake/Linking.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ else()
find_library(APPKIT_LIBRARY AppKit)
find_library(COREAUDIO_LIBRARY CoreAudio)
find_library(COREGRAPHICS_LIBRARY CoreGraphics)
find_library(COREVIDEO_LIBRARY CoreVideo)
find_library(AUDIOTOOLBOX_LIBRARY AudioToolbox)
find_library(UNIFORMTYPEIDENTIFIERS_LIBRARY UniformTypeIdentifiers)

Expand All @@ -88,6 +89,7 @@ else()
${COREAUDIO_LIBRARY}
${AUDIOTOOLBOX_LIBRARY}
${COREGRAPHICS_LIBRARY}
${COREVIDEO_LIBRARY}
${UNIFORMTYPEIDENTIFIERS_LIBRARY}
)
endif()
Expand Down
2 changes: 1 addition & 1 deletion indra/llappearance/lltexlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ class LLTexLayerSetInfo
//
// The composite image that a LLTexLayerSet writes to. Each LLTexLayerSet has one.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class LLTexLayerSetBuffer : public virtual LLRefCount
class LLTexLayerSetBuffer : public virtual LLThreadSafeRefCount
{
LOG_CLASS(LLTexLayerSetBuffer);

Expand Down
2 changes: 1 addition & 1 deletion indra/llcommon/llcommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ void LLCommon::initClass()
sAprInitialized = true;
}
LLTimer::initClass();
assert_main_thread(); // Make sure we record the main thread
assert_viewer_thread(); // Make sure we record the main thread
if (!sMasterThreadRecorder)
{
sMasterThreadRecorder = new LLTrace::ThreadRecorder();
Expand Down
4 changes: 2 additions & 2 deletions indra/llcommon/llcoros.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ bool LLCoros::on_main_coro()
}

// static
bool LLCoros::on_main_thread_main_coro()
bool LLCoros::on_viewer_thread_main_coro()
{
return on_main_coro() && on_main_thread();
return on_main_coro() && on_viewer_thread();
}

// static
Expand Down
6 changes: 3 additions & 3 deletions indra/llcommon/llcoros.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
// llassert(LLCoros::on_main_coro())
static bool on_main_coro();

// For debugging, return true if on the main thread and not in a coroutine
// For debugging, return true if on the viewer thread and not in a coroutine.
// Non-thread-safe code in the main loop should be protected by
// llassert(LLCoros::on_main_thread_main_coro())
static bool on_main_thread_main_coro();
// llassert(LLCoros::on_viewer_thread_main_coro())
static bool on_viewer_thread_main_coro();

/// The viewer's use of the term "coroutine" became deeply embedded before
/// the industry term "fiber" emerged to distinguish userland threads from
Expand Down
4 changes: 2 additions & 2 deletions indra/llcommon/llmainthreadtask.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* exception. See std::packaged_task.)
*
* When you call dispatch() on the main thread (as determined by
* on_main_thread() in llthread.h), it simply calls your task and returns the
* on_viewer_thread() in llthread.h), it simply calls your task and returns the
* result.
*
* When you call dispatch() on a secondary thread, it instantiates an
Expand All @@ -52,7 +52,7 @@ class LLMainThreadTask
template <typename CALLABLE>
static auto dispatch(CALLABLE&& callable) -> decltype(callable())
{
if (on_main_thread())
if (on_viewer_thread())
{
// we're already running on the main thread, perfect
return callable();
Expand Down
6 changes: 3 additions & 3 deletions indra/llcommon/llsingleton.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
#include <vector>
#include "mutex.h"
#include "lockstatic.h"
#include "llthread.h" // on_main_thread()
#include "llthread.h" // on_viewer_thread()
#include "llmainthreadtask.h"
#include "llprofiler.h"
#include "llerror.h"
Expand Down Expand Up @@ -548,7 +548,7 @@ class LLSingleton : public LLSingletonBase
}

// Here we need to construct a new instance.
if (on_main_thread())
if (on_viewer_thread())
{
// On the main thread, directly construct the instance while
// holding the lock.
Expand Down Expand Up @@ -657,7 +657,7 @@ class LLParamSingleton : public LLSingleton<DERIVED_TYPE>
" twice!"});
return nullptr;
}
else if (on_main_thread())
else if (on_viewer_thread())
{
// on the main thread, simply construct instance while holding lock
super::logdebugs({super::template classname<DERIVED_TYPE>(),
Expand Down
78 changes: 61 additions & 17 deletions indra/llcommon/llthread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,18 @@ void set_thread_name( DWORD dwThreadID, const char* threadName)
namespace
{

LLThread::id_t main_thread()
{
// Using a function-static variable to identify the main thread
// requires that control reach here from the main thread before it
// reaches here from any other thread. We simply trust that whichever
// thread gets here first is the main thread.
static LLThread::id_t s_thread_id = LLThread::currentID();
return s_thread_id;
}
// Thread identity anchors. A default-constructed thread id means
// "not set yet", so we don't need a separate flag.
//
// The viewer thread anchors itself at run() entry while other
// threads are already running and reading - atomic makes that
// intentional race well-defined.
std::atomic<LLThread::id_t> g_viewer_thread_id{};

// Set once on the OS main thread at init, before any thread that
// reads it exists - no atomic needed. Set explicitly rather than
// first-caller-wins since the viewer thread might get here first.
LLThread::id_t g_os_main_thread_id{};

#if LL_WINDOWS

Expand All @@ -131,20 +134,61 @@ namespace
#endif // LL_WINDOWS
} // anonymous namespace

LL_COMMON_API bool on_main_thread()
LL_COMMON_API void set_viewer_thread()
{
g_viewer_thread_id.store(LLThread::currentID(), std::memory_order_release);
}

LL_COMMON_API void clear_viewer_thread()
{
g_viewer_thread_id.store(LLThread::id_t(), std::memory_order_release);
}

LL_COMMON_API bool on_viewer_thread()
{
const LLThread::id_t id = g_viewer_thread_id.load(std::memory_order_acquire);
if (id == LLThread::id_t())
{
// The viewer thread hasn't spawned yet, so the OS main thread
// is still doing its job. Defer to that check.
return on_os_main_thread();
}
return (LLThread::currentID() == id);
}

LL_COMMON_API bool assert_viewer_thread()
{
return (LLThread::currentID() == main_thread());
if (on_viewer_thread())
return true;

LL_WARNS() << "Illegal execution from thread id " << LLThread::currentID()
<< " outside viewer thread "
<< g_viewer_thread_id.load(std::memory_order_acquire) << LL_ENDL;
return false;
}

LL_COMMON_API void set_os_main_thread()
{
g_os_main_thread_id = LLThread::currentID();
}

LL_COMMON_API bool on_os_main_thread()
{
if (g_os_main_thread_id == LLThread::id_t())
{
// Not registered yet - give early init the benefit of the doubt.
return true;
}
return (LLThread::currentID() == g_os_main_thread_id);
}

LL_COMMON_API bool assert_main_thread()
LL_COMMON_API bool assert_os_main_thread()
{
auto curr = LLThread::currentID();
auto main = main_thread();
if (curr == main)
if (on_os_main_thread())
return true;

LL_WARNS() << "Illegal execution from thread id " << curr
<< " outside main thread " << main << LL_ENDL;
LL_WARNS() << "Illegal execution from thread id " << LLThread::currentID()
<< " outside OS main thread " << g_os_main_thread_id << LL_ENDL;
return false;
}

Expand Down
21 changes: 19 additions & 2 deletions indra/llcommon/llthread.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,24 @@ class LL_COMMON_API LLResponder : public LLThreadSafeRefCount

//============================================================================

extern LL_COMMON_API bool assert_main_thread();
extern LL_COMMON_API bool on_main_thread();
// The viewer thread is where we render frames and run most of what
// used to be the main loop. It used to be the OS main thread; now it
// runs on its own while the OS main thread handles the compositor.
// set_viewer_thread() anchors it when the thread starts;
// clear_viewer_thread() un-anchors it after the thread is joined at
// shutdown. While unset, on_viewer_thread() falls back to the OS main
// thread check, so early init and post-join cleanup both run as the
// acting viewer thread without tripping asserts.
extern LL_COMMON_API void set_viewer_thread();
extern LL_COMMON_API void clear_viewer_thread();
extern LL_COMMON_API bool assert_viewer_thread();
extern LL_COMMON_API bool on_viewer_thread();

// The OS main thread owns the window message pump and the compositor.
// We record it explicitly at window init so it sticks to the real OS
// main thread rather than whoever happens to ask first.
extern LL_COMMON_API void set_os_main_thread();
extern LL_COMMON_API bool assert_os_main_thread();
extern LL_COMMON_API bool on_os_main_thread();

#endif // LL_LLTHREAD_H
6 changes: 3 additions & 3 deletions indra/llcommon/tests/llmainthreadtask_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
// other Linden headers
#include "../test/lltut.h"
#include "../test/sync.h"
#include "llthread.h" // on_main_thread()
#include "llthread.h" // on_viewer_thread()
#include "lleventtimer.h"
#include "lockstatic.h"

Expand All @@ -38,7 +38,7 @@ namespace tut
{
// we're not testing the result; this is just to cache the
// initial thread as the main thread.
on_main_thread();
on_viewer_thread();
}
};
typedef test_group<llmainthreadtask_data> llmainthreadtask_group;
Expand Down Expand Up @@ -85,7 +85,7 @@ namespace tut
// have to lock static mutex to set static data
LockStatic()->ran = true;
// indicate whether task was run on the main thread
return on_main_thread();
return on_viewer_thread();
}));
// wait for test<2>() to unblock us again
mSync.yield_until(3);
Expand Down
4 changes: 2 additions & 2 deletions indra/llprimitive/llmodelloader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,14 @@ LLModelLoader::LLModelLoader(
, mDebugMode(debugMode)
, mJointMap(legalJointNamesMap)
{
assert_main_thread();
assert_viewer_thread();
sActiveLoaderList.push_back(this) ;
mWarningsArray = LLSD::emptyArray();
}

LLModelLoader::~LLModelLoader()
{
assert_main_thread();
assert_viewer_thread();
sActiveLoaderList.remove(this);
}

Expand Down
10 changes: 10 additions & 0 deletions indra/llrender/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ set(llrender_SOURCE_FILES
llrendernavprim.cpp
llrendersphere.cpp
llrendertarget.cpp
llswapchain.cpp
llcompositor.cpp
lltestsquarecompositable.cpp
llgpuresource.cpp
llshadermgr.cpp
lltexture.cpp
lltexturemanagerbridge.cpp
Expand Down Expand Up @@ -59,6 +63,12 @@ set(llrender_HEADER_FILES
llrender2dutils.h
llrendernavprim.h
llrendersphere.h
llswapchain.h
llcompositor.h
llcompositable.h
lltestsquarecompositable.h
llgpuresource.h
llresourcelease.h
llshadermgr.h
lltexture.h
lltexturemanagerbridge.h
Expand Down
Loading
Loading