xref: /illumos-gate/usr/src/test/libc-tests/tests/threads/pthread_attr_get_np.c (revision dcbf3bd6a1f1360fc1afcee9e22c6dcff7844bf2)
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
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
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
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 *
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
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 *
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
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 *
300 pgn_set_three_thr(void *arg)
301 {
302 	VERIFY3S(pthread_barrier_wait(&pgn_barrier), !=, 1);
303 
304 	return (NULL);
305 }
306 
307 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
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