Age | Commit message (Collapse) | Author |
|
This Pty API wraps the ugliness that is POSIX PTY. It takes care of:
- edge-triggered HUP handling (avoid heavy CPU-usage on vhangup)
- HUP vs. input-queue draining (handle HUP _after_ draining the whole
input queue)
- SIGCHLD vs. HUP (HUP is no reliable way to catch PTY deaths, always
use SIGCHLD. Otherwise, vhangup() and friends will break.)
- Output queue buffering (async EPOLLOUT handling)
- synchronous setup (via Barrier API)
At the same time, the PTY API does not execve(). It simply fork()s and
leaves everything else to the caller. Usually, they execve() but we
support other setups, too.
This will be needed by multiple UI binaries (systemd-console, systemd-er,
...) so it's placed in src/shared/. It's not strictly related to
libsystemd-terminal, so it's not included there.
|
|
The Barrier-API simplifies cross-fork() synchronization a lot. Replace the
hard-coded eventfd-util implementation and drop it.
Compared to the old API, Barriers also handle exit() of the remote side as
abortion. This way, segfaults will not cause the parent to deadlock.
EINTR handling is currently ignored for any barrier-waits. This can easily
be added, but it isn't needed so far so I dropped it. EINTR handling in
general is ugly, anyway. You need to deal with pselect/ppoll/... variants
and make sure not to unblock signals at the wrong times. So genrally,
there's little use in adding it.
|
|
The "Barrier" object is a simple inter-process barrier implementation. It
allows placing synchronization points and waiting for the other side to
reach it. Additionally, it has an abortion-mechanism as second-layer
synchronization to send abortion-events asynchronously to the other side.
The API is usually used to synchronize processes during fork(). However,
it can be extended to pass state through execve() so you could synchronize
beyond execve().
Usually, it's used like this (error-handling replaced by assert() for
simplicity):
Barrier b;
r = barrier_init(&b);
assert_se(r >= 0);
pid = fork();
assert_se(pid >= 0);
if (pid == 0) {
barrier_set_role(&b, BARRIER_CHILD);
...do child post-setup...
if (CHILD_SETUP_FAILED)
exit(1);
...child setup done...
barrier_place(&b);
if (!barrier_sync(&b)) {
/* parent setup failed */
exit(1);
}
barrier_destroy(&b); /* redundant as execve() and exit() imply this */
/* parent & child setup successful */
execve(...);
}
barrier_set_role(&b, BARRIER_PARENT);
...do parent post-setup...
if (PARENT_SETUP_FAILED) {
barrier_abort(&b); /* send abortion event */
barrier_wait_abortion(&b); /* wait for child to abort (exit() implies abortion) */
barrier_destroy(&b);
...bail out...
}
...parent setup done...
barrier_place(&b);
if (!barrier_sync(&b)) {
...child setup failed... ;
barrier_destroy(&b);
...bail out...
}
barrier_destroy(&b);
...child setup successfull...
This is the most basic API. Using barrier_place() to place barriers and
barrier_sync() to perform a full synchronization between both processes.
barrier_abort() places an abortion barrier which superceeds any other
barriers, exit() (or barrier_destroy()) places an abortion-barrier that
queues behind existing barriers (thus *not* replacing existing barriers
unlike barrier_abort()).
This example uses hard-synchronization with wait_abortion(), sync() and
friends. These are all optional. Barriers are highly dynamic and can be
used for one-way synchronization or even no synchronization at all
(postponing it for later). The sync() call performs a full two-way
synchronization.
The API is documented and should be fairly self-explanatory. A test-suite
shows some special semantics regarding abortion, wait_next() and exit().
Internally, barriers use two eventfds and a pipe. The pipe is used to
detect exit()s of the remote side as eventfds do not allow that. The
eventfds are used to place barriers, one for each side. Barriers itself
are numbered, but the numbers are reused once both sides reached the same
barrier, thus you cannot address barriers by the index. Moreover, the
numbering is implicit and we only store a counter. This makes the
implementation itself very lightweight, which is probably negligible
considering that we need 3 FDs for a barrier..
Last but not least: This barrier implementation is quite heavy. It's
definitely not meant for fast IPC synchronization. However, it's very easy
to use. And given the *HUGE* overhead of fork(), the barrier-overhead
should be negligible.
|
|
inotify_add_watch returns ENOSPC, which translates to
"No space left on device", which is misleading.
https://bugs.freedesktop.org/show_bug.cgi?id=73628
|
|
https://bugs.freedesktop.org/show_bug.cgi?id=81158
|
|
|
|
So far both "indexes" and "indices" was used. Let's clean this up, and
stick to indices, since it appears to be used more frequently.
|
|
makes things a bit clearer and avoids any clashes with libc's index()
symbol.
|
|
That way, we can deprecate fields later on without problems
|
|
arrays
As long as the number of array entries is relatively small it's nicer to
simply return the number of entries directly, instead of using a size_t*
return parameter for it.
|
|
|
|
|
|
|
|
|
|
Constructors should return the object they created as first parameter,
except when they are generated as a child/member object of some other
object in which case that should be first.
|
|
|
|
Before, fragments of the progress bar would remain when
errors or warnings were printed.
|
|
One missing string found.
A few things had to be moved around to make it possible to test them.
|
|
|
|
If we want to avoid reading a totally empty file, it seems better
to check after we have opened the file, not before.
|
|
Special care is needed so that we get an error message if the
file failed to parse, but not when it is missing. To avoid duplicating
the same error check in every caller, add an additional 'warn' boolean
to tell config_parse whether a message should be issued.
This makes things both shorter and more robust wrt. to error reporting.
|
|
|
|
|
|
Also, hook up nss-resolve to make use of this information
|
|
|
|
Now we are getting into kernel < 3.4 territory...
https://bugs.freedesktop.org/show_bug.cgi?id=80095
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
It depends on libgobject and libgmodule which are installed in /usr/lib.
|
|
|
|
|
|
For pluggable ttys such as USB serial devices, the getty is restarted
and exits in a loop until the remove event reaches systemd. Under
certain circumstances the restart loop can overload the system in a
way that prevents the remove event from reaching systemd for a long
time (e.g. at least several minutes on a small embedded system).
Use the default RestartSec to prevent the restart loop from
overloading the system. Serial gettys are interactive units, so
waiting an extra 100ms really doesn't make a difference anyways
compared to the time it takes the user to log in.
|
|
|
|
and btw make it pass for 32bits where size_t != uint64_t
|
|
Instead of copying fields into new memory allocations, simply keep pointers
into the receive buffer. Data in this buffer is only copied when there is not
enough space for new data and a large chunk of the buffer contains old data.
|
|
Define DATA_SIZE_MAX to mean the maximum size of a single
field, and ENTRY_SIZE_MAX to mean the size of the whole
entry, with some rough calculation of overhead over the payload.
Check if entries are not too big when processing native journal
messages.
|
|
|
|
|
|
|
|
|
|
We can append /upload ourselves.
|
|
|
|
|