1 /* $NetBSD: pthread_attr.c,v 1.18 2017/08/01 12:31:45 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2002, 2003, 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Nathan J. Williams. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD: pthread_attr.c,v 1.18 2017/08/01 12:31:45 martin Exp $"); 34 35 #include <errno.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <unistd.h> 40 41 #ifndef __lint__ 42 #define pthread_attr_get_np _pthread_attr_get_np 43 #endif 44 45 #include "pthread.h" 46 #include "pthread_int.h" 47 48 __weak_alias(pthread_attr_get_np, _pthread_attr_get_np) 49 50 static struct pthread_attr_private *pthread__attr_init_private( 51 pthread_attr_t *); 52 53 static struct pthread_attr_private * 54 pthread__attr_init_private(pthread_attr_t *attr) 55 { 56 struct pthread_attr_private *p; 57 58 if ((p = attr->pta_private) != NULL) 59 return p; 60 61 p = calloc(1, sizeof(*p)); 62 if (p != NULL) { 63 attr->pta_private = p; 64 p->ptap_policy = SCHED_OTHER; 65 p->ptap_stacksize = pthread__stacksize; 66 p->ptap_guardsize = pthread__guardsize; 67 } 68 return p; 69 } 70 71 72 int 73 pthread_attr_init(pthread_attr_t *attr) 74 { 75 76 attr->pta_magic = PT_ATTR_MAGIC; 77 attr->pta_flags = 0; 78 attr->pta_private = NULL; 79 80 return 0; 81 } 82 83 84 int 85 pthread_attr_destroy(pthread_attr_t *attr) 86 { 87 struct pthread_attr_private *p; 88 89 if ((p = attr->pta_private) != NULL) 90 free(p); 91 92 return 0; 93 } 94 95 96 int 97 pthread_attr_get_np(pthread_t thread, pthread_attr_t *attr) 98 { 99 struct pthread_attr_private *p; 100 101 p = pthread__attr_init_private(attr); 102 if (p == NULL) 103 return ENOMEM; 104 105 attr->pta_flags = thread->pt_flags & 106 (PT_FLAG_DETACHED | PT_FLAG_SCOPE_SYSTEM | PT_FLAG_EXPLICIT_SCHED); 107 108 p->ptap_namearg = thread->pt_name; 109 p->ptap_stackaddr = thread->pt_stack.ss_sp; 110 p->ptap_stacksize = thread->pt_stack.ss_size; 111 p->ptap_guardsize = thread->pt_guardsize; 112 return pthread_getschedparam(thread, &p->ptap_policy, &p->ptap_sp); 113 } 114 115 116 int 117 pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) 118 { 119 120 if (attr->pta_flags & PT_FLAG_DETACHED) 121 *detachstate = PTHREAD_CREATE_DETACHED; 122 else 123 *detachstate = PTHREAD_CREATE_JOINABLE; 124 125 return 0; 126 } 127 128 129 int 130 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) 131 { 132 133 switch (detachstate) { 134 case PTHREAD_CREATE_JOINABLE: 135 attr->pta_flags &= ~PT_FLAG_DETACHED; 136 break; 137 case PTHREAD_CREATE_DETACHED: 138 attr->pta_flags |= PT_FLAG_DETACHED; 139 break; 140 default: 141 return EINVAL; 142 } 143 144 return 0; 145 } 146 147 148 int 149 pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guard) 150 { 151 struct pthread_attr_private *p; 152 153 if ((p = attr->pta_private) == NULL) 154 *guard = pthread__guardsize; 155 else 156 *guard = p->ptap_guardsize; 157 158 return 0; 159 } 160 161 162 int 163 pthread_attr_setguardsize(pthread_attr_t *attr, size_t guard) 164 { 165 struct pthread_attr_private *p; 166 167 p = pthread__attr_init_private(attr); 168 if (p == NULL) 169 return ENOMEM; 170 171 p->ptap_guardsize = guard; 172 173 return 0; 174 } 175 176 177 int 178 pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit) 179 { 180 181 if (attr->pta_flags & PT_FLAG_EXPLICIT_SCHED) 182 *inherit = PTHREAD_EXPLICIT_SCHED; 183 else 184 *inherit = PTHREAD_INHERIT_SCHED; 185 186 return 0; 187 } 188 189 190 int 191 pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit) 192 { 193 194 switch (inherit) { 195 case PTHREAD_INHERIT_SCHED: 196 attr->pta_flags &= ~PT_FLAG_EXPLICIT_SCHED; 197 break; 198 case PTHREAD_EXPLICIT_SCHED: 199 attr->pta_flags |= PT_FLAG_EXPLICIT_SCHED; 200 break; 201 default: 202 return EINVAL; 203 } 204 205 return 0; 206 } 207 208 209 int 210 pthread_attr_getscope(const pthread_attr_t *attr, int *scope) 211 { 212 213 if (attr->pta_flags & PT_FLAG_SCOPE_SYSTEM) 214 *scope = PTHREAD_SCOPE_SYSTEM; 215 else 216 *scope = PTHREAD_SCOPE_PROCESS; 217 218 return 0; 219 } 220 221 222 int 223 pthread_attr_setscope(pthread_attr_t *attr, int scope) 224 { 225 226 switch (scope) { 227 case PTHREAD_SCOPE_PROCESS: 228 attr->pta_flags &= ~PT_FLAG_SCOPE_SYSTEM; 229 break; 230 case PTHREAD_SCOPE_SYSTEM: 231 attr->pta_flags |= PT_FLAG_SCOPE_SYSTEM; 232 break; 233 default: 234 return EINVAL; 235 } 236 237 return 0; 238 } 239 240 241 int 242 pthread_attr_setschedparam(pthread_attr_t *attr, 243 const struct sched_param *param) 244 { 245 struct pthread_attr_private *p; 246 int error; 247 248 if (param == NULL) 249 return EINVAL; 250 p = pthread__attr_init_private(attr); 251 if (p == NULL) 252 return ENOMEM; 253 error = pthread__checkpri(param->sched_priority); 254 if (error == 0) 255 p->ptap_sp = *param; 256 return error; 257 } 258 259 260 int 261 pthread_attr_getschedparam(const pthread_attr_t *attr, 262 struct sched_param *param) 263 { 264 struct pthread_attr_private *p; 265 266 if (param == NULL) 267 return EINVAL; 268 p = attr->pta_private; 269 if (p == NULL) 270 memset(param, 0, sizeof(*param)); 271 else 272 *param = p->ptap_sp; 273 return 0; 274 } 275 276 277 int 278 pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) 279 { 280 struct pthread_attr_private *p; 281 282 283 switch (policy) { 284 case SCHED_OTHER: 285 case SCHED_FIFO: 286 case SCHED_RR: 287 p = pthread__attr_init_private(attr); 288 if (p == NULL) 289 return ENOMEM; 290 p->ptap_policy = policy; 291 return 0; 292 default: 293 return ENOTSUP; 294 } 295 } 296 297 298 int 299 pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) 300 { 301 struct pthread_attr_private *p; 302 303 p = attr->pta_private; 304 if (p == NULL) { 305 *policy = SCHED_OTHER; 306 return 0; 307 } 308 *policy = p->ptap_policy; 309 return 0; 310 } 311 312 313 int 314 pthread_attr_getstack(const pthread_attr_t *attr, void **addr, size_t *size) 315 { 316 struct pthread_attr_private *p; 317 318 if ((p = attr->pta_private) == NULL) { 319 *addr = NULL; 320 *size = pthread__stacksize; 321 } else { 322 *addr = p->ptap_stackaddr; 323 *size = p->ptap_stacksize; 324 } 325 326 return 0; 327 } 328 329 330 int 331 pthread_attr_setstack(pthread_attr_t *attr, void *addr, size_t size) 332 { 333 struct pthread_attr_private *p; 334 335 p = pthread__attr_init_private(attr); 336 if (p == NULL) 337 return ENOMEM; 338 339 p->ptap_stackaddr = addr; 340 p->ptap_stacksize = size; 341 342 return 0; 343 } 344 345 346 int 347 pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *size) 348 { 349 struct pthread_attr_private *p; 350 351 if ((p = attr->pta_private) == NULL) 352 *size = pthread__stacksize; 353 else 354 *size = p->ptap_stacksize; 355 356 return 0; 357 } 358 359 360 int 361 pthread_attr_setstacksize(pthread_attr_t *attr, size_t size) 362 { 363 struct pthread_attr_private *p; 364 365 if (size < (size_t)sysconf(_SC_THREAD_STACK_MIN)) 366 return EINVAL; 367 368 p = pthread__attr_init_private(attr); 369 if (p == NULL) 370 return ENOMEM; 371 372 p->ptap_stacksize = size; 373 374 return 0; 375 } 376 377 378 int 379 pthread_attr_getstackaddr(const pthread_attr_t *attr, void **addr) 380 { 381 struct pthread_attr_private *p; 382 383 if ((p = attr->pta_private) == NULL) 384 *addr = NULL; 385 else 386 *addr = p->ptap_stackaddr; 387 388 return 0; 389 } 390 391 392 int 393 pthread_attr_setstackaddr(pthread_attr_t *attr, void *addr) 394 { 395 struct pthread_attr_private *p; 396 397 p = pthread__attr_init_private(attr); 398 if (p == NULL) 399 return ENOMEM; 400 401 p->ptap_stackaddr = addr; 402 403 return 0; 404 } 405 406 407 int 408 pthread_attr_getname_np(const pthread_attr_t *attr, char *name, size_t len, 409 void **argp) 410 { 411 struct pthread_attr_private *p; 412 413 if ((p = attr->pta_private) == NULL) { 414 name[0] = '\0'; 415 if (argp != NULL) 416 *argp = NULL; 417 } else { 418 strlcpy(name, p->ptap_name, len); 419 if (argp != NULL) 420 *argp = p->ptap_namearg; 421 } 422 423 return 0; 424 } 425 426 427 int 428 pthread_attr_setname_np(pthread_attr_t *attr, const char *name, void *arg) 429 { 430 struct pthread_attr_private *p; 431 int namelen; 432 433 p = pthread__attr_init_private(attr); 434 if (p == NULL) 435 return ENOMEM; 436 437 namelen = snprintf(p->ptap_name, PTHREAD_MAX_NAMELEN_NP, name, arg); 438 if (namelen >= PTHREAD_MAX_NAMELEN_NP) { 439 p->ptap_name[0] = '\0'; 440 return EINVAL; 441 } 442 p->ptap_namearg = arg; 443 444 return 0; 445 } 446 447 int 448 pthread_attr_setcreatesuspend_np(pthread_attr_t *attr) 449 { 450 attr->pta_flags |= PT_FLAG_SUSPENDED; 451 return 0; 452 } 453 454 int 455 pthread_getattr_np(pthread_t thread, pthread_attr_t *attr) 456 { 457 int error; 458 if ((error = pthread_attr_init(attr)) != 0) 459 return error; 460 if ((error = pthread_attr_get_np(thread, attr)) != 0) { 461 (void)pthread_attr_destroy(attr); 462 return error; 463 } 464 return 0; 465 } 466