Session::addService now returns a reference to the added Service. This
allows clients to hold a reference for further direct interaction with
the Service object.
This commit also introduces a new Session::createService convenience
method that creates the service and returns a reference to it.
The name "Service" better reflects the general purpose of this class: It
provides *something* (often resource management) to the Session, is
owned by the Session, and receives notifications from the Session when
the controller detaches / is detached, and when the Session is shut
down.
An example of a non-resource-managing Service (to be added in an
upcoming patch) is a detach / shutdown notification service: Clients can
add this service to register arbitrary callbacks to be run on detach /
shutdown. The advantage of this over the current Session detach /
shutdown callback system is that clients can control both the order of
the callbacks, and their order relative to notification of other
services.
Session::waitForShutdown is a convenience wrapper around the
asynchronous Session::shutdown call. The previous
Session::waitForShutdown call waited on a std::condition_variable to
signal the end of shutdown, but it's easier to just embed a std::promise
in a callback to the asynchronous shutdown method.
All calls to Session::shutdown were enquing their on-shutdown-complete
callbacks in Session's ShutdownInfo struct, but this queue is only
drained once by the thread that initiates shutdown. After the queue is
drained, subsequent calls to Session::shutdown were enquing their
callbacks in a queue that would never be drained.
This patch updates Session::shutdown to check whether shutdown has
completed already and, if so, run the on-shutdown-complete immediately.
This patch also fixes a concurrency bug: Session::shutdownComplete was
accessing SI->OnCompletes outside the session mutex, but this could lead
to corruption of SI->OnCompletes if a concurrent call to
Session::shutdown tried to enqueue a new callback to SI->OnCompletes
concurrently. This has been fixed by moving the SI->OnCompletes queue to
a new variable under the Session mutex, then draining the new queue
outside the mutex. (No testcase yet: this was discovered by observation,
and replicating the bug would depend on timing).
The WrapperFunctionBuffer(orc_rt_WrapperFunctionBuffer) constructor
takes ownership of the underlying buffer (if one exists). Making the
constructor explicit makes this clearer at the call site.
This mirrors a similar change to the LLVM-side API in dec5d663745.
ControllerAccess provides an abstract interface for bidirectional RPC
between the executor (running JIT'd code) and the controller (containing
the llvm::orc::ExecutionSession). ControllerAccess implementations are
expected to implement IPC / RPC using a concrete communication method
(shared memory, pipes, sockets, native system IPC, etc).
Calls from executor to controller are made via callController, with
"handler tags" (addresses in the executor) specifying the target handler
in the controller. A handler must be associated in the controller with
the given tag for the call to succeed. This ensures that only registered
entry points in the controller can be used, and avoids leaking
controller addresses into the executor.
Calls in both directions are to "wrapper functions" that take a buffer
of bytes as input and return a buffer of bytes as output. In the ORC
runtime these must be `orc_rt_WrapperFunction`s (see
Session::handleWrapperCall). The interpretation of the byte buffers is
up to the wrapper functions: the ORC runtime imposes no restrictions on
how the bytes are to be interpreted.
ControllerAccess objects may be detached from the Session prior to
Session shutdown, in which case no further calls may be made in either
direction, and any pending results (from calls made that haven't
returned yet) should return errors. If the ControllerAccess class is
still attached at Session shutdown time it will be detached as part of
the shutdown process. The ControllerAccess::disconnect method must
support concurrent entry on multiple threads, and all callers must block
until they can guarantee that no further calls will be received or
accepted.
Moves all Session member variables dedicated to shutdown into a new
ShutdownInfo struct, and uses the presence / absence of this struct as
the flag to indicate that we've entered the "shutting down" state. This
simplifies the implementation of the shutdown process.
Introduces the Task and TaskDispatcher interfaces (TaskDispatcher.h),
ThreadPoolTaskDispatcher implementation (ThreadPoolTaskDispatch.h), and
updates Session to include a TaskDispatcher instance that can be used to
run tasks.
TaskDispatcher's introduction is motivated by the need to handle calls
to JIT'd code initiated from the controller process: Incoming calls will
be wrapped in Tasks and dispatched. Session shutdown will wait on
TaskDispatcher shutdown, ensuring that all Tasks are run or destroyed
prior to the Session being destroyed.
An orc-rt Session contains a JIT'd program, managing resources and
communicating with a remote JIT-controller instance (expected to be an
orc::ExecutionSession, though this is not required).