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