1 | /* pthread_atfork supports handlers that call pthread_atfork or dlclose. |
2 | Copyright (C) 2022-2024 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
5 | The GNU C Library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with the GNU C Library; if not, see |
17 | <https://www.gnu.org/licenses/>. */ |
18 | |
19 | #include <support/xdlfcn.h> |
20 | #include <stdio.h> |
21 | #include <support/xthread.h> |
22 | #include <sys/types.h> |
23 | #include <sys/wait.h> |
24 | #include <support/xunistd.h> |
25 | #include <support/check.h> |
26 | #include <stdlib.h> |
27 | |
28 | static void * |
29 | thread_func (void *x) |
30 | { |
31 | return NULL; |
32 | } |
33 | |
34 | static unsigned int second_atfork_handler_runcount = 0; |
35 | |
36 | static void |
37 | second_atfork_handler (void) |
38 | { |
39 | second_atfork_handler_runcount++; |
40 | } |
41 | |
42 | static void *h = NULL; |
43 | |
44 | static unsigned int atfork_handler_runcount = 0; |
45 | |
46 | static void |
47 | prepare (void) |
48 | { |
49 | /* These atfork handlers are registered while atfork handlers are being |
50 | executed and thus will not be executed during the corresponding |
51 | fork. */ |
52 | TEST_VERIFY_EXIT (pthread_atfork (second_atfork_handler, |
53 | second_atfork_handler, |
54 | second_atfork_handler) == 0); |
55 | |
56 | /* This will de-register the atfork handlers registered by the dlopen'd |
57 | library and so they will not be executed. */ |
58 | if (h != NULL) |
59 | { |
60 | xdlclose (handle: h); |
61 | h = NULL; |
62 | } |
63 | |
64 | atfork_handler_runcount++; |
65 | } |
66 | |
67 | static void |
68 | after (void) |
69 | { |
70 | atfork_handler_runcount++; |
71 | } |
72 | |
73 | static int |
74 | do_test (void) |
75 | { |
76 | /* Make sure __libc_single_threaded is 0. */ |
77 | pthread_attr_t attr; |
78 | xpthread_attr_init (attr: &attr); |
79 | xpthread_attr_setdetachstate (attr: &attr, PTHREAD_CREATE_DETACHED); |
80 | xpthread_create (attr: &attr, thread_func, NULL); |
81 | |
82 | void (*reg_atfork_handlers) (void); |
83 | |
84 | h = xdlopen (filename: "tst-atfork4mod.so" , RTLD_LAZY); |
85 | |
86 | reg_atfork_handlers = xdlsym (handle: h, symbol: "reg_atfork_handlers" ); |
87 | |
88 | reg_atfork_handlers (); |
89 | |
90 | /* We register our atfork handlers *after* loading the module so that our |
91 | prepare handler is called first at fork, where we then dlclose the |
92 | module before its prepare handler has a chance to be called. */ |
93 | TEST_VERIFY_EXIT (pthread_atfork (prepare, after, after) == 0); |
94 | |
95 | pid_t pid = xfork (); |
96 | |
97 | /* Both the parent and the child processes should observe this. */ |
98 | TEST_VERIFY_EXIT (atfork_handler_runcount == 2); |
99 | TEST_VERIFY_EXIT (second_atfork_handler_runcount == 0); |
100 | |
101 | if (pid > 0) |
102 | { |
103 | int childstat; |
104 | |
105 | xwaitpid (-1, status: &childstat, flags: 0); |
106 | TEST_VERIFY_EXIT (WIFEXITED (childstat) |
107 | && WEXITSTATUS (childstat) == 0); |
108 | |
109 | /* This time, the second set of atfork handlers should also be called |
110 | since the handlers are already in place before fork is called. */ |
111 | |
112 | pid = xfork (); |
113 | |
114 | TEST_VERIFY_EXIT (atfork_handler_runcount == 4); |
115 | TEST_VERIFY_EXIT (second_atfork_handler_runcount == 2); |
116 | |
117 | if (pid > 0) |
118 | { |
119 | xwaitpid (-1, status: &childstat, flags: 0); |
120 | TEST_VERIFY_EXIT (WIFEXITED (childstat) |
121 | && WEXITSTATUS (childstat) == 0); |
122 | } |
123 | } |
124 | |
125 | return 0; |
126 | } |
127 | |
128 | #include <support/test-driver.c> |
129 | |