2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 14:35:26 +00:00

remove references to obsolete isc_task/timer functions

removed references in code comments, doc/dev documentation, etc, to
isc_task, isc_timer_reset(), and isc_timertype_inactive. also removed a
coccinelle patch related to isc_timer_reset() that was no longer needed.
This commit is contained in:
Evan Hunt
2023-02-21 12:21:32 -08:00
parent ee186855bf
commit b058f99cb8
9 changed files with 43 additions and 148 deletions

View File

@@ -32,7 +32,7 @@ information regarding copyright ownership.
* [Iterators](#iterators)
* [Logging](#logging)
* [Adding a new RR type](#rrtype)
* [Task and timer model](#tasks)
* [Asynchronous operations](#async)
### <a name="reviews"></a>The code review process
@@ -1366,86 +1366,10 @@ In nearly all cases, this is simply a wrapper around the `compare()`
function, except where DNSSEC comparisons are specified as
case-sensitive. Unknown RR types are always compared case-sensitively.
#### <a name="tasks"></a>Task and timer model
#### <a name="async"></a>Asynchronous operations
The BIND task/timer management system can be thought of as comparable to a
simple non-preemptive multitasking operating system.
In this model, what BIND calls a "task" (or an `isc_task_t` object) is the
equivalent of what is usually called a "process" in an operating system:
a persistent execution context in which functions run when action is
required. When the action is complete, the task goes to sleep, and
wakes up again when more work arrives. A "worker thread" is comparable
to an operating system's CPU; when a task is ready to run, a worker
thread will run it. By default, BIND creates one worker thread for each
system CPU.
An "event" object can be associated with a task, and triggered when a a
specific condition occurs. Each event object contains a pointer to a
specific function and arguments to be passed to it. When the event
triggers, the task is placed onto a "ready queue" in the task manager. As
each running task finishes, the worker threads pull new tasks off the ready
queue. When the task associated with a given event reaches the head of the
queue, the specified function will be called.
Examples:
A timer is set for a specified time in the future, and the event will
be triggered at that time.
/*
* Function to handle a timeout
*/
static void
timeout(isc_task_t *task, isc_event_t *event) {
/* do things */
}
...
/*
* Set up a timer in timer manager 'timermgr', to run
* once, with a NULL expiration time, after 'interval'
* has passed; it will run the function 'timeout' with
* 'arg' as its argument in task 'task'.
*/
isc_timer_t *timer = NULL;
result = isc_timer_create(timermgr, task, timeout, arg, &timer);
result = isc_timer_reset(timermgr, isc_timertype_once, NULL,
interval, false);
An event can also be explicitly triggered via `isc_task_send()`.
static void
do_things(isc_task_t *task, isc_event_t *event) {
/* this function does things */
}
...
/*
* Allocate an event that calls 'do_things' with a
* NULL argument, using 'myself' as ev_sender.
*
* DNS_EVENT_DOTHINGS must be defined in <dns/events.h>.
*
* (Note that 'size' must be specified because there are
* event objects that inherit from isc_event_t, incorporating
* common members via the ISC_EVENT_COMMON member and then
* following them with other members.)
*/
isc_event_t *event;
event = isc_event_allocate(mctx, myself, DNS_EVENT_DOTHINGS,
do_things, NULL, sizeof(isc_event_t));
if (event == NULL)
return (ISC_R_NOMEMORY);
...
/*
* Send the allocated event to task 'task'
*/
isc_task_send(task, event);
Asynchronous operations are processed using the event loop manager;
see the [Loop Manager](loopmgr.md) document for details.
#### More...

View File

@@ -79,38 +79,25 @@ need to run the event on a different thread.
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.
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.
## 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 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.
The ``isc_nm_listen*()`` functions MUST be called from the ``main`` loop.
The general design of Network Manager is based on callbacks. An extra care must
be taken when implementing new functions because the callbacks MUST be called
asynchronously because the caller might be inside a lock and the same lock must
be acquired in the callback. This doesn't mean that the callback must be always
called asynchronously, because sometimes we are already in the libuv callback
and thus we can just call the callback directly, but in other places, especially
when returning an error, the control hasn't been returned to the caller yet and
in such case, the callback must be scheduled onto the event loop instead of
executing it directly.
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.

View File

@@ -46,7 +46,7 @@ result information as the return value of the function. E.g.
isc_result_t result;
result = isc_task_send(task, &event);
result = isc_stdio_open(filename, 0644, &fp);
Note that an explicit result type is used, instead of mixing the error result
type with the normal result type. E.g. the C library routine getc() can

View File

@@ -764,24 +764,18 @@ described for the public interfaces, except `{library}` and `{module}` are
separated by a double-underscore. This indicates that the name is
internal, its API is not as formal as the public API, and thus it might
change without any sort of notice. Examples of this usage include
`dns__zone_loadpending()` and `isc__taskmgr_ready()`.
`dns__zone_loadpending()` and `isc__mem_printallactive()`.
In many cases, a public interface is instantiated by a private back-end
implementation. The double-underscore naming style is sometimes used in
that situation; for example, `isc_task_attach()` calls the `attach`
function provided by a task API implementation; in BIND 9, this function
is provided by `isc__task_attach()`.
Other times, private interface implementations are static functions
that are pointed to by "method" tables. For example, the `dns_db`
interface is implemented in several places, including `lib/dns/rbtdb.c`
(the red-black tree database used for internal storage of zones and
cache data) and `lib/dns/sdlz.c` (an interface to DLZ modules).
In some cases, a public interface is instantiated by a private back-end
implementation. The private interface implementations are typically
static functions that are pointed to by "method" tables. For example,
the `dns_db` interface is implemented in several places, including
`lib/dns/rbtdb.c` (the red-black tree database used for internal storage of
zones and cache data) and `lib/dns/sdlz.c` (an interface to DLZ modules).
An object of type `dns_dbmethods_t` is created for each of these,
containing function pointers to the local implementations of each
of the `dns_db` API functions. The `dns_db_findnode()` function
is provided by static functions called `findnode()` in each file,
and so on.
containing function pointers to the local implementations of each of the
`dns_db` API functions. The `dns_db_findnode()` function is provided by
static functions called `findnode()` in each file, and so on.
#### Initialization