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 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 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 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 * 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 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 * 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 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 * 294 pgn_set_three_thr(void *arg) 295 { 296 VERIFY3S(pthread_barrier_wait(&pgn_barrier), !=, 1); 297 298 return (NULL); 299 } 300 301 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 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 }