summaryrefslogtreecommitdiffstats
path: root/src/shared/barrier.c (follow)
Commit message (Collapse)AuthorAgeFilesLines
* shared/barrier: remove parensZbigniew Jędrzejewski-Szmek2023-08-161-2/+2
|
* tree-wide: modernizations with RET_NERRNO()Lennart Poettering2022-11-221-3/+1
|
* tree-wide: use ERRNO_IS_TRANSIENT()Yu Watanabe2021-11-301-2/+3
|
* tree-wide: mark set-but-not-used variables as unused to make LLVM happyFrantisek Sumsal2021-09-151-1/+1
| | | | | | | | | | | | | | LLVM 13 introduced `-Wunused-but-set-variable` diagnostic flag, which trips over some intentionally set-but-not-used variables or variables attached to cleanup handlers with side effects (`_cleanup_umask_`, `_cleanup_(notify_on_cleanup)`, `_cleanup_(restore_sigsetp)`, etc.): ``` ../src/basic/process-util.c:1257:46: error: variable 'saved_ssp' set but not used [-Werror,-Wunused-but-set-variable] _cleanup_(restore_sigsetp) sigset_t *saved_ssp = NULL; ^ 1 error generated. ```
* tree-wide: use ppoll_usec()Yu Watanabe2021-03-031-9/+5
|
* tree-wide: return NULL from freeing functionsZbigniew Jędrzejewski-Szmek2021-02-161-2/+3
| | | | | | I started working on this because I wanted to change how DEFINE_TRIVIAL_CLEANUP_FUNC is defined. Even independently of that change, it's nice to make make things more consistent and predictable.
* license: LGPL-2.1+ -> LGPL-2.1-or-laterYu Watanabe2020-11-091-1/+1
|
* tree-wide: check POLLNVAL everywhereLennart Poettering2020-06-101-4/+8
| | | | | | | | | | | | | poll() sets POLLNVAL inside of the poll structures if an invalid fd is passed. So far we generally didn't check for that, thus not taking notice of the error. Given that this specific kind of error is generally indication of a programming error, and given that our code is embedded into our projects via NSS or because people link against our library, let's explicitly check for this and convert it to EBADF. (I ran into a busy loop because of this missing check when some of my test code accidentally closed an fd it shouldn't close, so this is a real thing)
* tree-wide: use SWAP_TWO a bit moreLennart Poettering2018-11-261-5/+1
|
* Move various files that don't need to be in basic/ to shared/Zbigniew Jędrzejewski-Szmek2018-11-201-0/+398
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This doesn't have much effect on the final build, because we link libbasic.a into libsystemd-shared.so, so in the end, all the object built from basic/ end up in libsystemd-shared. And when the static library is linked into binaries, any objects that are included in it but are not used are trimmed. Hence, the size of output artifacts doesn't change: $ du -sb /var/tmp/inst* 54181861 /var/tmp/inst1 (old) 54207441 /var/tmp/inst1s (old split-usr) 54182477 /var/tmp/inst2 (new) 54208041 /var/tmp/inst2s (new split-usr) (The negligible change in size is because libsystemd-shared.so is bigger by a few hundred bytes. I guess it's because symbols are named differently or something like that.) The effect is on the build process, in particular partial builds. This change effectively moves the requirements on some build steps toward the leaves of the dependency tree. Two effects: - when building items that do not depend on libsystemd-shared, we build less stuff for libbasic.a (which wouldn't be used anyway, so it's a net win). - when building items that do depend on libshared, we reduce libbasic.a as a synchronization point, possibly allowing better parallelism. Method: 1. copy list of .h files from src/basic/meson.build to /tmp/basic 2. $ for i in $(grep '.h$' /tmp/basic); do echo $i; git --no-pager grep "include \"$i\"" src/basic/ 'src/lib*' 'src/nss-*' 'src/journal/sd-journal.c' |grep -v "${i%.h}.c";echo ;done | less
* build-sys: split internal basic/ library from shared/Kay Sievers2015-06-111-416/+0
| | | | | | | | | | basic/ can be used by everything cannot use anything outside of basic/ libsystemd/ can use basic/ cannot use shared/ shared/ can use libsystemd/
* treewide: Correct typos and spell plural of bus consistentTorstein Husebø2015-05-111-1/+1
|
* shared: fix wrong assertion in barrier_set_role()Cristian Rodríguez2015-02-241-1/+1
| | | | | | | | assert(b->pipe[0] >= 0 && b->pipe[0] >= 0); Test the same condition twice, pretty sure we mean assert(b->pipe[0] >= 0 && b->pipe[1] >= 0);
* remove unused includesThomas Hindoe Paaboel Andersen2015-02-231-3/+0
| | | | | | This patch removes includes that are not used. The removals were found with include-what-you-use which checks if any of the symbols from a header is in use.
* barrier: fix up constructor error handlingDavid Herrmann2014-10-021-5/+14
| | | | | | | | | We cannot rely on "errno" to be non-zero on failure, if we perform multiple glibc calls. That is, if the first eventfd() call fails, but the second succeeds, we cleanup the barrier but return 0. Fix this by always testing the return value immediately. This should also fix all the coverity warnings.
* barrier: suppress false-positive warningDavid Herrmann2014-07-191-0/+2
| | | | | | If poll() returns, one of both revents must be set, thus "buf" is set by either clause. This is non-obvious for code-checkers so add an "else continue;" clause to suppress "uninitialized variable" warnings.
* barrier: initalize file descriptors with -1Zbigniew Jędrzejewski-Szmek2014-07-191-73/+41
| | | | | | | | | | | Explicitly initalize descriptors using explicit assignment like bus_error. This makes barriers follow the same conventions as everything else and makes things a bit simpler too. Rename barier_init to barier_create so it is obvious that it is not about initialization. Remove some parens, etc.
* shared: add generic IPC barrierDavid Herrmann2014-07-171-0/+440
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.