/* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2016 Joyent, Inc. */ /* * Test and verify that pthrad_attr_get_np works as we expect. * * Verify the following: * o ESRCH * o stack size is set to a valid value after a thread is created. * o main thread can grab an alternate thread's info. * o custom guard size is honored * o detach state * - detached 1 * - joinable 2 * - changing 2 * o daemon state * - enabled 1 * - disabled 2 * o scope * - system 1 * - process 2 * o inheritable * - inherit 1 * - explicit 2 * o priority * - honors change 2 * o policy * - honours change 2 * * * For each of the cases above we explicitly go through and create the set of * attributes as marked above and then inside of a thread, verify that the * attributes match what we expect. Because each case ends up in creating a * detached thread, we opt to have both it and the main thread enter a barrier * to indicate that we have completed the test successfully. */ #include #include #include #include #include #include #include #include #include #include #include /* * Currently these are only defined in thr_uberdata.h. Rather than trying and * fight with libc headers, just explicitly define them here. */ #define PTHREAD_CREATE_DAEMON_NP 0x100 /* = THR_DAEMON */ #define PTHREAD_CREATE_NONDAEMON_NP 0 extern int pthread_attr_setdaemonstate_np(pthread_attr_t *, int); extern int pthread_attr_getdaemonstate_np(const pthread_attr_t *, int *); #define PGN_TEST_PRI 23 static pthread_attr_t pgn_attr; static pthread_attr_t pgn_thr_attr; static pthread_barrier_t pgn_barrier; /* * Verify that the stack pointer of a context is consistent with where the * attributes indicate. */ static void pgn_verif_thr_stack(pthread_attr_t *attr) { size_t stksz; void *stk; ucontext_t ctx; uint32_t sp; VERIFY0(getcontext(&ctx)); VERIFY0(pthread_attr_getstack(attr, &stk, &stksz)); VERIFY3P(stk, !=, NULL); VERIFY3S(stksz, !=, 0); sp = ctx.uc_mcontext.gregs[R_SP]; VERIFY3U(sp, >, (uintptr_t)stk); VERIFY3U(sp, <, (uintptr_t)stk + stksz); } static void pgn_test_fini(void) { int ret; ret = pthread_barrier_wait(&pgn_barrier); VERIFY(ret == 0 || ret == PTHREAD_BARRIER_SERIAL_THREAD); VERIFY0(pthread_attr_destroy(&pgn_attr)); VERIFY0(pthread_attr_destroy(&pgn_thr_attr)); VERIFY0(pthread_barrier_destroy(&pgn_barrier)); } static void pgn_test_init(void) { VERIFY0(pthread_attr_init(&pgn_attr)); VERIFY0(pthread_attr_init(&pgn_thr_attr)); VERIFY0(pthread_barrier_init(&pgn_barrier, NULL, 2)); } /* ARGSUSED */ static void * pgn_set_one_thr(void *arg) { int odetach, ndetach; int odaemon, ndaemon; int oscope, nscope; int oinherit, ninherit; VERIFY0(pthread_attr_get_np(pthread_self(), &pgn_attr)); pgn_verif_thr_stack(&pgn_attr); VERIFY0(pthread_attr_getdetachstate(&pgn_thr_attr, &odetach)); VERIFY0(pthread_attr_getdetachstate(&pgn_attr, &ndetach)); VERIFY3S(odetach, ==, ndetach); VERIFY3S(ndetach, ==, PTHREAD_CREATE_DETACHED); VERIFY0(pthread_attr_getdaemonstate_np(&pgn_thr_attr, &odaemon)); VERIFY0(pthread_attr_getdaemonstate_np(&pgn_attr, &ndaemon)); VERIFY3S(odaemon, ==, ndaemon); VERIFY3S(ndaemon, ==, PTHREAD_CREATE_DAEMON_NP); VERIFY0(pthread_attr_getscope(&pgn_thr_attr, &oscope)); VERIFY0(pthread_attr_getscope(&pgn_attr, &nscope)); VERIFY3S(oscope, ==, nscope); VERIFY3S(nscope, ==, PTHREAD_SCOPE_SYSTEM); VERIFY0(pthread_attr_getinheritsched(&pgn_thr_attr, &oinherit)); VERIFY0(pthread_attr_getinheritsched(&pgn_attr, &ninherit)); VERIFY3S(oinherit, ==, ninherit); VERIFY3S(ninherit, ==, PTHREAD_INHERIT_SCHED); VERIFY3S(pthread_barrier_wait(&pgn_barrier), !=, 1); return (NULL); } static void pgn_set_one(void) { int ret; pthread_t thr; pgn_test_init(); VERIFY0(pthread_attr_setdetachstate(&pgn_thr_attr, PTHREAD_CREATE_DETACHED)); VERIFY0(pthread_attr_setdaemonstate_np(&pgn_thr_attr, PTHREAD_CREATE_DAEMON_NP)); VERIFY0(pthread_attr_setscope(&pgn_thr_attr, PTHREAD_SCOPE_SYSTEM)); VERIFY0(pthread_attr_setinheritsched(&pgn_thr_attr, PTHREAD_INHERIT_SCHED)); VERIFY0(pthread_create(&thr, &pgn_thr_attr, pgn_set_one_thr, NULL)); /* * Verify it's not joinable. */ ret = pthread_join(thr, NULL); VERIFY3S(ret, ==, EINVAL); /* * At this point we let the test continue and wait on the barrier. We'll * wake up when the other thread is done. */ pgn_test_fini(); } /* ARGSUSED */ static void * pgn_set_two_thr(void *arg) { int odetach, ndetach; int odaemon, ndaemon; int oscope, nscope; int oinherit, ninherit; int opolicy, npolicy; struct sched_param oparam, nparam; VERIFY0(pthread_attr_get_np(pthread_self(), &pgn_attr)); pgn_verif_thr_stack(&pgn_attr); VERIFY0(pthread_attr_getdetachstate(&pgn_thr_attr, &odetach)); VERIFY0(pthread_attr_getdetachstate(&pgn_attr, &ndetach)); VERIFY3S(odetach, ==, ndetach); VERIFY3S(ndetach, ==, PTHREAD_CREATE_JOINABLE); VERIFY0(pthread_attr_getdaemonstate_np(&pgn_thr_attr, &odaemon)); VERIFY0(pthread_attr_getdaemonstate_np(&pgn_attr, &ndaemon)); VERIFY3S(odaemon, ==, ndaemon); VERIFY3S(ndaemon, ==, PTHREAD_CREATE_NONDAEMON_NP); VERIFY0(pthread_attr_getscope(&pgn_thr_attr, &oscope)); VERIFY0(pthread_attr_getscope(&pgn_attr, &nscope)); VERIFY3S(oscope, ==, nscope); VERIFY3S(nscope, ==, PTHREAD_SCOPE_PROCESS); VERIFY0(pthread_attr_getinheritsched(&pgn_thr_attr, &oinherit)); VERIFY0(pthread_attr_getinheritsched(&pgn_attr, &ninherit)); VERIFY3S(oinherit, ==, ninherit); VERIFY3S(ninherit, ==, PTHREAD_EXPLICIT_SCHED); VERIFY0(pthread_attr_getschedpolicy(&pgn_thr_attr, &opolicy)); VERIFY0(pthread_attr_getschedpolicy(&pgn_attr, &npolicy)); VERIFY3S(opolicy, ==, npolicy); VERIFY3S(npolicy, ==, SCHED_FSS); /* * Now that we've validated the basics, go ahead and test the changes, * which include making sure that we see updates via * pthread_setschedparam() and pthread_detach(). */ VERIFY0(pthread_detach(pthread_self())); opolicy = SCHED_FX; oparam.sched_priority = PGN_TEST_PRI; VERIFY0(pthread_setschedparam(pthread_self(), opolicy, &oparam)); VERIFY0(pthread_attr_get_np(pthread_self(), &pgn_attr)); VERIFY0(pthread_attr_getdetachstate(&pgn_attr, &ndetach)); VERIFY3S(odetach, !=, ndetach); VERIFY3S(ndetach, ==, PTHREAD_CREATE_DETACHED); VERIFY0(pthread_attr_getschedpolicy(&pgn_attr, &npolicy)); VERIFY0(pthread_attr_getschedparam(&pgn_attr, &nparam)); VERIFY3S(opolicy, ==, npolicy); VERIFY3S(npolicy, ==, SCHED_FX); VERIFY3S(oparam.sched_priority, ==, nparam.sched_priority); VERIFY3S(nparam.sched_priority, ==, PGN_TEST_PRI); VERIFY3S(pthread_barrier_wait(&pgn_barrier), !=, 1); return (NULL); } static void pgn_set_two(void) { pthread_t thr; pgn_test_init(); VERIFY0(pthread_attr_setdetachstate(&pgn_thr_attr, PTHREAD_CREATE_JOINABLE)); VERIFY0(pthread_attr_setdaemonstate_np(&pgn_thr_attr, PTHREAD_CREATE_NONDAEMON_NP)); VERIFY0(pthread_attr_setscope(&pgn_thr_attr, PTHREAD_SCOPE_PROCESS)); VERIFY0(pthread_attr_setinheritsched(&pgn_thr_attr, PTHREAD_EXPLICIT_SCHED)); VERIFY0(pthread_attr_setschedpolicy(&pgn_thr_attr, SCHED_FSS)); VERIFY0(pthread_create(&thr, &pgn_thr_attr, pgn_set_two_thr, NULL)); /* * At this point we let the test continue and wait on the barrier. We'll * wake up when the other thread is done. */ pgn_test_fini(); } /* ARGSUSED */ static void * pgn_set_three_thr(void *arg) { VERIFY3S(pthread_barrier_wait(&pgn_barrier), !=, 1); return (NULL); } void pgn_set_three(void) { pthread_t thr; pthread_attr_t altattr, selfattr; void *altstk, *selfstk; size_t altsz, selfsz; VERIFY0(pthread_attr_init(&altattr)); VERIFY0(pthread_attr_init(&selfattr)); pgn_test_init(); VERIFY0(pthread_create(&thr, NULL, pgn_set_three_thr, NULL)); VERIFY0(pthread_attr_get_np(thr, &altattr)); VERIFY0(pthread_attr_get_np(pthread_self(), &selfattr)); VERIFY0(pthread_attr_getstack(&selfattr, &selfstk, &selfsz)); VERIFY0(pthread_attr_getstack(&altattr, &altstk, &altsz)); VERIFY3P(altstk, !=, selfstk); pgn_test_fini(); VERIFY0(pthread_attr_destroy(&selfattr)); VERIFY0(pthread_attr_destroy(&altattr)); } int main(void) { int ret; VERIFY0(pthread_attr_init(&pgn_attr)); ret = pthread_attr_get_np(UINT32_MAX, &pgn_attr); VERIFY3S(ret, ==, ESRCH); pgn_set_one(); pgn_set_two(); pgn_set_three(); exit(0); }