lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame^] | 1 | /* Linuxthreads - a simple clone()-based implementation of Posix */ |
| 2 | /* threads for Linux. */ |
| 3 | /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */ |
| 4 | /* */ |
| 5 | /* This program is free software; you can redistribute it and/or */ |
| 6 | /* modify it under the terms of the GNU Library General Public License */ |
| 7 | /* as published by the Free Software Foundation; either version 2 */ |
| 8 | /* of the License, or (at your option) any later version. */ |
| 9 | /* */ |
| 10 | /* This program is distributed in the hope that it will be useful, */ |
| 11 | /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ |
| 12 | /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ |
| 13 | /* GNU Library General Public License for more details. */ |
| 14 | |
| 15 | /* Handling of thread attributes */ |
| 16 | |
| 17 | #include <errno.h> |
| 18 | #include <inttypes.h> |
| 19 | #include <stdio.h> |
| 20 | #include <stdio_ext.h> |
| 21 | #include <stdlib.h> |
| 22 | #include <string.h> |
| 23 | #include <unistd.h> |
| 24 | #include <sys/param.h> |
| 25 | #include <sys/resource.h> |
| 26 | #include "pthread.h" |
| 27 | #include "internals.h" |
| 28 | |
| 29 | |
| 30 | int __pthread_attr_init(pthread_attr_t *attr) |
| 31 | { |
| 32 | size_t ps = __getpagesize (); |
| 33 | |
| 34 | attr->__detachstate = PTHREAD_CREATE_JOINABLE; |
| 35 | attr->__schedpolicy = SCHED_OTHER; |
| 36 | attr->__schedparam.sched_priority = 0; |
| 37 | attr->__inheritsched = PTHREAD_EXPLICIT_SCHED; |
| 38 | attr->__scope = PTHREAD_SCOPE_SYSTEM; |
| 39 | #ifdef NEED_SEPARATE_REGISTER_STACK |
| 40 | attr->__guardsize = ps + ps; |
| 41 | #else |
| 42 | attr->__guardsize = ps; |
| 43 | #endif |
| 44 | attr->__stackaddr = NULL; |
| 45 | attr->__stackaddr_set = 0; |
| 46 | attr->__stacksize = STACK_SIZE - ps; |
| 47 | return 0; |
| 48 | } |
| 49 | strong_alias (__pthread_attr_init, pthread_attr_init) |
| 50 | |
| 51 | int __pthread_attr_destroy(pthread_attr_t *attr) |
| 52 | { |
| 53 | return 0; |
| 54 | } |
| 55 | strong_alias (__pthread_attr_destroy, pthread_attr_destroy) |
| 56 | |
| 57 | int __pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) |
| 58 | { |
| 59 | if (detachstate < PTHREAD_CREATE_JOINABLE || |
| 60 | detachstate > PTHREAD_CREATE_DETACHED) |
| 61 | return EINVAL; |
| 62 | attr->__detachstate = detachstate; |
| 63 | return 0; |
| 64 | } |
| 65 | strong_alias (__pthread_attr_setdetachstate, pthread_attr_setdetachstate) |
| 66 | |
| 67 | int __pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) |
| 68 | { |
| 69 | *detachstate = attr->__detachstate; |
| 70 | return 0; |
| 71 | } |
| 72 | strong_alias (__pthread_attr_getdetachstate, pthread_attr_getdetachstate) |
| 73 | |
| 74 | int __pthread_attr_setschedparam(pthread_attr_t *attr, |
| 75 | const struct sched_param *param) |
| 76 | { |
| 77 | int max_prio = __sched_get_priority_max(attr->__schedpolicy); |
| 78 | int min_prio = __sched_get_priority_min(attr->__schedpolicy); |
| 79 | |
| 80 | if (param->sched_priority < min_prio || param->sched_priority > max_prio) |
| 81 | return EINVAL; |
| 82 | memcpy (&attr->__schedparam, param, sizeof (struct sched_param)); |
| 83 | return 0; |
| 84 | } |
| 85 | strong_alias (__pthread_attr_setschedparam, pthread_attr_setschedparam) |
| 86 | |
| 87 | int __pthread_attr_getschedparam(const pthread_attr_t *attr, |
| 88 | struct sched_param *param) |
| 89 | { |
| 90 | memcpy (param, &attr->__schedparam, sizeof (struct sched_param)); |
| 91 | return 0; |
| 92 | } |
| 93 | strong_alias (__pthread_attr_getschedparam, pthread_attr_getschedparam) |
| 94 | |
| 95 | int __pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) |
| 96 | { |
| 97 | if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR) |
| 98 | return EINVAL; |
| 99 | attr->__schedpolicy = policy; |
| 100 | return 0; |
| 101 | } |
| 102 | strong_alias (__pthread_attr_setschedpolicy, pthread_attr_setschedpolicy) |
| 103 | |
| 104 | int __pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) |
| 105 | { |
| 106 | *policy = attr->__schedpolicy; |
| 107 | return 0; |
| 108 | } |
| 109 | strong_alias (__pthread_attr_getschedpolicy, pthread_attr_getschedpolicy) |
| 110 | |
| 111 | int __pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit) |
| 112 | { |
| 113 | if (inherit != PTHREAD_INHERIT_SCHED && inherit != PTHREAD_EXPLICIT_SCHED) |
| 114 | return EINVAL; |
| 115 | attr->__inheritsched = inherit; |
| 116 | return 0; |
| 117 | } |
| 118 | strong_alias (__pthread_attr_setinheritsched, pthread_attr_setinheritsched) |
| 119 | |
| 120 | int __pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inherit) |
| 121 | { |
| 122 | *inherit = attr->__inheritsched; |
| 123 | return 0; |
| 124 | } |
| 125 | strong_alias (__pthread_attr_getinheritsched, pthread_attr_getinheritsched) |
| 126 | |
| 127 | int __pthread_attr_setscope(pthread_attr_t *attr, int scope) |
| 128 | { |
| 129 | switch (scope) { |
| 130 | case PTHREAD_SCOPE_SYSTEM: |
| 131 | attr->__scope = scope; |
| 132 | return 0; |
| 133 | case PTHREAD_SCOPE_PROCESS: |
| 134 | return ENOTSUP; |
| 135 | default: |
| 136 | return EINVAL; |
| 137 | } |
| 138 | } |
| 139 | strong_alias (__pthread_attr_setscope, pthread_attr_setscope) |
| 140 | |
| 141 | int __pthread_attr_getscope(const pthread_attr_t *attr, int *scope) |
| 142 | { |
| 143 | *scope = attr->__scope; |
| 144 | return 0; |
| 145 | } |
| 146 | strong_alias (__pthread_attr_getscope, pthread_attr_getscope) |
| 147 | |
| 148 | int __pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) |
| 149 | { |
| 150 | /* The guard size must not be larger than the stack itself */ |
| 151 | if (guardsize >= attr->__stacksize) return EINVAL; |
| 152 | |
| 153 | attr->__guardsize = guardsize; |
| 154 | |
| 155 | return 0; |
| 156 | } |
| 157 | weak_alias (__pthread_attr_setguardsize, pthread_attr_setguardsize) |
| 158 | |
| 159 | int __pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize) |
| 160 | { |
| 161 | *guardsize = attr->__guardsize; |
| 162 | return 0; |
| 163 | } |
| 164 | weak_alias (__pthread_attr_getguardsize, pthread_attr_getguardsize) |
| 165 | |
| 166 | #if 0 /* uClibc: deprecated stuff disabled */ |
| 167 | int __pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) |
| 168 | { |
| 169 | attr->__stackaddr = stackaddr; |
| 170 | attr->__stackaddr_set = 1; |
| 171 | return 0; |
| 172 | } |
| 173 | weak_alias (__pthread_attr_setstackaddr, pthread_attr_setstackaddr) |
| 174 | |
| 175 | link_warning (pthread_attr_setstackaddr, |
| 176 | "the use of `pthread_attr_setstackaddr' is deprecated, use `pthread_attr_setstack'") |
| 177 | |
| 178 | int __pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) |
| 179 | { |
| 180 | /* XXX This function has a stupid definition. The standard specifies |
| 181 | no error value but what is if no stack address was set? We simply |
| 182 | return the value we have in the member. */ |
| 183 | *stackaddr = attr->__stackaddr; |
| 184 | return 0; |
| 185 | } |
| 186 | weak_alias (__pthread_attr_getstackaddr, pthread_attr_getstackaddr) |
| 187 | |
| 188 | link_warning (pthread_attr_getstackaddr, |
| 189 | "the use of `pthread_attr_getstackaddr' is deprecated, use `pthread_attr_getstack'") |
| 190 | #endif |
| 191 | |
| 192 | |
| 193 | int __pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) |
| 194 | { |
| 195 | #ifdef FLOATING_STACKS |
| 196 | /* We have to check against the maximum allowed stack size. This is no |
| 197 | problem if the manager is already started and we determined it. If |
| 198 | this hasn't happened, we have to find the limit outself. */ |
| 199 | if (__pthread_max_stacksize == 0) |
| 200 | __pthread_init_max_stacksize (); |
| 201 | |
| 202 | if (stacksize > __pthread_max_stacksize) |
| 203 | return EINVAL; |
| 204 | #else |
| 205 | /* We have a fixed size limit. */ |
| 206 | if (stacksize > STACK_SIZE) |
| 207 | return EINVAL; |
| 208 | #endif |
| 209 | |
| 210 | /* We don't accept value smaller than PTHREAD_STACK_MIN. */ |
| 211 | if (stacksize < PTHREAD_STACK_MIN) |
| 212 | return EINVAL; |
| 213 | |
| 214 | attr->__stacksize = stacksize; |
| 215 | return 0; |
| 216 | } |
| 217 | |
| 218 | #if PTHREAD_STACK_MIN == 16384 || defined __UCLIBC__ |
| 219 | weak_alias (__pthread_attr_setstacksize, pthread_attr_setstacksize) |
| 220 | #else |
| 221 | versioned_symbol (libpthread, __pthread_attr_setstacksize, |
| 222 | pthread_attr_setstacksize, GLIBC_2_3_3); |
| 223 | |
| 224 | # if SHLIB_COMPAT(libpthread, GLIBC_2_1, GLIBC_2_3_3) |
| 225 | |
| 226 | int __old_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) |
| 227 | { |
| 228 | # ifdef FLOATING_STACKS |
| 229 | /* We have to check against the maximum allowed stack size. This is no |
| 230 | problem if the manager is already started and we determined it. If |
| 231 | this hasn't happened, we have to find the limit outself. */ |
| 232 | if (__pthread_max_stacksize == 0) |
| 233 | __pthread_init_max_stacksize (); |
| 234 | |
| 235 | if (stacksize > __pthread_max_stacksize) |
| 236 | return EINVAL; |
| 237 | # else |
| 238 | /* We have a fixed size limit. */ |
| 239 | if (stacksize > STACK_SIZE) |
| 240 | return EINVAL; |
| 241 | # endif |
| 242 | |
| 243 | /* We don't accept value smaller than old PTHREAD_STACK_MIN. */ |
| 244 | if (stacksize < 16384) |
| 245 | return EINVAL; |
| 246 | |
| 247 | attr->__stacksize = stacksize; |
| 248 | return 0; |
| 249 | } |
| 250 | compat_symbol (libpthread, __old_pthread_attr_setstacksize, |
| 251 | pthread_attr_setstacksize, GLIBC_2_1); |
| 252 | # endif |
| 253 | #endif |
| 254 | |
| 255 | |
| 256 | int __pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) |
| 257 | { |
| 258 | *stacksize = attr->__stacksize; |
| 259 | return 0; |
| 260 | } |
| 261 | weak_alias (__pthread_attr_getstacksize, pthread_attr_getstacksize) |
| 262 | |
| 263 | int __pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, |
| 264 | size_t stacksize) |
| 265 | { |
| 266 | int err; |
| 267 | |
| 268 | if ((((uintptr_t) stackaddr) |
| 269 | & (__alignof__ (struct _pthread_descr_struct) - 1)) != 0) |
| 270 | err = EINVAL; |
| 271 | else |
| 272 | err = __pthread_attr_setstacksize (attr, stacksize); |
| 273 | if (err == 0) |
| 274 | { |
| 275 | #ifndef _STACK_GROWS_UP |
| 276 | attr->__stackaddr = (char *) stackaddr + stacksize; |
| 277 | #else |
| 278 | attr->__stackaddr = stackaddr; |
| 279 | #endif |
| 280 | attr->__stackaddr_set = 1; |
| 281 | } |
| 282 | |
| 283 | return err; |
| 284 | } |
| 285 | |
| 286 | #if PTHREAD_STACK_MIN == 16384 || defined __UCLIBC__ |
| 287 | weak_alias (__pthread_attr_setstack, pthread_attr_setstack) |
| 288 | #else |
| 289 | versioned_symbol (libpthread, __pthread_attr_setstack, pthread_attr_setstack, |
| 290 | GLIBC_2_3_3); |
| 291 | # if SHLIB_COMPAT(libpthread, GLIBC_2_2, GLIBC_2_3_3) |
| 292 | int __old_pthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, |
| 293 | size_t stacksize) |
| 294 | { |
| 295 | int err; |
| 296 | |
| 297 | if ((((uintptr_t) stackaddr) |
| 298 | & (__alignof__ (struct _pthread_descr_struct) - 1)) != 0) |
| 299 | err = EINVAL; |
| 300 | else |
| 301 | err = __old_pthread_attr_setstacksize (attr, stacksize); |
| 302 | if (err == 0) |
| 303 | { |
| 304 | # ifndef _STACK_GROWS_UP |
| 305 | attr->__stackaddr = (char *) stackaddr + stacksize; |
| 306 | # else |
| 307 | attr->__stackaddr = stackaddr; |
| 308 | # endif |
| 309 | attr->__stackaddr_set = 1; |
| 310 | } |
| 311 | |
| 312 | return err; |
| 313 | } |
| 314 | |
| 315 | compat_symbol (libpthread, __old_pthread_attr_setstack, pthread_attr_setstack, |
| 316 | GLIBC_2_2); |
| 317 | |
| 318 | # endif |
| 319 | #endif |
| 320 | |
| 321 | int __pthread_attr_getstack (const pthread_attr_t *attr, void **stackaddr, |
| 322 | size_t *stacksize) |
| 323 | { |
| 324 | /* XXX This function has a stupid definition. The standard specifies |
| 325 | no error value but what is if no stack address was set? We simply |
| 326 | return the value we have in the member. */ |
| 327 | #ifndef _STACK_GROWS_UP |
| 328 | *stackaddr = (char *) attr->__stackaddr - attr->__stacksize; |
| 329 | #else |
| 330 | *stackaddr = attr->__stackaddr; |
| 331 | #endif |
| 332 | *stacksize = attr->__stacksize; |
| 333 | return 0; |
| 334 | } |
| 335 | weak_alias (__pthread_attr_getstack, pthread_attr_getstack) |
| 336 | |
| 337 | int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr) |
| 338 | { |
| 339 | pthread_handle handle = thread_handle (thread); |
| 340 | pthread_descr descr; |
| 341 | int ret = 0; |
| 342 | |
| 343 | if (handle == NULL) |
| 344 | return ENOENT; |
| 345 | |
| 346 | descr = handle->h_descr; |
| 347 | |
| 348 | attr->__detachstate = (descr->p_detached |
| 349 | ? PTHREAD_CREATE_DETACHED |
| 350 | : PTHREAD_CREATE_JOINABLE); |
| 351 | |
| 352 | attr->__schedpolicy = __sched_getscheduler (descr->p_pid); |
| 353 | if (attr->__schedpolicy == -1) |
| 354 | return errno; |
| 355 | |
| 356 | if (__sched_getparam (descr->p_pid, |
| 357 | (struct sched_param *) &attr->__schedparam) != 0) |
| 358 | return errno; |
| 359 | |
| 360 | attr->__inheritsched = descr->p_inheritsched; |
| 361 | attr->__scope = PTHREAD_SCOPE_SYSTEM; |
| 362 | |
| 363 | #ifdef _STACK_GROWS_DOWN |
| 364 | # ifdef USE_TLS |
| 365 | attr->__stacksize = descr->p_stackaddr - (char *)descr->p_guardaddr |
| 366 | - descr->p_guardsize; |
| 367 | # else |
| 368 | attr->__stacksize = (char *)(descr + 1) - (char *)descr->p_guardaddr |
| 369 | - descr->p_guardsize; |
| 370 | # endif |
| 371 | #else |
| 372 | # ifdef USE_TLS |
| 373 | attr->__stacksize = (char *)descr->p_guardaddr - descr->p_stackaddr; |
| 374 | # else |
| 375 | attr->__stacksize = (char *)descr->p_guardaddr - (char *)descr; |
| 376 | # endif |
| 377 | #endif |
| 378 | attr->__guardsize = descr->p_guardsize; |
| 379 | attr->__stackaddr_set = descr->p_userstack; |
| 380 | #ifdef NEED_SEPARATE_REGISTER_STACK |
| 381 | if (descr->p_userstack == 0) |
| 382 | attr->__stacksize *= 2; |
| 383 | /* XXX This is awkward. The guard pages are in the middle of the |
| 384 | two stacks. We must count the guard size in the stack size since |
| 385 | otherwise the range of the stack area cannot be computed. */ |
| 386 | attr->__stacksize += attr->__guardsize; |
| 387 | #endif |
| 388 | #ifdef USE_TLS |
| 389 | attr->__stackaddr = descr->p_stackaddr; |
| 390 | #else |
| 391 | # ifndef _STACK_GROWS_UP |
| 392 | attr->__stackaddr = (char *)(descr + 1); |
| 393 | # else |
| 394 | attr->__stackaddr = (char *)descr; |
| 395 | # endif |
| 396 | #endif |
| 397 | |
| 398 | #ifdef USE_TLS |
| 399 | if (attr->__stackaddr == NULL) |
| 400 | #else |
| 401 | if (descr == &__pthread_initial_thread) |
| 402 | #endif |
| 403 | { |
| 404 | /* Stack size limit. */ |
| 405 | struct rlimit rl; |
| 406 | |
| 407 | /* The safest way to get the top of the stack is to read |
| 408 | /proc/self/maps and locate the line into which |
| 409 | __libc_stack_end falls. */ |
| 410 | FILE *fp = fopen ("/proc/self/maps", "rc"); |
| 411 | if (fp == NULL) |
| 412 | ret = errno; |
| 413 | /* We need the limit of the stack in any case. */ |
| 414 | else if (getrlimit (RLIMIT_STACK, &rl) != 0) |
| 415 | ret = errno; |
| 416 | else |
| 417 | { |
| 418 | /* We need no locking. */ |
| 419 | __fsetlocking (fp, FSETLOCKING_BYCALLER); |
| 420 | |
| 421 | /* Until we found an entry (which should always be the case) |
| 422 | mark the result as a failure. */ |
| 423 | ret = ENOENT; |
| 424 | |
| 425 | char *line = NULL; |
| 426 | size_t linelen = 0; |
| 427 | uintptr_t last_to = 0; |
| 428 | |
| 429 | while (! feof_unlocked (fp)) |
| 430 | { |
| 431 | if (getdelim (&line, &linelen, '\n', fp) <= 0) |
| 432 | break; |
| 433 | |
| 434 | uintptr_t from; |
| 435 | uintptr_t to; |
| 436 | if (sscanf (line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2) |
| 437 | continue; |
| 438 | if (from <= (uintptr_t) __libc_stack_end |
| 439 | && (uintptr_t) __libc_stack_end < to) |
| 440 | { |
| 441 | /* Found the entry. Now we have the info we need. */ |
| 442 | attr->__stacksize = rl.rlim_cur; |
| 443 | #ifdef _STACK_GROWS_UP |
| 444 | /* Don't check to enforce a limit on the __stacksize */ |
| 445 | attr->__stackaddr = (void *) from; |
| 446 | #else |
| 447 | attr->__stackaddr = (void *) to; |
| 448 | |
| 449 | /* The limit might be too high. */ |
| 450 | if ((size_t) attr->__stacksize |
| 451 | > (size_t) attr->__stackaddr - last_to) |
| 452 | attr->__stacksize = (size_t) attr->__stackaddr - last_to; |
| 453 | #endif |
| 454 | |
| 455 | /* We succeed and no need to look further. */ |
| 456 | ret = 0; |
| 457 | break; |
| 458 | } |
| 459 | last_to = to; |
| 460 | } |
| 461 | |
| 462 | fclose (fp); |
| 463 | free (line); |
| 464 | } |
| 465 | } |
| 466 | |
| 467 | return 0; |
| 468 | |
| 469 | } |