Line data Source code
1 : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2 :
3 : /***
4 : This file is part of systemd.
5 :
6 : Copyright 2013 Lennart Poettering
7 :
8 : systemd is free software; you can redistribute it and/or modify it
9 : under the terms of the GNU Lesser General Public License as published by
10 : the Free Software Foundation; either version 2.1 of the License, or
11 : (at your option) any later version.
12 :
13 : systemd is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : Lesser General Public License for more details.
17 :
18 : You should have received a copy of the GNU Lesser General Public License
19 : along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 : ***/
21 :
22 : #include <pthread.h>
23 : #include <unistd.h>
24 :
25 : #include "async.h"
26 : #include "log.h"
27 : #include "util.h"
28 :
29 11 : int asynchronous_job(void* (*func)(void *p), void *arg) {
30 : pthread_attr_t a;
31 : pthread_t t;
32 : int r;
33 :
34 : /* It kinda sucks that we have to resort to threads to
35 : * implement an asynchronous sync(), but well, such is
36 : * life.
37 : *
38 : * Note that issuing this command right before exiting a
39 : * process will cause the process to wait for the sync() to
40 : * complete. This function hence is nicely asynchronous really
41 : * only in long running processes. */
42 :
43 11 : r = pthread_attr_init(&a);
44 11 : if (r > 0)
45 0 : return -r;
46 :
47 11 : r = pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
48 11 : if (r > 0)
49 0 : goto finish;
50 :
51 11 : r = pthread_create(&t, &a, func, arg);
52 :
53 : finish:
54 11 : pthread_attr_destroy(&a);
55 11 : return -r;
56 : }
57 :
58 1 : static void *sync_thread(void *p) {
59 1 : sync();
60 1 : return NULL;
61 : }
62 :
63 1 : int asynchronous_sync(void) {
64 1 : log_debug("Spawning new thread for sync");
65 :
66 1 : return asynchronous_job(sync_thread, NULL);
67 : }
68 :
69 8 : static void *close_thread(void *p) {
70 8 : assert_se(close_nointr(PTR_TO_INT(p)) != -EBADF);
71 8 : return NULL;
72 : }
73 :
74 49 : int asynchronous_close(int fd) {
75 : int r;
76 :
77 : /* This is supposed to behave similar to safe_close(), but
78 : * actually invoke close() asynchronously, so that it will
79 : * never block. Ideally the kernel would have an API for this,
80 : * but it doesn't, so we work around it, and hide this as a
81 : * far away as we can. */
82 :
83 49 : if (fd >= 0) {
84 16 : PROTECT_ERRNO;
85 :
86 8 : r = asynchronous_job(close_thread, INT_TO_PTR(fd));
87 8 : if (r < 0)
88 0 : assert_se(close_nointr(fd) != -EBADF);
89 : }
90 :
91 49 : return -1;
92 : }
|