]>
Commit | Line | Data |
---|---|---|
706ad1e7 | 1 | /* Test support for single-thread optimizations. With threads. |
581c785b | 2 | Copyright (C) 2020-2022 Free Software Foundation, Inc. |
706ad1e7 FW |
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 <stddef.h> | |
20 | #include <stdio.h> | |
21 | #include <support/check.h> | |
22 | #include <support/namespace.h> | |
23 | #include <support/xdlfcn.h> | |
24 | #include <support/xthread.h> | |
25 | #include <sys/single_threaded.h> | |
26 | ||
27 | /* First barrier synchronizes main thread, thread 1, thread 2. */ | |
28 | static pthread_barrier_t barrier1; | |
29 | ||
30 | /* Second barrier synchronizes main thread, thread 2. */ | |
31 | static pthread_barrier_t barrier2; | |
32 | ||
33 | /* Defined in tst-single-threaded-mod1.so. */ | |
34 | _Bool single_threaded_1 (void); | |
35 | ||
36 | /* Initialized via dlsym. */ | |
37 | static _Bool (*single_threaded_2) (void); | |
38 | static _Bool (*single_threaded_3) (void); | |
39 | static _Bool (*single_threaded_4) (void); | |
40 | ||
41 | static void * | |
42 | threadfunc (void *closure) | |
43 | { | |
44 | TEST_VERIFY (!__libc_single_threaded); | |
45 | TEST_VERIFY (!single_threaded_1 ()); | |
46 | TEST_VERIFY (!single_threaded_2 ()); | |
47 | ||
48 | /* Wait until the main thread loads more functions. */ | |
49 | xpthread_barrier_wait (&barrier1); | |
50 | ||
51 | TEST_VERIFY (!__libc_single_threaded); | |
52 | TEST_VERIFY (!single_threaded_1 ()); | |
53 | TEST_VERIFY (!single_threaded_2 ()); | |
54 | TEST_VERIFY (!single_threaded_3 ()); | |
55 | TEST_VERIFY (!single_threaded_4 ()); | |
56 | ||
57 | /* Second thread waits on second barrier, too. */ | |
58 | if (closure != NULL) | |
59 | xpthread_barrier_wait (&barrier2); | |
60 | TEST_VERIFY (!__libc_single_threaded); | |
61 | TEST_VERIFY (!single_threaded_1 ()); | |
62 | TEST_VERIFY (!single_threaded_2 ()); | |
63 | TEST_VERIFY (!single_threaded_3 ()); | |
64 | TEST_VERIFY (!single_threaded_4 ()); | |
65 | ||
66 | return NULL; | |
67 | } | |
68 | ||
69 | /* Used for closure arguments to the subprocess function. */ | |
70 | static char expected_false = 0; | |
71 | static char expected_true = 1; | |
72 | ||
73 | /* A subprocess inherits currently inherits the single-threaded state | |
74 | of the parent process. */ | |
75 | static void | |
76 | subprocess (void *closure) | |
77 | { | |
78 | const char *expected = closure; | |
79 | TEST_COMPARE (__libc_single_threaded, *expected); | |
80 | TEST_COMPARE (single_threaded_1 (), *expected); | |
81 | if (single_threaded_2 != NULL) | |
82 | TEST_COMPARE (single_threaded_2 (), *expected); | |
83 | if (single_threaded_3 != NULL) | |
84 | TEST_COMPARE (single_threaded_3 (), *expected); | |
85 | if (single_threaded_4 != NULL) | |
86 | TEST_VERIFY (!single_threaded_4 ()); | |
87 | } | |
88 | ||
89 | static int | |
90 | do_test (void) | |
91 | { | |
92 | printf ("info: main __libc_single_threaded address: %p\n", | |
93 | &__libc_single_threaded); | |
94 | TEST_VERIFY (__libc_single_threaded); | |
95 | TEST_VERIFY (single_threaded_1 ()); | |
96 | support_isolate_in_subprocess (subprocess, &expected_true); | |
97 | ||
98 | void *handle_mod2 = xdlopen ("tst-single_threaded-mod2.so", RTLD_LAZY); | |
99 | single_threaded_2 = xdlsym (handle_mod2, "single_threaded_2"); | |
100 | TEST_VERIFY (single_threaded_2 ()); | |
101 | ||
102 | /* Two threads plus main thread. */ | |
103 | xpthread_barrier_init (&barrier1, NULL, 3); | |
104 | ||
105 | /* Main thread and second thread. */ | |
106 | xpthread_barrier_init (&barrier2, NULL, 2); | |
107 | ||
108 | pthread_t thr1 = xpthread_create (NULL, threadfunc, NULL); | |
109 | TEST_VERIFY (!__libc_single_threaded); | |
110 | TEST_VERIFY (!single_threaded_1 ()); | |
111 | TEST_VERIFY (!single_threaded_2 ()); | |
112 | support_isolate_in_subprocess (subprocess, &expected_false); | |
113 | ||
114 | pthread_t thr2 = xpthread_create (NULL, threadfunc, &thr2); | |
115 | TEST_VERIFY (!__libc_single_threaded); | |
116 | TEST_VERIFY (!single_threaded_1 ()); | |
117 | TEST_VERIFY (!single_threaded_2 ()); | |
118 | support_isolate_in_subprocess (subprocess, &expected_false); | |
119 | ||
120 | /* Delayed library load, while already multi-threaded. */ | |
121 | void *handle_mod3 = xdlopen ("tst-single_threaded-mod3.so", RTLD_LAZY); | |
122 | single_threaded_3 = xdlsym (handle_mod3, "single_threaded_3"); | |
123 | TEST_VERIFY (!__libc_single_threaded); | |
124 | TEST_VERIFY (!single_threaded_1 ()); | |
125 | TEST_VERIFY (!single_threaded_2 ()); | |
126 | TEST_VERIFY (!single_threaded_3 ()); | |
127 | support_isolate_in_subprocess (subprocess, &expected_false); | |
128 | ||
129 | /* Same with dlmopen. */ | |
130 | void *handle_mod4 = dlmopen (LM_ID_NEWLM, "tst-single_threaded-mod4.so", | |
131 | RTLD_LAZY); | |
132 | single_threaded_4 = xdlsym (handle_mod4, "single_threaded_4"); | |
133 | TEST_VERIFY (!__libc_single_threaded); | |
134 | TEST_VERIFY (!single_threaded_1 ()); | |
135 | TEST_VERIFY (!single_threaded_2 ()); | |
136 | TEST_VERIFY (!single_threaded_3 ()); | |
137 | TEST_VERIFY (!single_threaded_4 ()); | |
138 | support_isolate_in_subprocess (subprocess, &expected_false); | |
139 | ||
140 | /* Run the newly loaded functions from the other threads as | |
141 | well. */ | |
142 | xpthread_barrier_wait (&barrier1); | |
143 | TEST_VERIFY (!__libc_single_threaded); | |
144 | TEST_VERIFY (!single_threaded_1 ()); | |
145 | TEST_VERIFY (!single_threaded_2 ()); | |
146 | TEST_VERIFY (!single_threaded_3 ()); | |
147 | TEST_VERIFY (!single_threaded_4 ()); | |
148 | support_isolate_in_subprocess (subprocess, &expected_false); | |
149 | ||
150 | /* Join first thread. This should not bring us back into | |
151 | single-threaded mode. */ | |
152 | xpthread_join (thr1); | |
153 | TEST_VERIFY (!__libc_single_threaded); | |
154 | TEST_VERIFY (!single_threaded_1 ()); | |
155 | TEST_VERIFY (!single_threaded_2 ()); | |
156 | TEST_VERIFY (!single_threaded_3 ()); | |
157 | TEST_VERIFY (!single_threaded_4 ()); | |
158 | support_isolate_in_subprocess (subprocess, &expected_false); | |
159 | ||
160 | /* We may be back in single-threaded mode after joining both | |
161 | threads, but this is not guaranteed. */ | |
162 | xpthread_barrier_wait (&barrier2); | |
163 | xpthread_join (thr2); | |
164 | printf ("info: __libc_single_threaded after joining all threads: %d\n", | |
165 | __libc_single_threaded); | |
166 | ||
167 | xdlclose (handle_mod4); | |
168 | xdlclose (handle_mod3); | |
169 | xdlclose (handle_mod2); | |
170 | ||
171 | return 0; | |
172 | } | |
173 | ||
174 | #include <support/test-driver.c> |