2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-28 21:17:54 +00:00
bind/doc/dev/loopmgr.md
Ondřej Surý 84c90e223f
New event loop handling API
This commit introduces new APIs for applications and signal handling,
intended to replace isc_app for applications built on top of libisc.

* isc_app will be replaced with isc_loopmgr, which handles the
  starting and stopping of applications. In isc_loopmgr, the main
  thread is not blocked, but is part of the working thread set.
  The loop manager will start a number of threads, each with a
  uv_loop event loop running. Setup and teardown functions can be
  assigned which will run when the loop starts and stops, and
  jobs can be scheduled to run in the meantime. When
  isc_loopmgr_shutdown() is run from any the loops, all loops
  will shut down and the application can terminate.

* signal handling will now be handled with a separate isc_signal unit.
  isc_loopmgr only handles SIGTERM and SIGINT for application
  termination, but the application may install additional signal
  handlers, such as SIGHUP as a signal to reload configuration.

* new job running primitives, isc_job and isc_async, have been added.
  Both units schedule callbacks (specifying a callback function and
  argument) on an event loop. The difference is that isc_job unit is
  unlocked and not thread-safe, so it can be used to efficiently
  run jobs in the same thread, while isc_async is thread-safe and
  uses locking, so it can be used to pass jobs from one thread to
  another.

* isc_tid will be used to track the thread ID in isc_loop worker
  threads.

* unit tests have been added for the new APIs.
2022-08-25 12:24:29 +02:00

4.4 KiB

Loop Manager

This document aims to describe the design of the basic event loop handling in the BIND 9.

Every application is expected to create and use a single isc_loopmgr_t instance, but the isc_loopmgr API itself doesn't enforce this requirement.

Event Loops

The loop manager creates N event loops (of type isc_loop_t), where N is specified by the caller when creating the loop manager. The number of event loops is usually same as the number of logical CPUs. The minimum N is 1, and maximum is limited only by the machine resources.

For each event loop, a thread is created by the loop manager. The isc_loop_t object itself is built on top of uv_loop_t. uv_loop_t is not thread-safe, and this is also true for isc_loop_t. If you need to run an event on a different event loop, see below for the isc_async API.

The application can get a reference to the current event loop using isc_loop_current(), to the main event loop (loop 0) that will always exist using isc_loop_main() and to an arbitrary event loop using isc_loop_get().

Application Start and Stop

Every application MUST add its initial events using isc_loopmgr_setup() to be run on all initialized event loops or isc_loop_setup() to be run on a selected event loop.

Applications MAY also add events to be run when the application is shut down by calling isc_loopmgr_teardown() (or isc_loop_teardown() for a specific event loop).

After the setup and teardown events have been configured, the application may be started via isc_loopmgr_run(). isc_loopmgr_run() will block for the caller while event loops are running. When the work is done, isc_loopmgr_shutdown() must be run from within one of the event loops; this will cause all loops to be shut down and isc_loopmgr_run() to return.

The most notable change from the isc_app API is the lack of a blocked main thread. The loop manager starts the main event loop on the main thread when the application is started.

This API now replaces the old isc_app API.

Signal Handling

The loop manager itself takes care of handling the SIGTERM and SIGINT signals, but the application MAY add more handlers via isc_signal API. In named, for example, SIGHUP is used to trigger an application reload.

Event scheduling

The application may add events to the event loop via isc_job_run() for jobs on the same event loop, or via isc_async_run() for jobs to be passed to other event loops. Both functions take the event loop, the callback and the callback argument as parameters.

Generally isc_job_run() is more direct, as it schedules the event directly on the event loop and doesn't use locking, and should be preferred unless you need to run the event on a different thread.

isc_async_run() is the only new thread-safe function provided by the loop manager, uses locked list to collect new jobs and uv_async() primitive to enqueue the collected jobs onto the event loop.

Tasks

The isc_task API has been modified to run the tasks directly on the loop manager. The new isc_job and isc_async APIs are preferred for simple events; the isc_task API is provided for backward-compatibility purposes and thus is also thread-safe because it uses locking and uv_async() to enqueue events onto the event loop.

Timers

The isc_timer API is now built on top of the uv_timer_t object. It has been changed to support only ticker and once timers, and now uses isc_timer_start() and isc_timer_stop() instead of changing the timer type to inactive. The isc_timer_t object is not thread-safe.

Network Manager

The network manager has been changed to use the loop manager event loops instead of managing its own event loops.

The new network manager calls are not thread-safe; all connect/read/write functions MUST be called from the thread that created the network manager socket.

The isc_nm_listen*() functions MUST be called from the main loop.