Two sleep() methods: one accepting F32Milliseconds, or in general any LLUnits
time class; the other accepting any std::chrono::duration.
The significant thing about each of these sleep() methods, as opposed to any
freestanding sleep() function, is that it only sleeps until the app starts
shutdown. Moreover, it returns true if it slept for the whole specified
duration, false if it woke for app shutdown.
This is accomplished by making LLApp::sStatus be an LLScalarCond<EAppStatus>
instead of a plain EAppStatus enum, and by making setStatus() call set_all()
each time the value changes. Then each new sleep() method can call
wait_for_unequal(duration, APP_STATUS_RUNNING).
Introducing llcond.h into llapp.h triggered an #include circularity because
llthread.h #included llapp.h even though it didn't reference anything from it.
Removed. This, in turn, necessitated adding #include "llapp.h" to several .cpp
files that reference LLApp but had been depending on other header files to
drag in llapp.h.
The observed crash was due to sharing a stateful global resource (the global
LLMessageSystem instance) between different tasks. Specifically, a coroutine
sets its mMessageReader one way, expecting that value to persist until it's
done with message parsing, but another coroutine sneaks in at a suspension
point and sets it differently.
Introduce LockMessageReader and LockMessageChecker classes, which must be
instantiated by a consumer of the resource. The constructor of each locks a
coroutine-aware mutex, so that for the lifetime of the lock object no other
coroutine can instantiate another.
Refactor the code so that LLMessageSystem::mMessageReader can only be modified
by LockMessageReader, not by direct assignment. mMessageReader is now an
instance of LLMessageReaderPointer, which supports dereferencing and
comparison but not assignment. Only LockMessageReader can change its value.
LockMessageReader addresses the use case in which the specific mMessageReader
value need only persist for the duration of a single method call. Add an
instance in LLMessageHandlerBridge::post().
LockMessageChecker is a subclass of LockMessageReader: both lock the same
mutex. LockMessageChecker addresses the use case in which the specific
mMessageReader value must persist across multiple method calls. Modify the
methods in question to require a LockMessageChecker instance. Provide
LockMessageChecker forwarding methods to facilitate calling the underlying
LLMessageSystem methods via the LockMessageChecker instance.
Add LockMessageChecker instances to LLAppViewer::idleNetwork(), a couple cases
in idle_startup() and LLMessageSystem::establishBidirectionalTrust().
The problem was that class-static LLUrlEntryParcel::sRegionHost was being
initialized by copying class-static LLHost::invalid. Naturally, these two
statics are initialized in different source files. Since C++ makes no promises
about the relative order in which objects in different object files are
initialized, it seems we hit a case in which we were trying to initialize
sRegionHost by copying a completely uninitialized LLHost::invalid.
In general we might attempt to address such cross-translation-unit issues by
introducing an LLSingleton. But in this particular case, the punch line is
that LLHost::invalid is explicitly constructed identically to a
default-constructed LLHost! In other words, LLHost::invalid provides nothing
we couldn't get from LLHost(). All it gives us is an opportunity for glitches
such as the above.
Remove LLHost::invalid and all references, replacing with LLHost().
continued conversion to units system
made units perform type promotion correctly and preserve type in arithmetic
e.g. can now do LLVector3 in units
added typedefs for remaining common unit types, including implicits
consolidated most indra-specific constants in llcommon under indra_constants.h
fixed issues with operations on mixed unit types (implicit and explicit)
made LL_INFOS() style macros variadic in order to subsume other logging methods
such as ll_infos
added optional tag output to error recorders