Age | Commit message (Collapse) | Author |
|
|
|
|
|
|
|
|
|
|
|
|
|
Make LLCoros constructor echo "LLApp" status-change events on new "LLCoros"
event pump.
Rename LLCoros::kill() to killreq() because this operation only registers a
request for the named coroutine to terminate next time it calls checkStop().
Add a new CoroData member to record the name of the coroutine requesting
termination. killreq() sets that and also posts "killreq" to "LLCoros".
Add an optional final-cleanup callback to LLCoros::checkStop(). Make
checkStop() check for a pending killreq() request as well as viewer
termination. Introduce new LLCoros::Killed exception for that case.
Introduce LLCoros::getStopListener(), with two overloads, to encapsulate some
of the messy logic to listen (perhaps temporarily) for viewer shutdown. Both
overloads are for use by code at the source end of a queue or promise or other
resource for which coroutines might still be waiting at viewer shutdown time.
One overload is specifically for when the caller knows the name of the one and
only coroutine that will wait on the resource (e.g. because the caller IS that
coroutine). That overload honors killreq().
Use getStopListener() to simplify the four existing places where we set up
such a listener. Add a fifth: also make WorkQueue listen for viewer shutdown
(resolving a TODO comment).
Remove LLLUAmanager::terminateScript(), getTerminationList() and the static
sTerminationList. In the Lua interrupt callback, instead of checking
sTerminationList, call LLCoros::checkStop().
Change LLFloaterLUAScripts terminate-script logic to call LLCoros::killreq()
instead of posting on "LLLua" and calling LLLUAmanager::terminateScript().
Drop LLApp::setStatus() posting to "LLLua" LLEventPump: the above makes that
moot.
|
|
instead of on LLEventTimer.
LLEventTimer takes cycles from the main loop to run through the collection of
pending LLEventTimers, checking each to see if we've reached its timestamp.
But LLMainThreadTask does not require delay timing; it wants the main loop to
service it ASAP. That's what the "mainloop" WorkQueue is for.
But WorkQueue::waitForResult() forbids calls from a thread's default
coroutine. While that restriction may still make sense in general, we
specifically want to be able to pause LLMainThreadTask's caller, no matter
what coroutine it's running on. Introduce WorkQueue::waitForResult_() that
bypasses the check.
|
|
|
|
Rather than continuing to propagate try/catch (Closed)
(aka LLThreadSafeQueueInterrupt) constructs through the code base, make
WorkQueueBase::post() return bool indicating success (i.e. ! isClosed()).
This obviates postIfOpen(), which no one was using anyway.
In effect, postIfOpen() is renamed post(), bypassing the exception when
isClosed().
Review existing try/catch blocks of that sort, changing to test for post()
returning false.
|
|
catching and returning false
|
|
Apparently Visual Studio and Xcode disagree on the intended lifespan of a
certain temporary expression. Capturing it in a named variable works.
|
|
For work queues that don't need timestamped tasks, eliminate the overhead of a
priority queue ordered by timestamp. Timestamped task support moves to
WorkSchedule. WorkQueue is a simpler queue that just waits for work.
Both WorkQueue and WorkSchedule can be accessed via new WorkQueueBase API. Of
course the WorkQueueBase API doesn't deal with timestamps, but a WorkSchedule
can be accessed directly to post timestamped tasks and then handled normally
(e.g. by ThreadPool) to run them.
Most ThreadPool functionality migrates to new ThreadPoolBase class, with
template subclass ThreadPoolUsing<WorkQueue> or ThreadPoolUsing<WorkSchedule>
depending on need. ThreadPool is now an alias for ThreadPoolUsing<WorkQueue>.
Importantly, ThreadPoolUsing::getQueue() delivers a reference to the specific
queue subclass type, so you can post timestamped tasks on a queue retrieved
from ThreadPoolUsing<WorkSchedule>::getQueue().
Since ThreadPool is no longer a simple class but an alias for a particular
template specialization, introduce threadpool_fwd.h to forward-declare it.
Recast workqueue_test.cpp to exercise WorkSchedule, since some of the tests
are time-based. A future todo would be to exercise each applicable test with
both WorkQueue and WorkSchedule.
|
|
# Conflicts:
# indra/llrender/llgl.cpp
# indra/llrender/llrendertarget.cpp
# indra/newview/VIEWER_VERSION.txt
# indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
# indra/newview/llfloaterpreference.cpp
# indra/newview/llviewercontrol.cpp
# indra/newview/llviewermenu.cpp
# indra/newview/llviewertexturelist.cpp
# indra/newview/llvovolume.cpp
|
|
The work queue callback binds "this". This is deemed safe due to current dependencies, but see the associated comment in the return callback. There was some trial and error to get a this-binded lambda to compile.
Due to LLVorbisDecodeState writing to disk off-thread, limit audio decodes proportional to general worker thread count. Guess the thread count for now.
|
|
We inadvertently changed tryPost() to call ThreadSafeSchedule::tryPost(),
which doesn't exist.
|
|
|
|
Reverting a merge is sticky: it tells git you never want to see that branch
again. Merging the DRTVWR-546 branch, which contained the revert, into the
glthread branch undid much of the development work on that branch. To restore
it we must revert the revert.
This reverts commit 029b41c0419e975bbb28454538b46dc69ce5d2ba.
|
|
|
|
|
|
This reverts commit 5188a26a8521251dda07ac0140bb129f28417e49, reversing
changes made to 819088563e13f1d75e048311fbaf0df4a79b7e19.
|
|
We want to skip calling PostMessage() to bump the window thread out of
GetMessage() in any frame with no work functions pending for that thread. That
test depends on being able to sense the size() of the queue. Having converted
to WorkQueue, we need that queue to support size().
|
|
Give ThreadPool and WorkQueue the ability to override default
ThreadSafeSchedule capacity.
Instantiate "mainloop" WorkQueue and "General" ThreadPool with very large
capacity because we never want to have to block trying to push to either.
|
|
postIfOpen() provides a no-exception alternative to post(), which blocks if
full but throws if closed. postIfOpen() likewise blocks if full, but returns
true if able to post and false if the queue was closed.
|
|
|
|
|
|
|
|
postTo() sets up two-way communication: the caller asks to run work on some
other WorkQueue, expecting an eventual callback on the originating WorkQueue.
That permits us to transport any exception thrown by the work callable back to
rethrow on the originating WorkQueue.
|
|
In addition to the name making the blocking explicit, we changed the
signature: instead of specifying a target WorkQueue on which to run,
waitForResult() runs the passed callable on its own WorkQueue.
Why is that? Because, unlike postTo(), we do not require a handshake between
two different WorkQueues. postTo() allows running arbitrary callback code,
setting variables or whatever, on the originating WorkQueue (presumably on the
originating thread). waitForResult() synchronizes using Promise/Future, which
are explicitly designed for cross-thread communication. We need not call
set_value() on the originating thread, so we don't need a postTo() callback
lambda.
|
|
The idea is that you can call runOn(target, callable) from a (non-default)
coroutine and block that coroutine until the result becomes available.
As a safety check, we forbid calling runOn() from a thread's default
coroutine, assuming that a given thread's default coroutine is the one
servicing the relevant WorkQueue.
|
|
Add a test exercising this feature.
|
|
ThreadPool bundles a WorkQueue with the specified number of worker threads to
service it. Each ThreadPool has a name that can be used to locate its
WorkQueue.
Each worker thread calls WorkQueue::runUntilClose().
ThreadPool listens on the "LLApp" LLEventPump for shutdown notification. On
receiving that, it closes its WorkQueue and then join()s each of its worker
threads for orderly shutdown.
Add a settings.xml entry "ThreadPoolSizes", the first LLSD-valued settings
entry to expect a map: pool name->size. The expectation is that usually code
instantiating a particular ThreadPool will have a default size in mind, but it
should check "ThreadPoolSizes" for a user override.
Make idle_startup()'s STATE_SEED_CAP_GRANTED state instantiate a "General"
ThreadPool. This is function-static for lazy initialization.
Eliminate LLMainLoopRepeater, which is completely unreferenced. Any potential
future use cases are better addressed by posting to the main loop's WorkQueue.
Eliminate llappviewer.cpp's private LLDeferredTaskList class, which
implemented LLAppViewer::addOnIdleCallback(). Make addOnIdleCallback() post
work to the main loop's WorkQueue instead.
|
|
It seems CALLBACK is a macro in some Microsoft header file. Bleah.
|
|
A typical WorkQueue has a string name, which can be used to find it to post
work to it. "Work" is a nullary callable.
WorkQueue is a multi-producer, multi-consumer thread-safe queue: multiple
threads can service the WorkQueue, multiple threads can post work to it.
Work can be scheduled in the future by submitting with a timestamp. In
addition, a given work item can be scheduled to run on a recurring basis.
A requesting thread servicing a WorkQueue of its own, such as the viewer's
main thread, can submit work to another WorkQueue along with a callback to be
passed the result (of arbitrary type) of the first work item. The callback is
posted to the originating WorkQueue, permitting safe data exchange between
participating threads.
Methods are provided for different kinds of servicing threads. runUntilClose()
is useful for a simple worker thread. runFor(duration) devotes no more than a
specified time slice to that WorkQueue, e.g. for use by the main thread.
|