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-07-26 13:03:22 +02:00
|
|
|
<!--
|
|
|
|
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
|
|
|
|
|
|
SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
|
|
|
This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
|
|
|
|
See the COPYRIGHT file distributed with this work for additional
|
|
|
|
information regarding copyright ownership.
|
|
|
|
-->
|
|
|
|
|
|
|
|
# Loop Manager
|
|
|
|
|
|
|
|
This document aims to describe the design of the basic event loop handling in
|
|
|
|
the BIND 9.
|
|
|
|
|
2025-07-14 10:50:21 +02:00
|
|
|
Every application is expected to run ``isc_loopmgr_create()``, either
|
|
|
|
directly or indirectly via ``isc_managers_create()``. This creates a
|
|
|
|
single loop manager.
|
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-07-26 13:03:22 +02:00
|
|
|
|
|
|
|
## 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.
|
|
|
|
|
|
|
|
## Timers
|
|
|
|
|
2023-02-21 12:21:32 -08:00
|
|
|
The ``isc_timer`` API is built on top of the ``uv_timer_t`` object.
|
|
|
|
It supports ``ticker`` and ``once`` timers, and uses ``isc_timer_start()``
|
|
|
|
and ``isc_timer_stop()`` to start and stop timers. The ``isc_timer_t``
|
|
|
|
object is not thread-safe.
|
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-07-26 13:03:22 +02:00
|
|
|
|
|
|
|
## Network Manager
|
|
|
|
|
2023-02-21 12:21:32 -08:00
|
|
|
The network manager is built on top loop manager event loops rather than
|
|
|
|
managing its own event loops. Network manager calls are not thread-safe:
|
|
|
|
all connect/read/write functions MUST be called from the thread that created
|
|
|
|
the network manager socket.
|
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-07-26 13:03:22 +02:00
|
|
|
|
|
|
|
The ``isc_nm_listen*()`` functions MUST be called from the ``main`` loop.
|
2022-09-29 11:12:15 +02:00
|
|
|
|
2023-02-21 12:21:32 -08:00
|
|
|
The general design of Network Manager is based on callbacks. Callback
|
|
|
|
functions should always be called asynchronously by the network manager,
|
|
|
|
because the caller might be holding a lock, and the callback may try to
|
|
|
|
acquire the same lock. So even if a network manager function is able to
|
|
|
|
determine a result immediately, the callback must be scheduled onto the
|
|
|
|
event loop instead of executed directly.
|