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 }