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