1 /* 2 * Copyright (c) 2003 Craig Rodrigues <rodrigc@attbi.com>. 3 * Copyright (c) 2002,2003 Alexey Zelkin <phantom@FreeBSD.org> 4 * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>. 5 * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. 6 * Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice(s), this list of conditions and the following disclaimer 14 * unmodified other than the allowable addition of one or more 15 * copyright notices. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice(s), this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY 22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 30 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 31 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "namespace.h" 35 #include <sys/types.h> 36 #include <sys/sysctl.h> 37 #include <machine/tls.h> 38 #include <errno.h> 39 #include <pthread.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <pthread_np.h> 43 #include "un-namespace.h" 44 45 #include "thr_private.h" 46 47 int 48 _pthread_attr_destroy(pthread_attr_t *attr) 49 { 50 int ret; 51 52 /* Check for invalid arguments: */ 53 if (attr == NULL || *attr == NULL) { 54 /* Invalid argument: */ 55 ret = EINVAL; 56 } else { 57 /* Free the memory allocated to the attribute object: */ 58 __free(*attr); 59 60 /* 61 * Leave the attribute pointer NULL now that the memory 62 * has been freed: 63 */ 64 *attr = NULL; 65 ret = 0; 66 } 67 return(ret); 68 } 69 70 __strong_reference(_pthread_attr_destroy, pthread_attr_destroy); 71 72 int 73 _pthread_attr_get_np(pthread_t pid, pthread_attr_t *dst) 74 { 75 struct pthread *curthread; 76 struct pthread_attr attr; 77 int ret; 78 79 if (pid == NULL || dst == NULL || *dst == NULL) 80 return (EINVAL); 81 82 curthread = tls_get_curthread(); 83 if ((ret = _thr_ref_add(curthread, pid, /*include dead*/0)) != 0) 84 return (ret); 85 attr = pid->attr; 86 if (pid->tlflags & TLFLAGS_DETACHED) 87 attr.flags |= PTHREAD_DETACHED; 88 _thr_ref_delete(curthread, pid); 89 memcpy(*dst, &attr, sizeof(struct pthread_attr)); 90 91 return (0); 92 } 93 94 __strong_reference(_pthread_attr_get_np, pthread_attr_get_np); 95 96 int 97 _pthread_attr_getaffinity_np(const pthread_attr_t *attr, size_t cpusetsize, 98 cpu_set_t *mask) 99 { 100 const cpu_set_t *ret; 101 cpu_set_t mask1; 102 103 if (attr == NULL || *attr == NULL || mask == NULL) 104 return (EINVAL); 105 106 if (((*attr)->flags & THR_CPUMASK) == 0) { 107 size_t len; 108 109 len = sizeof(mask1); 110 if (sysctlbyname("machdep.smp_active", &mask1, &len, 111 NULL, 0) < 0) 112 return (errno); 113 ret = &mask1; 114 } else { 115 ret = &(*attr)->cpumask; 116 } 117 118 if (cpusetsize > sizeof(*ret)) { 119 memset(mask, 0, cpusetsize); 120 memcpy(mask, ret, sizeof(*ret)); 121 } else { 122 memcpy(mask, ret, cpusetsize); 123 } 124 return (0); 125 } 126 127 __strong_reference(_pthread_attr_getaffinity_np, pthread_attr_getaffinity_np); 128 129 int 130 _pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) 131 { 132 int ret; 133 134 /* Check for invalid arguments: */ 135 if (attr == NULL || *attr == NULL || detachstate == NULL) 136 ret = EINVAL; 137 else { 138 /* Check if the detached flag is set: */ 139 if ((*attr)->flags & PTHREAD_DETACHED) 140 /* Return detached: */ 141 *detachstate = PTHREAD_CREATE_DETACHED; 142 else 143 /* Return joinable: */ 144 *detachstate = PTHREAD_CREATE_JOINABLE; 145 ret = 0; 146 } 147 return(ret); 148 } 149 150 __strong_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate); 151 152 int 153 _pthread_attr_getguardsize(const pthread_attr_t * __restrict attr, 154 size_t * __restrict guardsize) 155 { 156 int ret; 157 158 /* Check for invalid arguments: */ 159 if (attr == NULL || *attr == NULL || guardsize == NULL) 160 ret = EINVAL; 161 else { 162 /* Return the guard size: */ 163 *guardsize = (*attr)->guardsize_attr; 164 ret = 0; 165 } 166 return(ret); 167 } 168 169 __strong_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize); 170 171 int 172 _pthread_attr_getinheritsched(const pthread_attr_t * __restrict attr, 173 int * __restrict sched_inherit) 174 { 175 int ret = 0; 176 177 if ((attr == NULL) || (*attr == NULL)) 178 ret = EINVAL; 179 else 180 *sched_inherit = (*attr)->sched_inherit; 181 182 return(ret); 183 } 184 185 __strong_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched); 186 187 int 188 _pthread_attr_getschedparam(const pthread_attr_t * __restrict attr, 189 struct sched_param * __restrict param) 190 { 191 int ret = 0; 192 193 if ((attr == NULL) || (*attr == NULL) || (param == NULL)) 194 ret = EINVAL; 195 else 196 param->sched_priority = (*attr)->prio; 197 198 return(ret); 199 } 200 201 __strong_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam); 202 203 int 204 _pthread_attr_getschedpolicy(const pthread_attr_t * __restrict attr, 205 int * __restrict policy) 206 { 207 int ret = 0; 208 209 if ((attr == NULL) || (*attr == NULL) || (policy == NULL)) 210 ret = EINVAL; 211 else 212 *policy = (*attr)->sched_policy; 213 214 return(ret); 215 } 216 217 __strong_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy); 218 219 int 220 _pthread_attr_getscope(const pthread_attr_t * __restrict attr, 221 int * __restrict contentionscope) 222 { 223 int ret = 0; 224 225 if ((attr == NULL) || (*attr == NULL) || (contentionscope == NULL)) 226 /* Return an invalid argument: */ 227 ret = EINVAL; 228 229 else 230 *contentionscope = ((*attr)->flags & PTHREAD_SCOPE_SYSTEM) ? 231 PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS; 232 233 return(ret); 234 } 235 236 __strong_reference(_pthread_attr_getscope, pthread_attr_getscope); 237 238 int 239 _pthread_attr_getstack(const pthread_attr_t * __restrict attr, 240 void ** __restrict stackaddr, 241 size_t * __restrict stacksize) 242 { 243 int ret; 244 245 /* Check for invalid arguments: */ 246 if (attr == NULL || *attr == NULL || stackaddr == NULL 247 || stacksize == NULL ) 248 ret = EINVAL; 249 else { 250 /* Return the stack address and size */ 251 *stackaddr = (*attr)->stackaddr_attr; 252 *stacksize = (*attr)->stacksize_attr; 253 ret = 0; 254 } 255 return(ret); 256 } 257 258 __strong_reference(_pthread_attr_getstack, pthread_attr_getstack); 259 260 int 261 _pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) 262 { 263 int ret; 264 265 /* Check for invalid arguments: */ 266 if (attr == NULL || *attr == NULL || stackaddr == NULL) 267 ret = EINVAL; 268 else { 269 /* Return the stack address: */ 270 *stackaddr = (*attr)->stackaddr_attr; 271 ret = 0; 272 } 273 return(ret); 274 } 275 276 __strong_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr); 277 278 int 279 _pthread_attr_getstacksize(const pthread_attr_t * __restrict attr, 280 size_t * __restrict stacksize) 281 { 282 int ret; 283 284 /* Check for invalid arguments: */ 285 if (attr == NULL || *attr == NULL || stacksize == NULL) 286 ret = EINVAL; 287 else { 288 /* Return the stack size: */ 289 *stacksize = (*attr)->stacksize_attr; 290 ret = 0; 291 } 292 return(ret); 293 } 294 295 __strong_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize); 296 297 int 298 _pthread_attr_init(pthread_attr_t *attr) 299 { 300 int ret; 301 pthread_attr_t pattr; 302 303 /* Allocate memory for the attribute object: */ 304 pattr = __malloc(sizeof(struct pthread_attr)); 305 if (pattr == NULL) { 306 /* Insufficient memory: */ 307 ret = ENOMEM; 308 } else { 309 /* Initialise the attribute object with the defaults: */ 310 memcpy(pattr, &_pthread_attr_default, 311 sizeof(struct pthread_attr)); 312 313 /* Return a pointer to the attribute object: */ 314 *attr = pattr; 315 ret = 0; 316 } 317 return(ret); 318 } 319 320 __strong_reference(_pthread_attr_init, pthread_attr_init); 321 322 int 323 _pthread_attr_setaffinity_np(pthread_attr_t *attr, size_t cpusetsize, 324 const cpu_set_t *mask) 325 { 326 cpu_set_t active, mask1; 327 size_t len, cplen = cpusetsize; 328 329 if (attr == NULL || *attr == NULL || mask == NULL) 330 return (EINVAL); 331 332 if (cplen > sizeof(mask1)) 333 cplen = sizeof(mask1); 334 CPU_ZERO(&mask1); 335 memcpy(&mask1, mask, cplen); 336 337 len = sizeof(active); 338 if (sysctlbyname("machdep.smp_active", &active, &len, NULL, 0) < 0) 339 return (errno); 340 341 CPUMASK_ANDMASK(mask1, active); 342 if (CPUMASK_TESTZERO(mask1)) 343 return (EPERM); 344 345 (*attr)->cpumask = mask1; 346 (*attr)->flags |= THR_CPUMASK; 347 return (0); 348 } 349 350 __strong_reference(_pthread_attr_setaffinity_np, pthread_attr_setaffinity_np); 351 352 int 353 _pthread_attr_setcreatesuspend_np(pthread_attr_t *attr) 354 { 355 int ret; 356 357 if (attr == NULL || *attr == NULL) { 358 ret = EINVAL; 359 } else { 360 (*attr)->suspend = THR_CREATE_SUSPENDED; 361 ret = 0; 362 } 363 return(ret); 364 } 365 366 __strong_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np); 367 368 int 369 _pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) 370 { 371 int ret; 372 373 /* Check for invalid arguments: */ 374 if (attr == NULL || *attr == NULL || 375 (detachstate != PTHREAD_CREATE_DETACHED && 376 detachstate != PTHREAD_CREATE_JOINABLE)) 377 ret = EINVAL; 378 else { 379 /* Check if detached state: */ 380 if (detachstate == PTHREAD_CREATE_DETACHED) 381 /* Set the detached flag: */ 382 (*attr)->flags |= PTHREAD_DETACHED; 383 else 384 /* Reset the detached flag: */ 385 (*attr)->flags &= ~PTHREAD_DETACHED; 386 ret = 0; 387 } 388 return(ret); 389 } 390 391 __strong_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate); 392 393 int 394 _pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) 395 { 396 int ret; 397 398 /* Check for invalid arguments. */ 399 if (attr == NULL || *attr == NULL) 400 ret = EINVAL; 401 else { 402 /* Save the stack size. */ 403 (*attr)->guardsize_attr = guardsize; 404 ret = 0; 405 } 406 return(ret); 407 } 408 409 __strong_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize); 410 411 int 412 _pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit) 413 { 414 int ret = 0; 415 416 if ((attr == NULL) || (*attr == NULL)) 417 ret = EINVAL; 418 else if (sched_inherit != PTHREAD_INHERIT_SCHED && 419 sched_inherit != PTHREAD_EXPLICIT_SCHED) 420 ret = EINVAL; 421 else 422 (*attr)->sched_inherit = sched_inherit; 423 424 return(ret); 425 } 426 427 __strong_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched); 428 429 int 430 _pthread_attr_setschedparam(pthread_attr_t * __restrict attr, 431 const struct sched_param * __restrict param) 432 { 433 int policy; 434 435 if ((attr == NULL) || (*attr == NULL)) 436 return (EINVAL); 437 438 if (param == NULL) 439 return (ENOTSUP); 440 441 policy = (*attr)->sched_policy; 442 443 { 444 int minv = sched_get_priority_min(policy); 445 int maxv = sched_get_priority_max(policy); 446 if (minv == -1 || maxv == -1 || 447 param->sched_priority < minv || 448 param->sched_priority > maxv) { 449 return (ENOTSUP); 450 } 451 } 452 453 (*attr)->prio = param->sched_priority; 454 455 return (0); 456 } 457 458 __strong_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam); 459 460 int 461 _pthread_attr_setschedpolicy(pthread_attr_t *attr, int pol) 462 { 463 int ret = 0; 464 465 if ((attr == NULL) || (*attr == NULL)) 466 ret = EINVAL; 467 else if (pol != SCHED_FIFO && pol != SCHED_OTHER && pol != SCHED_RR) 468 ret = EINVAL; 469 else 470 (*attr)->sched_policy = pol; 471 472 return(ret); 473 } 474 475 __strong_reference(_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy); 476 477 int 478 _pthread_attr_setscope(pthread_attr_t *attr, int contentionscope) 479 { 480 int ret = 0; 481 482 if ((attr == NULL) || (*attr == NULL)) { 483 /* Return an invalid argument: */ 484 ret = EINVAL; 485 } else if ((contentionscope != PTHREAD_SCOPE_PROCESS) && 486 (contentionscope != PTHREAD_SCOPE_SYSTEM)) { 487 ret = EINVAL; 488 } else if (contentionscope == PTHREAD_SCOPE_SYSTEM) { 489 (*attr)->flags |= contentionscope; 490 } else { 491 (*attr)->flags &= ~PTHREAD_SCOPE_SYSTEM; 492 } 493 return (ret); 494 } 495 496 __strong_reference(_pthread_attr_setscope, pthread_attr_setscope); 497 498 int 499 _pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, 500 size_t stacksize) 501 { 502 int ret; 503 504 /* Check for invalid arguments: */ 505 if (attr == NULL || *attr == NULL || stackaddr == NULL 506 || stacksize < PTHREAD_STACK_MIN) 507 ret = EINVAL; 508 else { 509 /* Save the stack address and stack size */ 510 (*attr)->stackaddr_attr = stackaddr; 511 (*attr)->stacksize_attr = stacksize; 512 ret = 0; 513 } 514 return(ret); 515 } 516 517 __strong_reference(_pthread_attr_setstack, pthread_attr_setstack); 518 519 int 520 _pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) 521 { 522 int ret; 523 524 /* Check for invalid arguments: */ 525 if (attr == NULL || *attr == NULL || stackaddr == NULL) 526 ret = EINVAL; 527 else { 528 /* Save the stack address: */ 529 (*attr)->stackaddr_attr = stackaddr; 530 ret = 0; 531 } 532 return(ret); 533 } 534 535 __strong_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr); 536 537 int 538 _pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) 539 { 540 int ret; 541 542 /* Check for invalid arguments: */ 543 if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN) 544 ret = EINVAL; 545 else { 546 /* Save the stack size: */ 547 (*attr)->stacksize_attr = stacksize; 548 ret = 0; 549 } 550 return(ret); 551 } 552 553 __strong_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize); 554