tasks.md 3.4 KB

Tasks and workers: doing stuff that may conceptually block, non-blocking

Tasks are things that might need to do potentially-blocking IO (e.g. recv(2), send(2) or accept(2)) or may take a non-negligible amount of time (e.g. compilation or factoring semiprimes).

The former should non-blocking, and the latter time-sliced. This is implemented with a kqueue (*BSD) or epoll instance (Linux), an event loop, cooperative multitasking, and recursion, sort of.

(There is no intention to port this to Windoze as long as it doesn't have a synchronous edge-polled event-notificaton mechanism.)

The entity that actually performs tasks is the worker.

Deciding what to do

  1. A worker has a queue of things to do. These all run for during their self-determined time quantum.
  2. The worker asks the kernel for which tasks IO became possible with kqueue or epoll_wait(2). These are added to the end of the todo queue.

Recursivity for heterogeneous tasks

Tasks of the same type are batched to reduce pressure on the caches. (As a side-effect, there are only a limited number of indirect calls.) Each task type has its own worker, which are a task of their own, of the top-level worker. (These two types of workers are implemented differently.)

This creates three levels of tasks: the top-level worker, type-specific task sets and tasks.

Don't wait if there are things to do

A worker should not block waiting for IO readyness if there are tasks, possibly of different workers, that may continue even if there is no change in IO readyness. In that case, it should rather poll.

To avoid blocking in this case, but without busy-waiting, a worker only blocks if no workers have pending tasks.

No type hierarchy, but rather loosely-coupled objects

E.g., there is a type for sockets (), tasks () homogeneous workers (task sets) (), heterogeneous workers () and listening sockets ().

A HTTP proxy connection task type may be composed of single sHT_task and two sHT_task. If a callback's argument is a pointer to an sHT_task, a pointer to the embedding structure can be calculated by sHT_container_of ().

TODO Allow multiple streams within a task.

Structure of workers

A worker has some structures for using the kernel's readyness notification mechanism and a queue of tasks to do.

It is assumed that the number of tasks in a heterogeneous worker is epsilon, such that we can do a simple loop over all tasks and always perform them (to avoid all indirect calls and provide a stable ordering).

When a task is performed, it is passed the worker it is in. (Although it is not disallowed, there is no explicit support for tasks being in multiple workers at the same time.)

Telling a worker what to do

TODO

Legal

Copyright (C) 2018 Ariadne Devos

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.