1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2016 Joyent, Inc.
14 */
15
16 /*
17 * Test and verify that pthrad_attr_get_np works as we expect.
18 *
19 * Verify the following:
20 * o ESRCH
21 * o stack size is set to a valid value after a thread is created.
22 * o main thread can grab an alternate thread's info.
23 * o custom guard size is honored
24 * o detach state
25 * - detached 1
26 * - joinable 2
27 * - changing 2
28 * o daemon state
29 * - enabled 1
30 * - disabled 2
31 * o scope
32 * - system 1
33 * - process 2
34 * o inheritable
35 * - inherit 1
36 * - explicit 2
37 * o priority
38 * - honors change 2
39 * o policy
40 * - honours change 2
41 *
42 *
43 * For each of the cases above we explicitly go through and create the set of
44 * attributes as marked above and then inside of a thread, verify that the
45 * attributes match what we expect. Because each case ends up in creating a
46 * detached thread, we opt to have both it and the main thread enter a barrier
47 * to indicate that we have completed the test successfully.
48 */
49
50 #include <errno.h>
51 #include <limits.h>
52 #include <stdio.h>
53 #include <pthread.h>
54 #include <unistd.h>
55 #include <ucontext.h>
56 #include <sched.h>
57 #include <strings.h>
58 #include <stdlib.h>
59
60 #include <sys/procfs.h>
61 #include <sys/debug.h>
62
63 /*
64 * Currently these are only defined in thr_uberdata.h. Rather than trying and
65 * fight with libc headers, just explicitly define them here.
66 */
67 #define PTHREAD_CREATE_DAEMON_NP 0x100 /* = THR_DAEMON */
68 #define PTHREAD_CREATE_NONDAEMON_NP 0
69 extern int pthread_attr_setdaemonstate_np(pthread_attr_t *, int);
70 extern int pthread_attr_getdaemonstate_np(const pthread_attr_t *, int *);
71
72 #define PGN_TEST_PRI 23
73
74 static pthread_attr_t pgn_attr;
75 static pthread_attr_t pgn_thr_attr;
76 static pthread_barrier_t pgn_barrier;
77
78
79 /*
80 * Verify that the stack pointer of a context is consistent with where the
81 * attributes indicate.
82 */
83 static void
pgn_verif_thr_stack(pthread_attr_t * attr)84 pgn_verif_thr_stack(pthread_attr_t *attr)
85 {
86 size_t stksz;
87 void *stk;
88 ucontext_t ctx;
89 uint32_t sp;
90
91 VERIFY0(getcontext(&ctx));
92 VERIFY0(pthread_attr_getstack(attr, &stk, &stksz));
93 VERIFY3P(stk, !=, NULL);
94 VERIFY3S(stksz, !=, 0);
95 sp = ctx.uc_mcontext.gregs[R_SP];
96 VERIFY3U(sp, >, (uintptr_t)stk);
97 VERIFY3U(sp, <, (uintptr_t)stk + stksz);
98 }
99
100
101 static void
pgn_test_fini(void)102 pgn_test_fini(void)
103 {
104 int ret;
105
106 ret = pthread_barrier_wait(&pgn_barrier);
107 VERIFY(ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD);
108 VERIFY0(pthread_attr_destroy(&pgn_attr));
109 VERIFY0(pthread_attr_destroy(&pgn_thr_attr));
110 VERIFY0(pthread_barrier_destroy(&pgn_barrier));
111 }
112
113 static void
pgn_test_init(void)114 pgn_test_init(void)
115 {
116 VERIFY0(pthread_attr_init(&pgn_attr));
117 VERIFY0(pthread_attr_init(&pgn_thr_attr));
118 VERIFY0(pthread_barrier_init(&pgn_barrier, NULL, 2));
119 }
120
121 /* ARGSUSED */
122 static void *
pgn_set_one_thr(void * arg)123 pgn_set_one_thr(void *arg)
124 {
125 int odetach, ndetach;
126 int odaemon, ndaemon;
127 int oscope, nscope;
128 int oinherit, ninherit;
129
130 VERIFY0(pthread_attr_get_np(pthread_self(), &pgn_attr));
131 pgn_verif_thr_stack(&pgn_attr);
132
133 VERIFY0(pthread_attr_getdetachstate(&pgn_thr_attr, &odetach));
134 VERIFY0(pthread_attr_getdetachstate(&pgn_attr, &ndetach));
135
136 VERIFY3S(odetach, ==, ndetach);
137 VERIFY3S(ndetach, ==, PTHREAD_CREATE_DETACHED);
138
139 VERIFY0(pthread_attr_getdaemonstate_np(&pgn_thr_attr, &odaemon));
140 VERIFY0(pthread_attr_getdaemonstate_np(&pgn_attr, &ndaemon));
141
142 VERIFY3S(odaemon, ==, ndaemon);
143 VERIFY3S(ndaemon, ==, PTHREAD_CREATE_DAEMON_NP);
144
145 VERIFY0(pthread_attr_getscope(&pgn_thr_attr, &oscope));
146 VERIFY0(pthread_attr_getscope(&pgn_attr, &nscope));
147
148 VERIFY3S(oscope, ==, nscope);
149 VERIFY3S(nscope, ==, PTHREAD_SCOPE_SYSTEM);
150
151 VERIFY0(pthread_attr_getinheritsched(&pgn_thr_attr, &oinherit));
152 VERIFY0(pthread_attr_getinheritsched(&pgn_attr, &ninherit));
153
154 VERIFY3S(oinherit, ==, ninherit);
155 VERIFY3S(ninherit, ==, PTHREAD_INHERIT_SCHED);
156
157 VERIFY3S(pthread_barrier_wait(&pgn_barrier), !=, 1);
158 return (NULL);
159 }
160
161 static void
pgn_set_one(void)162 pgn_set_one(void)
163 {
164 int ret;
165 pthread_t thr;
166
167 pgn_test_init();
168
169 VERIFY0(pthread_attr_setdetachstate(&pgn_thr_attr,
170 PTHREAD_CREATE_DETACHED));
171 VERIFY0(pthread_attr_setdaemonstate_np(&pgn_thr_attr,
172 PTHREAD_CREATE_DAEMON_NP));
173 VERIFY0(pthread_attr_setscope(&pgn_thr_attr, PTHREAD_SCOPE_SYSTEM));
174 VERIFY0(pthread_attr_setinheritsched(&pgn_thr_attr,
175 PTHREAD_INHERIT_SCHED));
176
177 VERIFY0(pthread_create(&thr, &pgn_thr_attr, pgn_set_one_thr, NULL));
178
179 /*
180 * Verify it's not joinable.
181 */
182 ret = pthread_join(thr, NULL);
183 VERIFY3S(ret, ==, EINVAL);
184
185 /*
186 * At this point we let the test continue and wait on the barrier. We'll
187 * wake up when the other thread is done.
188 */
189 pgn_test_fini();
190 }
191
192 /* ARGSUSED */
193 static void *
pgn_set_two_thr(void * arg)194 pgn_set_two_thr(void *arg)
195 {
196 int odetach, ndetach;
197 int odaemon, ndaemon;
198 int oscope, nscope;
199 int oinherit, ninherit;
200 int opolicy, npolicy;
201 struct sched_param oparam, nparam;
202
203 VERIFY0(pthread_attr_get_np(pthread_self(), &pgn_attr));
204 pgn_verif_thr_stack(&pgn_attr);
205
206 VERIFY0(pthread_attr_getdetachstate(&pgn_thr_attr, &odetach));
207 VERIFY0(pthread_attr_getdetachstate(&pgn_attr, &ndetach));
208
209 VERIFY3S(odetach, ==, ndetach);
210 VERIFY3S(ndetach, ==, PTHREAD_CREATE_JOINABLE);
211
212 VERIFY0(pthread_attr_getdaemonstate_np(&pgn_thr_attr, &odaemon));
213 VERIFY0(pthread_attr_getdaemonstate_np(&pgn_attr, &ndaemon));
214
215 VERIFY3S(odaemon, ==, ndaemon);
216 VERIFY3S(ndaemon, ==, PTHREAD_CREATE_NONDAEMON_NP);
217
218 VERIFY0(pthread_attr_getscope(&pgn_thr_attr, &oscope));
219 VERIFY0(pthread_attr_getscope(&pgn_attr, &nscope));
220
221 VERIFY3S(oscope, ==, nscope);
222 VERIFY3S(nscope, ==, PTHREAD_SCOPE_PROCESS);
223
224 VERIFY0(pthread_attr_getinheritsched(&pgn_thr_attr, &oinherit));
225 VERIFY0(pthread_attr_getinheritsched(&pgn_attr, &ninherit));
226
227 VERIFY3S(oinherit, ==, ninherit);
228 VERIFY3S(ninherit, ==, PTHREAD_EXPLICIT_SCHED);
229
230 VERIFY0(pthread_attr_getschedpolicy(&pgn_thr_attr, &opolicy));
231 VERIFY0(pthread_attr_getschedpolicy(&pgn_attr, &npolicy));
232
233 VERIFY3S(opolicy, ==, npolicy);
234 VERIFY3S(npolicy, ==, SCHED_FSS);
235
236 /*
237 * Now that we've validated the basics, go ahead and test the changes,
238 * which include making sure that we see updates via
239 * pthread_setschedparam() and pthread_detach().
240 */
241 VERIFY0(pthread_detach(pthread_self()));
242
243 opolicy = SCHED_FX;
244 oparam.sched_priority = PGN_TEST_PRI;
245 VERIFY0(pthread_setschedparam(pthread_self(), opolicy, &oparam));
246
247 VERIFY0(pthread_attr_get_np(pthread_self(), &pgn_attr));
248 VERIFY0(pthread_attr_getdetachstate(&pgn_attr, &ndetach));
249
250 VERIFY3S(odetach, !=, ndetach);
251 VERIFY3S(ndetach, ==, PTHREAD_CREATE_DETACHED);
252
253 VERIFY0(pthread_attr_getschedpolicy(&pgn_attr, &npolicy));
254 VERIFY0(pthread_attr_getschedparam(&pgn_attr, &nparam));
255
256 VERIFY3S(opolicy, ==, npolicy);
257 VERIFY3S(npolicy, ==, SCHED_FX);
258
259 VERIFY3S(oparam.sched_priority, ==, nparam.sched_priority);
260 VERIFY3S(nparam.sched_priority, ==, PGN_TEST_PRI);
261
262 VERIFY3S(pthread_barrier_wait(&pgn_barrier), !=, 1);
263
264 return (NULL);
265 }
266
267 static void
pgn_set_two(void)268 pgn_set_two(void)
269 {
270 pthread_t thr;
271
272 pgn_test_init();
273
274 VERIFY0(pthread_attr_setdetachstate(&pgn_thr_attr,
275 PTHREAD_CREATE_JOINABLE));
276 VERIFY0(pthread_attr_setdaemonstate_np(&pgn_thr_attr,
277 PTHREAD_CREATE_NONDAEMON_NP));
278 VERIFY0(pthread_attr_setscope(&pgn_thr_attr, PTHREAD_SCOPE_PROCESS));
279 VERIFY0(pthread_attr_setinheritsched(&pgn_thr_attr,
280 PTHREAD_EXPLICIT_SCHED));
281 VERIFY0(pthread_attr_setschedpolicy(&pgn_thr_attr, SCHED_FSS));
282
283 VERIFY0(pthread_create(&thr, &pgn_thr_attr, pgn_set_two_thr, NULL));
284
285 /*
286 * At this point we let the test continue and wait on the barrier. We'll
287 * wake up when the other thread is done.
288 */
289 pgn_test_fini();
290 }
291
292 /* ARGSUSED */
293 static void *
pgn_set_three_thr(void * arg)294 pgn_set_three_thr(void *arg)
295 {
296 VERIFY3S(pthread_barrier_wait(&pgn_barrier), !=, 1);
297
298 return (NULL);
299 }
300
301 void
pgn_set_three(void)302 pgn_set_three(void)
303 {
304 pthread_t thr;
305 pthread_attr_t altattr, selfattr;
306 void *altstk, *selfstk;
307 size_t altsz, selfsz;
308
309 VERIFY0(pthread_attr_init(&altattr));
310 VERIFY0(pthread_attr_init(&selfattr));
311 pgn_test_init();
312
313 VERIFY0(pthread_create(&thr, NULL, pgn_set_three_thr, NULL));
314
315 VERIFY0(pthread_attr_get_np(thr, &altattr));
316 VERIFY0(pthread_attr_get_np(pthread_self(), &selfattr));
317
318 VERIFY0(pthread_attr_getstack(&selfattr, &selfstk, &selfsz));
319 VERIFY0(pthread_attr_getstack(&altattr, &altstk, &altsz));
320 VERIFY3P(altstk, !=, selfstk);
321
322 pgn_test_fini();
323 VERIFY0(pthread_attr_destroy(&selfattr));
324 VERIFY0(pthread_attr_destroy(&altattr));
325 }
326
327 int
main(void)328 main(void)
329 {
330 int ret;
331
332 VERIFY0(pthread_attr_init(&pgn_attr));
333
334 ret = pthread_attr_get_np(UINT32_MAX, &pgn_attr);
335 VERIFY3S(ret, ==, ESRCH);
336
337 pgn_set_one();
338 pgn_set_two();
339 pgn_set_three();
340
341 exit(0);
342 }
343