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 #ifdef __sparc
79 #define gregs __gregs
80 #endif
81
82 /*
83 * Verify that the stack pointer of a context is consistent with where the
84 * attributes indicate.
85 */
86 static void
pgn_verif_thr_stack(pthread_attr_t * attr)87 pgn_verif_thr_stack(pthread_attr_t *attr)
88 {
89 size_t stksz;
90 void *stk;
91 ucontext_t ctx;
92 uint32_t sp;
93
94 VERIFY0(getcontext(&ctx));
95 VERIFY0(pthread_attr_getstack(attr, &stk, &stksz));
96 VERIFY3P(stk, !=, NULL);
97 VERIFY3S(stksz, !=, 0);
98 sp = ctx.uc_mcontext.gregs[R_SP];
99 VERIFY3U(sp, >, (uintptr_t)stk);
100 VERIFY3U(sp, <, (uintptr_t)stk + stksz);
101 }
102
103 #ifdef __sparc
104 #undef gregs
105 #endif
106
107 static void
pgn_test_fini(void)108 pgn_test_fini(void)
109 {
110 int ret;
111
112 ret = pthread_barrier_wait(&pgn_barrier);
113 VERIFY(ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD);
114 VERIFY0(pthread_attr_destroy(&pgn_attr));
115 VERIFY0(pthread_attr_destroy(&pgn_thr_attr));
116 VERIFY0(pthread_barrier_destroy(&pgn_barrier));
117 }
118
119 static void
pgn_test_init(void)120 pgn_test_init(void)
121 {
122 VERIFY0(pthread_attr_init(&pgn_attr));
123 VERIFY0(pthread_attr_init(&pgn_thr_attr));
124 VERIFY0(pthread_barrier_init(&pgn_barrier, NULL, 2));
125 }
126
127 /* ARGSUSED */
128 static void *
pgn_set_one_thr(void * arg)129 pgn_set_one_thr(void *arg)
130 {
131 int odetach, ndetach;
132 int odaemon, ndaemon;
133 int oscope, nscope;
134 int oinherit, ninherit;
135
136 VERIFY0(pthread_attr_get_np(pthread_self(), &pgn_attr));
137 pgn_verif_thr_stack(&pgn_attr);
138
139 VERIFY0(pthread_attr_getdetachstate(&pgn_thr_attr, &odetach));
140 VERIFY0(pthread_attr_getdetachstate(&pgn_attr, &ndetach));
141
142 VERIFY3S(odetach, ==, ndetach);
143 VERIFY3S(ndetach, ==, PTHREAD_CREATE_DETACHED);
144
145 VERIFY0(pthread_attr_getdaemonstate_np(&pgn_thr_attr, &odaemon));
146 VERIFY0(pthread_attr_getdaemonstate_np(&pgn_attr, &ndaemon));
147
148 VERIFY3S(odaemon, ==, ndaemon);
149 VERIFY3S(ndaemon, ==, PTHREAD_CREATE_DAEMON_NP);
150
151 VERIFY0(pthread_attr_getscope(&pgn_thr_attr, &oscope));
152 VERIFY0(pthread_attr_getscope(&pgn_attr, &nscope));
153
154 VERIFY3S(oscope, ==, nscope);
155 VERIFY3S(nscope, ==, PTHREAD_SCOPE_SYSTEM);
156
157 VERIFY0(pthread_attr_getinheritsched(&pgn_thr_attr, &oinherit));
158 VERIFY0(pthread_attr_getinheritsched(&pgn_attr, &ninherit));
159
160 VERIFY3S(oinherit, ==, ninherit);
161 VERIFY3S(ninherit, ==, PTHREAD_INHERIT_SCHED);
162
163 VERIFY3S(pthread_barrier_wait(&pgn_barrier), !=, 1);
164 return (NULL);
165 }
166
167 static void
pgn_set_one(void)168 pgn_set_one(void)
169 {
170 int ret;
171 pthread_t thr;
172
173 pgn_test_init();
174
175 VERIFY0(pthread_attr_setdetachstate(&pgn_thr_attr,
176 PTHREAD_CREATE_DETACHED));
177 VERIFY0(pthread_attr_setdaemonstate_np(&pgn_thr_attr,
178 PTHREAD_CREATE_DAEMON_NP));
179 VERIFY0(pthread_attr_setscope(&pgn_thr_attr, PTHREAD_SCOPE_SYSTEM));
180 VERIFY0(pthread_attr_setinheritsched(&pgn_thr_attr,
181 PTHREAD_INHERIT_SCHED));
182
183 VERIFY0(pthread_create(&thr, &pgn_thr_attr, pgn_set_one_thr, NULL));
184
185 /*
186 * Verify it's not joinable.
187 */
188 ret = pthread_join(thr, NULL);
189 VERIFY3S(ret, ==, EINVAL);
190
191 /*
192 * At this point we let the test continue and wait on the barrier. We'll
193 * wake up when the other thread is done.
194 */
195 pgn_test_fini();
196 }
197
198 /* ARGSUSED */
199 static void *
pgn_set_two_thr(void * arg)200 pgn_set_two_thr(void *arg)
201 {
202 int odetach, ndetach;
203 int odaemon, ndaemon;
204 int oscope, nscope;
205 int oinherit, ninherit;
206 int opolicy, npolicy;
207 struct sched_param oparam, nparam;
208
209 VERIFY0(pthread_attr_get_np(pthread_self(), &pgn_attr));
210 pgn_verif_thr_stack(&pgn_attr);
211
212 VERIFY0(pthread_attr_getdetachstate(&pgn_thr_attr, &odetach));
213 VERIFY0(pthread_attr_getdetachstate(&pgn_attr, &ndetach));
214
215 VERIFY3S(odetach, ==, ndetach);
216 VERIFY3S(ndetach, ==, PTHREAD_CREATE_JOINABLE);
217
218 VERIFY0(pthread_attr_getdaemonstate_np(&pgn_thr_attr, &odaemon));
219 VERIFY0(pthread_attr_getdaemonstate_np(&pgn_attr, &ndaemon));
220
221 VERIFY3S(odaemon, ==, ndaemon);
222 VERIFY3S(ndaemon, ==, PTHREAD_CREATE_NONDAEMON_NP);
223
224 VERIFY0(pthread_attr_getscope(&pgn_thr_attr, &oscope));
225 VERIFY0(pthread_attr_getscope(&pgn_attr, &nscope));
226
227 VERIFY3S(oscope, ==, nscope);
228 VERIFY3S(nscope, ==, PTHREAD_SCOPE_PROCESS);
229
230 VERIFY0(pthread_attr_getinheritsched(&pgn_thr_attr, &oinherit));
231 VERIFY0(pthread_attr_getinheritsched(&pgn_attr, &ninherit));
232
233 VERIFY3S(oinherit, ==, ninherit);
234 VERIFY3S(ninherit, ==, PTHREAD_EXPLICIT_SCHED);
235
236 VERIFY0(pthread_attr_getschedpolicy(&pgn_thr_attr, &opolicy));
237 VERIFY0(pthread_attr_getschedpolicy(&pgn_attr, &npolicy));
238
239 VERIFY3S(opolicy, ==, npolicy);
240 VERIFY3S(npolicy, ==, SCHED_FSS);
241
242 /*
243 * Now that we've validated the basics, go ahead and test the changes,
244 * which include making sure that we see updates via
245 * pthread_setschedparam() and pthread_detach().
246 */
247 VERIFY0(pthread_detach(pthread_self()));
248
249 opolicy = SCHED_FX;
250 oparam.sched_priority = PGN_TEST_PRI;
251 VERIFY0(pthread_setschedparam(pthread_self(), opolicy, &oparam));
252
253 VERIFY0(pthread_attr_get_np(pthread_self(), &pgn_attr));
254 VERIFY0(pthread_attr_getdetachstate(&pgn_attr, &ndetach));
255
256 VERIFY3S(odetach, !=, ndetach);
257 VERIFY3S(ndetach, ==, PTHREAD_CREATE_DETACHED);
258
259 VERIFY0(pthread_attr_getschedpolicy(&pgn_attr, &npolicy));
260 VERIFY0(pthread_attr_getschedparam(&pgn_attr, &nparam));
261
262 VERIFY3S(opolicy, ==, npolicy);
263 VERIFY3S(npolicy, ==, SCHED_FX);
264
265 VERIFY3S(oparam.sched_priority, ==, nparam.sched_priority);
266 VERIFY3S(nparam.sched_priority, ==, PGN_TEST_PRI);
267
268 VERIFY3S(pthread_barrier_wait(&pgn_barrier), !=, 1);
269
270 return (NULL);
271 }
272
273 static void
pgn_set_two(void)274 pgn_set_two(void)
275 {
276 pthread_t thr;
277
278 pgn_test_init();
279
280 VERIFY0(pthread_attr_setdetachstate(&pgn_thr_attr,
281 PTHREAD_CREATE_JOINABLE));
282 VERIFY0(pthread_attr_setdaemonstate_np(&pgn_thr_attr,
283 PTHREAD_CREATE_NONDAEMON_NP));
284 VERIFY0(pthread_attr_setscope(&pgn_thr_attr, PTHREAD_SCOPE_PROCESS));
285 VERIFY0(pthread_attr_setinheritsched(&pgn_thr_attr,
286 PTHREAD_EXPLICIT_SCHED));
287 VERIFY0(pthread_attr_setschedpolicy(&pgn_thr_attr, SCHED_FSS));
288
289 VERIFY0(pthread_create(&thr, &pgn_thr_attr, pgn_set_two_thr, NULL));
290
291 /*
292 * At this point we let the test continue and wait on the barrier. We'll
293 * wake up when the other thread is done.
294 */
295 pgn_test_fini();
296 }
297
298 /* ARGSUSED */
299 static void *
pgn_set_three_thr(void * arg)300 pgn_set_three_thr(void *arg)
301 {
302 VERIFY3S(pthread_barrier_wait(&pgn_barrier), !=, 1);
303
304 return (NULL);
305 }
306
307 void
pgn_set_three(void)308 pgn_set_three(void)
309 {
310 pthread_t thr;
311 pthread_attr_t altattr, selfattr;
312 void *altstk, *selfstk;
313 size_t altsz, selfsz;
314
315 VERIFY0(pthread_attr_init(&altattr));
316 VERIFY0(pthread_attr_init(&selfattr));
317 pgn_test_init();
318
319 VERIFY0(pthread_create(&thr, NULL, pgn_set_three_thr, NULL));
320
321 VERIFY0(pthread_attr_get_np(thr, &altattr));
322 VERIFY0(pthread_attr_get_np(pthread_self(), &selfattr));
323
324 VERIFY0(pthread_attr_getstack(&selfattr, &selfstk, &selfsz));
325 VERIFY0(pthread_attr_getstack(&altattr, &altstk, &altsz));
326 VERIFY3P(altstk, !=, selfstk);
327
328 pgn_test_fini();
329 VERIFY0(pthread_attr_destroy(&selfattr));
330 VERIFY0(pthread_attr_destroy(&altattr));
331 }
332
333 int
main(void)334 main(void)
335 {
336 int ret;
337
338 VERIFY0(pthread_attr_init(&pgn_attr));
339
340 ret = pthread_attr_get_np(UINT32_MAX, &pgn_attr);
341 VERIFY3S(ret, ==, ESRCH);
342
343 pgn_set_one();
344 pgn_set_two();
345 pgn_set_three();
346
347 exit(0);
348 }
349