1/* $NetBSD: pthread_attr.c,v 1.14 2010/08/06 14:23:06 christos 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.14 2010/08/06 14:23:06 christos 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 50static struct pthread_attr_private *pthread__attr_init_private( 51 pthread_attr_t *); 52 53static struct pthread_attr_private * 54pthread__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 = malloc(sizeof(*p)); 62 if (p != NULL) { 63 memset(p, 0, sizeof(*p)); 64 attr->pta_private = p; 65 p->ptap_policy = SCHED_OTHER; 66 } 67 return p; 68} 69 70 71int 72pthread_attr_init(pthread_attr_t *attr) 73{ 74 75 attr->pta_magic = PT_ATTR_MAGIC; 76 attr->pta_flags = 0; 77 attr->pta_private = NULL; 78 79 return 0; 80} 81 82 83int 84pthread_attr_destroy(pthread_attr_t *attr) 85{ 86 struct pthread_attr_private *p; 87 88 if ((p = attr->pta_private) != NULL) 89 free(p); 90 91 return 0; 92} 93 94 95int 96pthread_attr_get_np(pthread_t thread, pthread_attr_t *attr) 97{ 98 struct pthread_attr_private *p; 99 100 p = pthread__attr_init_private(attr); 101 if (p == NULL) 102 return ENOMEM; 103 104 attr->pta_flags = thread->pt_flags & 105 (PT_FLAG_DETACHED | PT_FLAG_SCOPE_SYSTEM | PT_FLAG_EXPLICIT_SCHED); 106 107 p->ptap_namearg = thread->pt_name; 108 p->ptap_stackaddr = thread->pt_stack.ss_sp; 109 p->ptap_stacksize = thread->pt_stack.ss_size; 110 p->ptap_guardsize = (size_t)sysconf(_SC_PAGESIZE); 111 return pthread_getschedparam(thread, &p->ptap_policy, &p->ptap_sp); 112} 113 114 115int 116pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) 117{ 118 119 if (attr->pta_flags & PT_FLAG_DETACHED) 120 *detachstate = PTHREAD_CREATE_DETACHED; 121 else 122 *detachstate = PTHREAD_CREATE_JOINABLE; 123 124 return 0; 125} 126 127 128int 129pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) 130{ 131 132 switch (detachstate) { 133 case PTHREAD_CREATE_JOINABLE: 134 attr->pta_flags &= ~PT_FLAG_DETACHED; 135 break; 136 case PTHREAD_CREATE_DETACHED: 137 attr->pta_flags |= PT_FLAG_DETACHED; 138 break; 139 default: 140 return EINVAL; 141 } 142 143 return 0; 144} 145 146 147int 148pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guard) 149{ 150 struct pthread_attr_private *p; 151 152 if ((p = attr->pta_private) == NULL) 153 *guard = (size_t)sysconf(_SC_PAGESIZE); 154 else 155 *guard = p->ptap_guardsize; 156 157 return 0; 158} 159 160 161int 162pthread_attr_setguardsize(pthread_attr_t *attr, size_t guard) 163{ 164 struct pthread_attr_private *p; 165 166 p = pthread__attr_init_private(attr); 167 if (p == NULL) 168 return ENOMEM; 169 170 p->ptap_guardsize = guard; 171 172 return 0; 173} 174 175 176int 177pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit) 178{ 179 180 if (attr->pta_flags & PT_FLAG_EXPLICIT_SCHED) 181 *inherit = PTHREAD_EXPLICIT_SCHED; 182 else 183 *inherit = PTHREAD_INHERIT_SCHED; 184 185 return 0; 186} 187 188 189int 190pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit) 191{ 192 193 switch (inherit) { 194 case PTHREAD_INHERIT_SCHED: 195 attr->pta_flags &= ~PT_FLAG_EXPLICIT_SCHED; 196 break; 197 case PTHREAD_EXPLICIT_SCHED: 198 attr->pta_flags |= PT_FLAG_EXPLICIT_SCHED; 199 break; 200 default: 201 return EINVAL; 202 } 203 204 return 0; 205} 206 207 208int 209pthread_attr_getscope(const pthread_attr_t *attr, int *scope) 210{ 211 212 if (attr->pta_flags & PT_FLAG_SCOPE_SYSTEM) 213 *scope = PTHREAD_SCOPE_SYSTEM; 214 else 215 *scope = PTHREAD_SCOPE_PROCESS; 216 217 return 0; 218} 219 220 221int 222pthread_attr_setscope(pthread_attr_t *attr, int scope) 223{ 224 225 switch (scope) { 226 case PTHREAD_SCOPE_PROCESS: 227 attr->pta_flags &= ~PT_FLAG_SCOPE_SYSTEM; 228 break; 229 case PTHREAD_SCOPE_SYSTEM: 230 attr->pta_flags |= PT_FLAG_SCOPE_SYSTEM; 231 break; 232 default: 233 return EINVAL; 234 } 235 236 return 0; 237} 238 239 240int 241pthread_attr_setschedparam(pthread_attr_t *attr, 242 const struct sched_param *param) 243{ 244 struct pthread_attr_private *p; 245 int error; 246 247 if (param == NULL) 248 return EINVAL; 249 p = pthread__attr_init_private(attr); 250 if (p == NULL) 251 return ENOMEM; 252 error = pthread__checkpri(param->sched_priority); 253 if (error == 0) 254 p->ptap_sp = *param; 255 return error; 256} 257 258 259int 260pthread_attr_getschedparam(const pthread_attr_t *attr, 261 struct sched_param *param) 262{ 263 struct pthread_attr_private *p; 264 265 if (param == NULL) 266 return EINVAL; 267 p = attr->pta_private; 268 if (p == NULL) 269 memset(param, 0, sizeof(*param)); 270 else 271 *param = p->ptap_sp; 272 return 0; 273} 274 275 276int 277pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) 278{ 279 struct pthread_attr_private *p; 280 281 282 switch (policy) { 283 case SCHED_OTHER: 284 case SCHED_FIFO: 285 case SCHED_RR: 286 p = pthread__attr_init_private(attr); 287 if (p == NULL) 288 return ENOMEM; 289 p->ptap_policy = policy; 290 return 0; 291 default: 292 return ENOTSUP; 293 } 294} 295 296 297int 298pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) 299{ 300 struct pthread_attr_private *p; 301 302 p = attr->pta_private; 303 if (p == NULL) { 304 *policy = SCHED_OTHER; 305 return 0; 306 } 307 *policy = p->ptap_policy; 308 return 0; 309} 310 311 312int 313pthread_attr_getstack(const pthread_attr_t *attr, void **addr, size_t *size) 314{ 315 struct pthread_attr_private *p; 316 317 if ((p = attr->pta_private) == NULL) { 318 *addr = NULL; 319 *size = pthread__stacksize; 320 } else { 321 *addr = p->ptap_stackaddr; 322 *size = p->ptap_stacksize; 323 } 324 325 return 0; 326} 327 328 329int 330pthread_attr_setstack(pthread_attr_t *attr, void *addr, size_t size) 331{ 332 struct pthread_attr_private *p; 333 334 p = pthread__attr_init_private(attr); 335 if (p == NULL) 336 return ENOMEM; 337 338 p->ptap_stackaddr = addr; 339 p->ptap_stacksize = size; 340 341 return 0; 342} 343 344 345int 346pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *size) 347{ 348 struct pthread_attr_private *p; 349 350 if ((p = attr->pta_private) == NULL) 351 *size = pthread__stacksize; 352 else 353 *size = p->ptap_stacksize; 354 355 return 0; 356} 357 358 359int 360pthread_attr_setstacksize(pthread_attr_t *attr, size_t size) 361{ 362 struct pthread_attr_private *p; 363 364 if (size < (size_t)sysconf(_SC_THREAD_STACK_MIN)) 365 return EINVAL; 366 367 p = pthread__attr_init_private(attr); 368 if (p == NULL) 369 return ENOMEM; 370 371 p->ptap_stacksize = size; 372 373 return 0; 374} 375 376 377int 378pthread_attr_getstackaddr(const pthread_attr_t *attr, void **addr) 379{ 380 struct pthread_attr_private *p; 381 382 if ((p = attr->pta_private) == NULL) 383 *addr = NULL; 384 else 385 *addr = p->ptap_stackaddr; 386 387 return 0; 388} 389 390 391int 392pthread_attr_setstackaddr(pthread_attr_t *attr, void *addr) 393{ 394 struct pthread_attr_private *p; 395 396 p = pthread__attr_init_private(attr); 397 if (p == NULL) 398 return ENOMEM; 399 400 p->ptap_stackaddr = addr; 401 402 return 0; 403} 404 405 406int 407pthread_attr_getname_np(const pthread_attr_t *attr, char *name, size_t len, 408 void **argp) 409{ 410 struct pthread_attr_private *p; 411 412 if ((p = attr->pta_private) == NULL) { 413 name[0] = '\0'; 414 if (argp != NULL) 415 *argp = NULL; 416 } else { 417 strlcpy(name, p->ptap_name, len); 418 if (argp != NULL) 419 *argp = p->ptap_namearg; 420 } 421 422 return 0; 423} 424 425 426int 427pthread_attr_setname_np(pthread_attr_t *attr, const char *name, void *arg) 428{ 429 struct pthread_attr_private *p; 430 int namelen; 431 432 p = pthread__attr_init_private(attr); 433 if (p == NULL) 434 return ENOMEM; 435 436 namelen = snprintf(p->ptap_name, PTHREAD_MAX_NAMELEN_NP, name, arg); 437 if (namelen >= PTHREAD_MAX_NAMELEN_NP) { 438 p->ptap_name[0] = '\0'; 439 return EINVAL; 440 } 441 p->ptap_namearg = arg; 442 443 return 0; 444} 445 446int 447pthread_attr_setcreatesuspend_np(pthread_attr_t *attr) 448{ 449 attr->pta_flags |= PT_FLAG_SUSPENDED; 450 return 0; 451} 452 453int 454pthread_getattr_np(pthread_t thread, pthread_attr_t *attr) 455{ 456 int error; 457 if ((error = pthread_attr_init(attr)) != 0) 458 return error; 459 if ((error = pthread_attr_get_np(thread, attr)) != 0) { 460 (void)pthread_attr_destroy(attr); 461 return error; 462 } 463 return 0; 464} 465