]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/async.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / basic / async.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
c65eb836 2
11c3a366 3#include <errno.h>
c65eb836 4#include <pthread.h>
11c3a366 5#include <stddef.h>
c65eb836
LP
6#include <unistd.h>
7
f485606b 8#include "async.h"
3ffd4af2 9#include "fd-util.h"
f485606b 10#include "log.h"
11c3a366 11#include "macro.h"
41bd3379
LP
12#include "process-util.h"
13#include "signal-util.h"
8a474b0c 14#include "util.h"
c65eb836 15
f485606b 16int asynchronous_job(void* (*func)(void *p), void *arg) {
5e9f01e8 17 sigset_t ss, saved_ss;
c65eb836
LP
18 pthread_attr_t a;
19 pthread_t t;
5e9f01e8 20 int r, k;
c65eb836 21
5e9f01e8
LP
22 /* It kinda sucks that we have to resort to threads to implement an asynchronous close(), but well, such is
23 * life. */
c65eb836
LP
24
25 r = pthread_attr_init(&a);
c1d630d5 26 if (r > 0)
c65eb836
LP
27 return -r;
28
29 r = pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
5e9f01e8
LP
30 if (r > 0) {
31 r = -r;
32 goto finish;
33 }
34
cd2a429e 35 assert_se(sigfillset(&ss) >= 0);
5e9f01e8
LP
36
37 /* Block all signals before forking off the thread, so that the new thread is started with all signals
38 * blocked. This way the existence of the new thread won't affect signal handling in other threads. */
39
40 r = pthread_sigmask(SIG_BLOCK, &ss, &saved_ss);
41 if (r > 0) {
42 r = -r;
c65eb836 43 goto finish;
5e9f01e8 44 }
c65eb836 45
f485606b 46 r = pthread_create(&t, &a, func, arg);
c65eb836 47
5e9f01e8
LP
48 k = pthread_sigmask(SIG_SETMASK, &saved_ss, NULL);
49
50 if (r > 0)
51 r = -r;
52 else if (k > 0)
53 r = -k;
54 else
55 r = 0;
56
c65eb836
LP
57finish:
58 pthread_attr_destroy(&a);
5e9f01e8 59 return r;
c65eb836 60}
f485606b 61
d00c2631 62int asynchronous_sync(pid_t *ret_pid) {
4c253ed1 63 int r;
41bd3379
LP
64
65 /* This forks off an invocation of fork() as a child process, in order to initiate synchronization to
66 * disk. Note that we implement this as helper process rather than thread as we don't want the sync() to hang our
67 * original process ever, and a thread would do that as the process can't exit with threads hanging in blocking
68 * syscalls. */
69
d00c2631 70 r = safe_fork("(sd-sync)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, ret_pid);
4c253ed1
LP
71 if (r < 0)
72 return r;
73 if (r == 0) {
41bd3379 74 /* Child process */
41bd3379
LP
75 (void) sync();
76 _exit(EXIT_SUCCESS);
77 }
f485606b 78
41bd3379 79 return 0;
f485606b 80}
8a474b0c
LP
81
82static void *close_thread(void *p) {
fa7ff4cf
LP
83 (void) pthread_setname_np(pthread_self(), "close");
84
23e096cc 85 assert_se(close_nointr(PTR_TO_FD(p)) != -EBADF);
8a474b0c
LP
86 return NULL;
87}
88
89int asynchronous_close(int fd) {
90 int r;
91
92 /* This is supposed to behave similar to safe_close(), but
93 * actually invoke close() asynchronously, so that it will
94 * never block. Ideally the kernel would have an API for this,
95 * but it doesn't, so we work around it, and hide this as a
96 * far away as we can. */
97
5ed12272
LP
98 if (fd >= 0) {
99 PROTECT_ERRNO;
100
23e096cc 101 r = asynchronous_job(close_thread, FD_TO_PTR(fd));
5ed12272
LP
102 if (r < 0)
103 assert_se(close_nointr(fd) != -EBADF);
104 }
8a474b0c
LP
105
106 return -1;
107}