Branch data Line data Source code
1 : : /* Unit tests for GThread
2 : : * Copyright (C) 2011 Red Hat, Inc
3 : : * Author: Matthias Clasen
4 : : *
5 : : * SPDX-License-Identifier: LicenseRef-old-glib-tests
6 : : *
7 : : * This work is provided "as is"; redistribution and modification
8 : : * in whole or in part, in any medium, physical or electronic is
9 : : * permitted without restriction.
10 : : *
11 : : * This work is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 : : *
15 : : * In no event shall the authors or contributors be liable for any
16 : : * direct, indirect, incidental, special, exemplary, or consequential
17 : : * damages (including, but not limited to, procurement of substitute
18 : : * goods or services; loss of use, data, or profits; or business
19 : : * interruption) however caused and on any theory of liability, whether
20 : : * in contract, strict liability, or tort (including negligence or
21 : : * otherwise) arising in any way out of the use of this software, even
22 : : * if advised of the possibility of such damage.
23 : : */
24 : :
25 : : #include <config.h>
26 : : #include <errno.h>
27 : :
28 : : #ifdef HAVE_SYS_TIME_H
29 : : #include <sys/time.h>
30 : : #endif
31 : : #include <sys/types.h>
32 : : #ifdef HAVE_SYS_PRCTL_H
33 : : #include <sys/prctl.h>
34 : : #endif
35 : :
36 : : #include <glib.h>
37 : :
38 : : #include "glib/glib-private.h"
39 : :
40 : : #ifdef G_OS_UNIX
41 : : #include <unistd.h>
42 : : #include <sys/resource.h>
43 : : #endif
44 : :
45 : : #ifdef THREADS_POSIX
46 : : #include <pthread.h>
47 : : #endif
48 : :
49 : : static gpointer
50 : 1 : thread1_func (gpointer data)
51 : : {
52 : 1 : g_thread_exit (GINT_TO_POINTER (1));
53 : :
54 : : g_assert_not_reached ();
55 : :
56 : : return NULL;
57 : : }
58 : :
59 : : /* test that g_thread_exit() works */
60 : : static void
61 : 1 : test_thread1 (void)
62 : : {
63 : : gpointer result;
64 : : GThread *thread;
65 : 1 : GError *error = NULL;
66 : :
67 : 1 : thread = g_thread_try_new ("test", thread1_func, NULL, &error);
68 : 1 : g_assert_no_error (error);
69 : :
70 : 1 : result = g_thread_join (thread);
71 : :
72 : 1 : g_assert_cmpint (GPOINTER_TO_INT (result), ==, 1);
73 : 1 : }
74 : :
75 : : static gpointer
76 : 1 : thread2_func (gpointer data)
77 : : {
78 : 1 : return g_thread_self ();
79 : : }
80 : :
81 : : /* test that g_thread_self() works */
82 : : static void
83 : 1 : test_thread2 (void)
84 : : {
85 : : gpointer result;
86 : : GThread *thread;
87 : :
88 : 1 : thread = g_thread_new ("test", thread2_func, NULL);
89 : :
90 : 1 : g_assert (g_thread_self () != thread);
91 : :
92 : 1 : result = g_thread_join (thread);
93 : :
94 : 1 : g_assert (result == thread);
95 : 1 : }
96 : :
97 : : static gpointer
98 : 4 : thread3_func (gpointer data)
99 : : {
100 : 4 : GThread *peer = data;
101 : : gint retval;
102 : :
103 : 4 : retval = 3;
104 : :
105 [ + + ]: 4 : if (peer)
106 : : {
107 : : gpointer result;
108 : :
109 : 2 : result = g_thread_join (peer);
110 : :
111 : 2 : retval += GPOINTER_TO_INT (result);
112 : : }
113 : :
114 : 4 : return GINT_TO_POINTER (retval);
115 : : }
116 : :
117 : : /* test that g_thread_join() works across peers */
118 : : static void
119 : 1 : test_thread3 (void)
120 : : {
121 : : gpointer result;
122 : : GThread *thread1, *thread2, *thread3;
123 : :
124 : 1 : thread1 = g_thread_new ("a", thread3_func, NULL);
125 : 1 : thread2 = g_thread_new ("b", thread3_func, thread1);
126 : 1 : thread3 = g_thread_new ("c", thread3_func, thread2);
127 : :
128 : 1 : result = g_thread_join (thread3);
129 : :
130 : 1 : g_assert_cmpint (GPOINTER_TO_INT(result), ==, 9);
131 : 1 : }
132 : :
133 : : /* test that thread creation fails as expected,
134 : : * by setting RLIMIT_NPROC ridiculously low
135 : : */
136 : : static void
137 : 1 : test_thread4 (void)
138 : : {
139 : : #ifdef _GLIB_ADDRESS_SANITIZER
140 : : g_test_incomplete ("FIXME: Leaks a GSystemThread's name, see glib#2308");
141 : : #elif defined(HAVE_PRLIMIT)
142 : : struct rlimit ol, nl;
143 : : GThread *thread;
144 : : GError *error;
145 : :
146 : 1 : getrlimit (RLIMIT_NPROC, &nl);
147 : 1 : nl.rlim_cur = 1;
148 : :
149 [ - + ]: 1 : if (prlimit (getpid (), RLIMIT_NPROC, &nl, &ol) != 0)
150 : 0 : g_error ("setting RLIMIT_NPROC to {cur=%ld,max=%ld} failed: %s",
151 : : (long) nl.rlim_cur, (long) nl.rlim_max, g_strerror (errno));
152 : :
153 : 1 : error = NULL;
154 : 1 : thread = g_thread_try_new ("a", thread1_func, NULL, &error);
155 : :
156 [ - + ]: 1 : if (thread != NULL)
157 : : {
158 : : gpointer result;
159 : :
160 : : /* Privileged processes might be able to create new threads even
161 : : * though the rlimit is too low. There isn't much we can do about
162 : : * this; we just can't test this failure mode in this situation. */
163 : 0 : g_test_skip ("Unable to test g_thread_try_new() failing with EAGAIN "
164 : : "while privileged (CAP_SYS_RESOURCE, CAP_SYS_ADMIN or "
165 : : "euid 0?)");
166 : 0 : result = g_thread_join (thread);
167 : 0 : g_assert_cmpint (GPOINTER_TO_INT (result), ==, 1);
168 : : }
169 : : else
170 : : {
171 : 1 : g_assert (thread == NULL);
172 : 1 : g_assert_error (error, G_THREAD_ERROR, G_THREAD_ERROR_AGAIN);
173 : 1 : g_error_free (error);
174 : : }
175 : :
176 [ - + ]: 1 : if (prlimit (getpid (), RLIMIT_NPROC, &ol, NULL) != 0)
177 : 0 : g_error ("resetting RLIMIT_NPROC failed: %s", g_strerror (errno));
178 : : #endif
179 : 1 : }
180 : :
181 : : static void
182 : 1 : test_thread5 (void)
183 : : {
184 : : GThread *thread;
185 : :
186 : 1 : thread = g_thread_new ("a", thread3_func, NULL);
187 : 1 : g_thread_ref (thread);
188 : 1 : g_thread_join (thread);
189 : 1 : g_thread_unref (thread);
190 : 1 : }
191 : :
192 : : static gpointer
193 : 1 : thread6_func (gpointer data)
194 : : {
195 : : #if defined (HAVE_PTHREAD_SETNAME_NP_WITH_TID) && defined (HAVE_PTHREAD_GETNAME_NP)
196 : : char name[16];
197 : :
198 : 1 : pthread_getname_np (pthread_self(), name, 16);
199 : :
200 : 1 : g_assert_cmpstr (name, ==, data);
201 : : #endif
202 : :
203 : 1 : return NULL;
204 : : }
205 : :
206 : : static void
207 : 1 : test_thread6 (void)
208 : : {
209 : : GThread *thread;
210 : :
211 : 1 : thread = g_thread_new ("abc", thread6_func, "abc");
212 : 1 : g_thread_join (thread);
213 : 1 : }
214 : :
215 : : #if defined(_SC_NPROCESSORS_ONLN) && defined(THREADS_POSIX) && defined(HAVE_PTHREAD_GETAFFINITY_NP)
216 : : static gpointer
217 : 1 : thread7_func (gpointer data)
218 : : {
219 : 1 : int idx = 0, err;
220 : 1 : int ncores = sysconf (_SC_NPROCESSORS_ONLN);
221 : :
222 : : cpu_set_t old_mask, new_mask;
223 : :
224 : 1 : err = pthread_getaffinity_np (pthread_self (), sizeof (old_mask), &old_mask);
225 : 1 : CPU_ZERO (&new_mask);
226 : 1 : g_assert_cmpint (err, ==, 0);
227 : :
228 [ + - ]: 1 : for (idx = 0; idx < ncores; ++idx)
229 [ + - + - : 1 : if (CPU_ISSET (idx, &old_mask))
+ - ]
230 : : {
231 [ + - ]: 1 : CPU_SET (idx, &new_mask);
232 : 1 : break;
233 : : }
234 : :
235 : 1 : err = pthread_setaffinity_np (pthread_self (), sizeof (new_mask), &new_mask);
236 : 1 : g_assert_cmpint (err, ==, 0);
237 : :
238 : 1 : int af_count = g_get_num_processors ();
239 : 1 : return GINT_TO_POINTER (af_count);
240 : : }
241 : : #endif
242 : :
243 : : static void
244 : 1 : test_thread7 (void)
245 : : {
246 : : #if defined(_SC_NPROCESSORS_ONLN) && defined(THREADS_POSIX) && defined(HAVE_PTHREAD_GETAFFINITY_NP)
247 : 1 : GThread *thread = g_thread_new ("mask", thread7_func, NULL);
248 : 1 : gpointer result = g_thread_join (thread);
249 : :
250 : 1 : g_assert_cmpint (GPOINTER_TO_INT (result), ==, 1);
251 : : #else
252 : : g_test_skip ("Skipping because pthread_getaffinity_np() is not available");
253 : : #endif
254 : 1 : }
255 : :
256 : : int
257 : 1 : main (int argc, char *argv[])
258 : : {
259 : 1 : g_test_init (&argc, &argv, NULL);
260 : :
261 : 1 : g_test_add_func ("/thread/thread1", test_thread1);
262 : 1 : g_test_add_func ("/thread/thread2", test_thread2);
263 : 1 : g_test_add_func ("/thread/thread3", test_thread3);
264 : 1 : g_test_add_func ("/thread/thread4", test_thread4);
265 : 1 : g_test_add_func ("/thread/thread5", test_thread5);
266 : 1 : g_test_add_func ("/thread/thread6", test_thread6);
267 : 1 : g_test_add_func ("/thread/thread7", test_thread7);
268 : :
269 : 1 : return g_test_run ();
270 : : }
|