написание и упаковка системных демонов (Writing and packaging system daemons)
ACTIVATION
New-style init systems provide multiple additional mechanisms to
activate services, as detailed below. It is common that services
are configured to be activated via more than one mechanism at the
same time. An example for systemd: bluetoothd.service might get
activated either when Bluetooth hardware is plugged in, or when
an application accesses its programming interfaces via D-Bus. Or,
a print server daemon might get activated when traffic arrives at
an IPP port, or when a printer is plugged in, or when a file is
queued in the printer spool directory. Even for services that are
intended to be started on system bootup unconditionally, it is a
good idea to implement some of the various activation schemes
outlined below, in order to maximize parallelization. If a daemon
implements a D-Bus service or listening socket, implementing the
full bus and socket activation scheme allows starting of the
daemon with its clients in parallel (which speeds up boot-up),
since all its communication channels are established already, and
no request is lost because client requests will be queued by the
bus system (in case of D-Bus) or the kernel (in case of sockets)
until the activation is completed.
Activation on Boot
Old-style daemons are usually activated exclusively on boot (and
manually by the administrator) via SysV init scripts, as detailed
in the LSB Linux Standard Base Core Specification
[1]. This method
of activation is supported ubiquitously on Linux init systems,
both old-style and new-style systems. Among other issues, SysV
init scripts have the disadvantage of involving shell scripts in
the boot process. New-style init systems generally employ updated
versions of activation, both during boot-up and during runtime
and using more minimal service description files.
In systemd, if the developer or administrator wants to make sure
that a service or other unit is activated automatically on boot,
it is recommended to place a symlink to the unit file in the
.wants/ directory of either multi-user.target or
graphical.target, which are normally used as boot targets at
system startup. See systemd.unit(5) for details about the .wants/
directories, and systemd.special(7) for details about the two
boot targets.
Socket-Based Activation
In order to maximize the possible parallelization and robustness
and simplify configuration and development, it is recommended for
all new-style daemons that communicate via listening sockets to
employ socket-based activation. In a socket-based activation
scheme, the creation and binding of the listening socket as
primary communication channel of daemons to local (and sometimes
remote) clients is moved out of the daemon code and into the init
system. Based on per-daemon configuration, the init system
installs the sockets and then hands them off to the spawned
process as soon as the respective daemon is to be started.
Optionally, activation of the service can be delayed until the
first inbound traffic arrives at the socket to implement
on-demand activation of daemons. However, the primary advantage
of this scheme is that all providers and all consumers of the
sockets can be started in parallel as soon as all sockets are
established. In addition to that, daemons can be restarted with
losing only a minimal number of client transactions, or even any
client request at all (the latter is particularly true for
state-less protocols, such as DNS or syslog), because the socket
stays bound and accessible during the restart, and all requests
are queued while the daemon cannot process them.
New-style daemons which support socket activation must be able to
receive their sockets from the init system instead of creating
and binding them themselves. For details about the programming
interfaces for this scheme provided by systemd, see
sd_listen_fds(3) and sd-daemon(3). For details about porting
existing daemons to socket-based activation, see below. With
minimal effort, it is possible to implement socket-based
activation in addition to traditional internal socket creation in
the same codebase in order to support both new-style and
old-style init systems from the same daemon binary.
systemd implements socket-based activation via .socket units,
which are described in systemd.socket(5). When configuring socket
units for socket-based activation, it is essential that all
listening sockets are pulled in by the special target unit
sockets.target. It is recommended to place a
WantedBy=sockets.target directive in the [Install] section to
automatically add such a dependency on installation of a socket
unit. Unless DefaultDependencies=no is set, the necessary
ordering dependencies are implicitly created for all socket
units. For more information about sockets.target, see
systemd.special(7). It is not necessary or recommended to place
any additional dependencies on socket units (for example from
multi-user.target or suchlike) when one is installed in
sockets.target.
Bus-Based Activation
When the D-Bus IPC system is used for communication with clients,
new-style daemons should employ bus activation so that they are
automatically activated when a client application accesses their
IPC interfaces. This is configured in D-Bus service files (not to
be confused with systemd service unit files!). To ensure that
D-Bus uses systemd to start-up and maintain the daemon, use the
SystemdService= directive in these service files to configure the
matching systemd service for a D-Bus service. e.g.: For a D-Bus
service whose D-Bus activation file is named
org.freedesktop.RealtimeKit.service, make sure to set
SystemdService=rtkit-daemon.service in that file to bind it to
the systemd service rtkit-daemon.service. This is needed to make
sure that the daemon is started in a race-free fashion when
activated via multiple mechanisms simultaneously.
Device-Based Activation
Often, daemons that manage a particular type of hardware should
be activated only when the hardware of the respective kind is
plugged in or otherwise becomes available. In a new-style init
system, it is possible to bind activation to hardware plug/unplug
events. In systemd, kernel devices appearing in the sysfs/udev
device tree can be exposed as units if they are tagged with the
string "systemd". Like any other kind of unit, they may then pull
in other units when activated (i.e. plugged in) and thus
implement device-based activation. systemd dependencies may be
encoded in the udev database via the SYSTEMD_WANTS= property. See
systemd.device(5) for details. Often, it is nicer to pull in
services from devices only indirectly via dedicated targets.
Example: Instead of pulling in bluetoothd.service from all the
various bluetooth dongles and other hardware available, pull in
bluetooth.target from them and bluetoothd.service from that
target. This provides for nicer abstraction and gives
administrators the option to enable bluetoothd.service via
controlling a bluetooth.target.wants/ symlink uniformly with a
command like enable
of systemctl(1) instead of manipulating the
udev ruleset.
Path-Based Activation
Often, runtime of daemons processing spool files or directories
(such as a printing system) can be delayed until these file
system objects change state, or become non-empty. New-style init
systems provide a way to bind service activation to file system
changes. systemd implements this scheme via path-based activation
configured in .path units, as outlined in systemd.path(5).
Timer-Based Activation
Some daemons that implement clean-up jobs that are intended to be
executed in regular intervals benefit from timer-based
activation. In systemd, this is implemented via .timer units, as
described in systemd.timer(5).
Other Forms of Activation
Other forms of activation have been suggested and implemented in
some systems. However, there are often simpler or better
alternatives, or they can be put together of combinations of the
schemes above. Example: Sometimes, it appears useful to start
daemons or .socket units when a specific IP address is configured
on a network interface, because network sockets shall be bound to
the address. However, an alternative to implement this is by
utilizing the Linux IP_FREEBIND
/IPV6_FREEBIND
socket option, as
accessible via FreeBind=yes in systemd socket files (see
systemd.socket(5) for details). This option, when enabled, allows
sockets to be bound to a non-local, not configured IP address,
and hence allows bindings to a particular IP address before it
actually becomes available, making such an explicit dependency to
the configured address redundant. Another often suggested trigger
for service activation is low system load. However, here too, a
more convincing approach might be to make proper use of features
of the operating system, in particular, the CPU or I/O scheduler
of Linux. Instead of scheduling jobs from userspace based on
monitoring the OS scheduler, it is advisable to leave the
scheduling of processes to the OS scheduler itself. systemd
provides fine-grained access to the CPU and I/O schedulers. If a
process executed by the init system shall not negatively impact
the amount of CPU or I/O bandwidth available to other processes,
it should be configured with CPUSchedulingPolicy=idle and/or
IOSchedulingClass=idle. Optionally, this may be combined with
timer-based activation to schedule background jobs during runtime
and with minimal impact on the system, and remove it from the
boot phase itself.