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 | #ifndef _INTERNALS_H |
| 16 | #define _INTERNALS_H 1 |
| 17 | |
| 18 | #include "uClibc-glue.h" |
| 19 | |
| 20 | /* Internal data structures */ |
| 21 | |
| 22 | /* Includes */ |
| 23 | |
| 24 | #include <limits.h> |
| 25 | #include <signal.h> |
| 26 | #include <stdbool.h> |
| 27 | #include <unistd.h> |
| 28 | #include <sys/ucontext.h> |
| 29 | #include <bits/stackinfo.h> |
| 30 | #include <bits/sigcontextinfo.h> |
| 31 | #include <bits/pthreadtypes.h> |
| 32 | |
| 33 | #ifdef USE_TLS |
| 34 | #include <tls.h> |
| 35 | #endif |
| 36 | #include "descr.h" |
| 37 | |
| 38 | #include "semaphore.h" |
| 39 | #include <pthread-functions.h> |
| 40 | |
| 41 | #ifndef THREAD_GETMEM |
| 42 | # define THREAD_GETMEM(descr, member) descr->member |
| 43 | #endif |
| 44 | #ifndef THREAD_GETMEM_NC |
| 45 | # define THREAD_GETMEM_NC(descr, member) descr->member |
| 46 | #endif |
| 47 | #ifndef THREAD_SETMEM |
| 48 | # define THREAD_SETMEM(descr, member, value) descr->member = (value) |
| 49 | #endif |
| 50 | #ifndef THREAD_SETMEM_NC |
| 51 | # define THREAD_SETMEM_NC(descr, member, value) descr->member = (value) |
| 52 | #endif |
| 53 | |
| 54 | #if !defined NOT_IN_libc && defined FLOATING_STACKS |
| 55 | # define LIBC_THREAD_GETMEM(descr, member) THREAD_GETMEM (descr, member) |
| 56 | # define LIBC_THREAD_SETMEM(descr, member, value) \ |
| 57 | THREAD_SETMEM (descr, member, value) |
| 58 | #else |
| 59 | # define LIBC_THREAD_GETMEM(descr, member) descr->member |
| 60 | # define LIBC_THREAD_SETMEM(descr, member, value) descr->member = (value) |
| 61 | #endif |
| 62 | |
| 63 | typedef void (*destr_function)(void *); |
| 64 | |
| 65 | struct pthread_key_struct { |
| 66 | int in_use; /* already allocated? */ |
| 67 | destr_function destr; /* destruction routine */ |
| 68 | }; |
| 69 | |
| 70 | |
| 71 | #define PTHREAD_START_ARGS_INITIALIZER(fct) \ |
| 72 | { (void *(*) (void *)) fct, NULL, {{0, }}, 0, { 0 } } |
| 73 | |
| 74 | |
| 75 | /* The type of thread handles. */ |
| 76 | |
| 77 | typedef struct pthread_handle_struct * pthread_handle; |
| 78 | |
| 79 | struct pthread_handle_struct { |
| 80 | struct _pthread_fastlock h_lock; /* Fast lock for sychronized access */ |
| 81 | pthread_descr h_descr; /* Thread descriptor or NULL if invalid */ |
| 82 | char * h_bottom; /* Lowest address in the stack thread */ |
| 83 | }; |
| 84 | |
| 85 | /* The type of messages sent to the thread manager thread */ |
| 86 | |
| 87 | struct pthread_request { |
| 88 | pthread_descr req_thread; /* Thread doing the request */ |
| 89 | enum { /* Request kind */ |
| 90 | REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT, |
| 91 | REQ_POST, REQ_DEBUG, REQ_KICK, REQ_FOR_EACH_THREAD |
| 92 | } req_kind; |
| 93 | union { /* Arguments for request */ |
| 94 | struct { /* For REQ_CREATE: */ |
| 95 | const pthread_attr_t * attr; /* thread attributes */ |
| 96 | void * (*fn)(void *); /* start function */ |
| 97 | void * arg; /* argument to start function */ |
| 98 | sigset_t mask; /* signal mask */ |
| 99 | } create; |
| 100 | struct { /* For REQ_FREE: */ |
| 101 | pthread_t thread_id; /* identifier of thread to free */ |
| 102 | } free; |
| 103 | struct { /* For REQ_PROCESS_EXIT: */ |
| 104 | int code; /* exit status */ |
| 105 | } exit; |
| 106 | void * post; /* For REQ_POST: the semaphore */ |
| 107 | struct { /* For REQ_FOR_EACH_THREAD: callback */ |
| 108 | void (*fn)(void *, pthread_descr); |
| 109 | void *arg; |
| 110 | } for_each; |
| 111 | } req_args; |
| 112 | }; |
| 113 | |
| 114 | |
| 115 | |
| 116 | typedef void (*arch_sighandler_t) (int, SIGCONTEXT); |
| 117 | union sighandler |
| 118 | { |
| 119 | arch_sighandler_t old; |
| 120 | void (*rt) (int, struct siginfo *, struct ucontext *); |
| 121 | }; |
| 122 | extern union sighandler __sighandler[NSIG]; |
| 123 | |
| 124 | |
| 125 | /* Signals used for suspend/restart and for cancellation notification. */ |
| 126 | |
| 127 | extern int __pthread_sig_restart; |
| 128 | extern int __pthread_sig_cancel; |
| 129 | |
| 130 | /* Signal used for interfacing with gdb */ |
| 131 | |
| 132 | extern int __pthread_sig_debug; |
| 133 | |
| 134 | /* Global array of thread handles, used for validating a thread id |
| 135 | and retrieving the corresponding thread descriptor. Also used for |
| 136 | mapping the available stack segments. */ |
| 137 | |
| 138 | extern struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX]; |
| 139 | |
| 140 | /* Descriptor of the main thread */ |
| 141 | |
| 142 | extern pthread_descr __pthread_main_thread; |
| 143 | |
| 144 | /* File descriptor for sending requests to the thread manager. |
| 145 | Initially -1, meaning that __pthread_initialize_manager must be called. */ |
| 146 | |
| 147 | extern int __pthread_manager_request; |
| 148 | |
| 149 | /* Other end of the pipe for sending requests to the thread manager. */ |
| 150 | |
| 151 | extern int __pthread_manager_reader; |
| 152 | |
| 153 | #ifdef FLOATING_STACKS |
| 154 | /* Maximum stack size. */ |
| 155 | extern size_t __pthread_max_stacksize; |
| 156 | #endif |
| 157 | |
| 158 | /* Pending request for a process-wide exit */ |
| 159 | |
| 160 | extern int __pthread_exit_requested, __pthread_exit_code; |
| 161 | |
| 162 | /* Set to 1 by gdb if we're debugging */ |
| 163 | |
| 164 | extern __volatile__ int __pthread_threads_debug; |
| 165 | |
| 166 | /* Globally enabled events. */ |
| 167 | extern __volatile__ td_thr_events_t __pthread_threads_events; |
| 168 | |
| 169 | /* Pointer to descriptor of thread with last event. */ |
| 170 | extern __volatile__ pthread_descr __pthread_last_event; |
| 171 | |
| 172 | /* Flag which tells whether we are executing on SMP kernel. */ |
| 173 | extern int __pthread_smp_kernel; |
| 174 | |
| 175 | /* Return the handle corresponding to a thread id */ |
| 176 | |
| 177 | static __inline__ pthread_handle thread_handle(pthread_t id) |
| 178 | { |
| 179 | return &__pthread_handles[id % PTHREAD_THREADS_MAX]; |
| 180 | } |
| 181 | |
| 182 | /* Validate a thread handle. Must have acquired h->h_spinlock before. */ |
| 183 | |
| 184 | static __inline__ int invalid_handle(pthread_handle h, pthread_t id) |
| 185 | { |
| 186 | return h->h_descr == NULL || h->h_descr->p_tid != id || h->h_descr->p_terminated; |
| 187 | } |
| 188 | |
| 189 | static __inline__ int nonexisting_handle(pthread_handle h, pthread_t id) |
| 190 | { |
| 191 | return h->h_descr == NULL || h->h_descr->p_tid != id; |
| 192 | } |
| 193 | |
| 194 | /* Fill in defaults left unspecified by pt-machine.h. */ |
| 195 | |
| 196 | /* We round up a value with page size. */ |
| 197 | #ifndef page_roundup |
| 198 | #define page_roundup(v,p) ((((size_t) (v)) + (p) - 1) & ~((p) - 1)) |
| 199 | #endif |
| 200 | |
| 201 | /* The page size we can get from the system. This should likely not be |
| 202 | changed by the machine file but, you never know. */ |
| 203 | #ifndef PAGE_SIZE |
| 204 | #define PAGE_SIZE (sysconf (_SC_PAGE_SIZE)) |
| 205 | #endif |
| 206 | |
| 207 | /* The initial size of the thread stack. Must be a multiple of PAGE_SIZE. */ |
| 208 | #ifndef INITIAL_STACK_SIZE |
| 209 | #define INITIAL_STACK_SIZE (4 * PAGE_SIZE) |
| 210 | #endif |
| 211 | |
| 212 | /* Size of the thread manager stack. The "- 32" avoids wasting space |
| 213 | with some malloc() implementations. */ |
| 214 | #ifndef THREAD_MANAGER_STACK_SIZE |
| 215 | #define THREAD_MANAGER_STACK_SIZE (2 * PAGE_SIZE - 32) |
| 216 | #endif |
| 217 | |
| 218 | /* The base of the "array" of thread stacks. The array will grow down from |
| 219 | here. Defaults to the calculated bottom of the initial application |
| 220 | stack. */ |
| 221 | #ifndef THREAD_STACK_START_ADDRESS |
| 222 | #define THREAD_STACK_START_ADDRESS __pthread_initial_thread_bos |
| 223 | #endif |
| 224 | |
| 225 | /* If MEMORY_BARRIER isn't defined in pt-machine.h, assume the |
| 226 | architecture doesn't need a memory barrier instruction (e.g. Intel |
| 227 | x86). Still we need the compiler to respect the barrier and emit |
| 228 | all outstanding operations which modify memory. Some architectures |
| 229 | distinguish between full, read and write barriers. */ |
| 230 | |
| 231 | #ifndef MEMORY_BARRIER |
| 232 | #define MEMORY_BARRIER() __asm__ ("" : : : "memory") |
| 233 | #endif |
| 234 | #ifndef READ_MEMORY_BARRIER |
| 235 | #define READ_MEMORY_BARRIER() MEMORY_BARRIER() |
| 236 | #endif |
| 237 | #ifndef WRITE_MEMORY_BARRIER |
| 238 | #define WRITE_MEMORY_BARRIER() MEMORY_BARRIER() |
| 239 | #endif |
| 240 | |
| 241 | /* Max number of times we must spin on a spinlock calling sched_yield(). |
| 242 | After MAX_SPIN_COUNT iterations, we put the calling thread to sleep. */ |
| 243 | |
| 244 | #ifndef MAX_SPIN_COUNT |
| 245 | #define MAX_SPIN_COUNT 50 |
| 246 | #endif |
| 247 | |
| 248 | /* Max number of times the spinlock in the adaptive mutex implementation |
| 249 | spins actively on SMP systems. */ |
| 250 | |
| 251 | #ifndef MAX_ADAPTIVE_SPIN_COUNT |
| 252 | #define MAX_ADAPTIVE_SPIN_COUNT 100 |
| 253 | #endif |
| 254 | |
| 255 | /* Duration of sleep (in nanoseconds) when we can't acquire a spinlock |
| 256 | after MAX_SPIN_COUNT iterations of sched_yield(). |
| 257 | With the 2.0 and 2.1 kernels, this MUST BE > 2ms. |
| 258 | (Otherwise the kernel does busy-waiting for realtime threads, |
| 259 | giving other threads no chance to run.) */ |
| 260 | |
| 261 | #ifndef SPIN_SLEEP_DURATION |
| 262 | #define SPIN_SLEEP_DURATION 2000001 |
| 263 | #endif |
| 264 | |
| 265 | /* Defined and used in libc.so. */ |
| 266 | extern int __libc_multiple_threads attribute_hidden; |
| 267 | extern int __librt_multiple_threads; |
| 268 | |
| 269 | /* Debugging */ |
| 270 | |
| 271 | #ifdef DEBUG |
| 272 | #include <assert.h> |
| 273 | #define ASSERT assert |
| 274 | #define MSG __pthread_message |
| 275 | #else |
| 276 | #define ASSERT(x) |
| 277 | #define MSG(msg,arg...) |
| 278 | #endif |
| 279 | |
| 280 | /* Internal global functions */ |
| 281 | |
| 282 | extern void __pthread_do_exit (void *retval, char *currentframe) |
| 283 | __attribute__ ((__noreturn__)); |
| 284 | extern void __pthread_destroy_specifics (void); |
| 285 | extern void __pthread_perform_cleanup (char *currentframe); |
| 286 | extern void __pthread_init_max_stacksize (void); |
| 287 | extern int __pthread_initialize_manager (void); |
| 288 | extern void __pthread_message (const char * fmt, ...); |
| 289 | extern int __pthread_manager (void *reqfd); |
| 290 | extern int __pthread_manager_event (void *reqfd); |
| 291 | extern void __pthread_manager_sighandler (int sig); |
| 292 | extern void __pthread_reset_main_thread (void); |
| 293 | extern void __pthread_once_fork_prepare (void); |
| 294 | extern void __pthread_once_fork_parent (void); |
| 295 | extern void __pthread_once_fork_child (void); |
| 296 | extern void __flockfilelist (void); |
| 297 | extern void __funlockfilelist (void); |
| 298 | extern void __fresetlockfiles (void); |
| 299 | extern void __pthread_manager_adjust_prio (int thread_prio); |
| 300 | extern void __pthread_initialize_minimal (void); |
| 301 | |
| 302 | extern int __pthread_attr_setguardsize (pthread_attr_t *__attr, |
| 303 | size_t __guardsize); |
| 304 | extern int __pthread_attr_getguardsize (const pthread_attr_t *__attr, |
| 305 | size_t *__guardsize); |
| 306 | #if 0 /* uClibc: deprecated stuff disabled */ |
| 307 | extern int __pthread_attr_setstackaddr (pthread_attr_t *__attr, |
| 308 | void *__stackaddr); |
| 309 | extern int __pthread_attr_getstackaddr (const pthread_attr_t *__attr, |
| 310 | void **__stackaddr); |
| 311 | #endif |
| 312 | extern int __pthread_attr_setstacksize (pthread_attr_t *__attr, |
| 313 | size_t __stacksize); |
| 314 | extern int __pthread_attr_getstacksize (const pthread_attr_t *__attr, |
| 315 | size_t *__stacksize); |
| 316 | extern int __pthread_attr_setstack (pthread_attr_t *__attr, void *__stackaddr, |
| 317 | size_t __stacksize); |
| 318 | extern int __pthread_attr_getstack (const pthread_attr_t *__attr, void **__stackaddr, |
| 319 | size_t *__stacksize); |
| 320 | extern int __pthread_attr_destroy (pthread_attr_t *attr); |
| 321 | extern int __pthread_attr_setdetachstate (pthread_attr_t *attr, |
| 322 | int detachstate); |
| 323 | extern int __pthread_attr_getdetachstate (const pthread_attr_t *attr, |
| 324 | int *detachstate); |
| 325 | extern int __pthread_attr_setschedparam (pthread_attr_t *attr, |
| 326 | const struct sched_param *param); |
| 327 | extern int __pthread_attr_getschedparam (const pthread_attr_t *attr, |
| 328 | struct sched_param *param); |
| 329 | extern int __pthread_attr_setschedpolicy (pthread_attr_t *attr, int policy); |
| 330 | extern int __pthread_attr_getschedpolicy (const pthread_attr_t *attr, |
| 331 | int *policy); |
| 332 | extern int __pthread_attr_setinheritsched (pthread_attr_t *attr, int inherit); |
| 333 | extern int __pthread_attr_getinheritsched (const pthread_attr_t *attr, |
| 334 | int *inherit); |
| 335 | extern int __pthread_attr_setscope (pthread_attr_t *attr, int scope); |
| 336 | extern int __pthread_attr_getscope (const pthread_attr_t *attr, int *scope); |
| 337 | |
| 338 | extern int __pthread_getconcurrency (void); |
| 339 | extern int __pthread_setconcurrency (int __level); |
| 340 | extern int __pthread_mutex_timedlock (pthread_mutex_t *__mutex, |
| 341 | const struct timespec *__abstime); |
| 342 | extern int __pthread_mutexattr_getpshared (const pthread_mutexattr_t *__attr, |
| 343 | int *__pshared); |
| 344 | extern int __pthread_mutexattr_setpshared (pthread_mutexattr_t *__attr, |
| 345 | int __pshared); |
| 346 | extern int __pthread_mutexattr_gettype (const pthread_mutexattr_t *__attr, |
| 347 | int *__kind); |
| 348 | extern void __pthread_kill_other_threads_np (void); |
| 349 | extern int __pthread_mutex_init (pthread_mutex_t *__mutex, |
| 350 | __const pthread_mutexattr_t *__mutex_attr); |
| 351 | extern int __pthread_mutex_destroy (pthread_mutex_t *__mutex); |
| 352 | extern int __pthread_mutex_lock (pthread_mutex_t *__mutex); |
| 353 | extern int __pthread_mutex_trylock (pthread_mutex_t *__mutex); |
| 354 | extern int __pthread_mutex_unlock (pthread_mutex_t *__mutex); |
| 355 | |
| 356 | extern int __pthread_cond_init (pthread_cond_t *cond, |
| 357 | const pthread_condattr_t *cond_attr); |
| 358 | extern int __pthread_cond_destroy (pthread_cond_t *cond); |
| 359 | extern int __pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex); |
| 360 | extern int __pthread_cond_timedwait (pthread_cond_t *cond, |
| 361 | pthread_mutex_t *mutex, |
| 362 | const struct timespec *abstime); |
| 363 | extern int __pthread_cond_signal (pthread_cond_t *cond); |
| 364 | extern int __pthread_cond_broadcast (pthread_cond_t *cond); |
| 365 | extern int __pthread_condattr_init (pthread_condattr_t *attr); |
| 366 | extern int __pthread_condattr_destroy (pthread_condattr_t *attr); |
| 367 | extern pthread_t __pthread_self (void); |
| 368 | extern pthread_descr __pthread_thread_self (void); |
| 369 | extern pthread_descr __pthread_self_stack (void) attribute_hidden; |
| 370 | extern int __pthread_equal (pthread_t thread1, pthread_t thread2); |
| 371 | extern void __pthread_exit (void *retval) |
| 372 | #if defined NOT_IN_libc && defined IS_IN_libpthread |
| 373 | attribute_noreturn |
| 374 | #endif |
| 375 | ; |
| 376 | extern int __pthread_getschedparam (pthread_t thread, int *policy, |
| 377 | struct sched_param *param); |
| 378 | extern int __pthread_setschedparam (pthread_t thread, int policy, |
| 379 | const struct sched_param *param); |
| 380 | extern int __pthread_setcancelstate (int state, int * oldstate); |
| 381 | extern int __pthread_setcanceltype (int type, int * oldtype); |
| 382 | |
| 383 | extern void __pthread_restart_old(pthread_descr th); |
| 384 | extern void __pthread_suspend_old(pthread_descr self); |
| 385 | extern int __pthread_timedsuspend_old(pthread_descr self, const struct timespec *abstime); |
| 386 | |
| 387 | extern void __pthread_restart_new(pthread_descr th); |
| 388 | extern void __pthread_suspend_new(pthread_descr self); |
| 389 | extern int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abstime); |
| 390 | |
| 391 | extern void __pthread_wait_for_restart_signal(pthread_descr self); |
| 392 | |
| 393 | extern void __pthread_sigsuspend (const sigset_t *mask) attribute_hidden; |
| 394 | |
| 395 | extern int __pthread_rwlock_timedrdlock (pthread_rwlock_t *__restrict __rwlock, |
| 396 | __const struct timespec *__restrict |
| 397 | __abstime); |
| 398 | extern int __pthread_rwlock_timedwrlock (pthread_rwlock_t *__restrict __rwlock, |
| 399 | __const struct timespec *__restrict |
| 400 | __abstime); |
| 401 | extern int __pthread_rwlockattr_destroy (pthread_rwlockattr_t *__attr); |
| 402 | |
| 403 | extern int __pthread_barrierattr_getpshared (__const pthread_barrierattr_t * |
| 404 | __restrict __attr, |
| 405 | int *__restrict __pshared); |
| 406 | |
| 407 | extern int __pthread_spin_lock (pthread_spinlock_t *__lock); |
| 408 | extern int __pthread_spin_trylock (pthread_spinlock_t *__lock); |
| 409 | extern int __pthread_spin_unlock (pthread_spinlock_t *__lock); |
| 410 | extern int __pthread_spin_init (pthread_spinlock_t *__lock, int __pshared); |
| 411 | extern int __pthread_spin_destroy (pthread_spinlock_t *__lock); |
| 412 | |
| 413 | /* Global pointers to old or new suspend functions */ |
| 414 | |
| 415 | extern void (*__pthread_restart)(pthread_descr); |
| 416 | extern void (*__pthread_suspend)(pthread_descr); |
| 417 | extern int (*__pthread_timedsuspend)(pthread_descr, const struct timespec *); |
| 418 | |
| 419 | /* Prototypes for some of the new semaphore functions. */ |
| 420 | extern int sem_post (sem_t * sem); |
| 421 | extern int sem_init (sem_t *__sem, int __pshared, unsigned int __value); |
| 422 | extern int sem_wait (sem_t *__sem); |
| 423 | extern int sem_trywait (sem_t *__sem); |
| 424 | extern int sem_getvalue (sem_t *__restrict __sem, int *__restrict __sval); |
| 425 | extern int sem_destroy (sem_t *__sem); |
| 426 | |
| 427 | /* Prototypes for compatibility functions. */ |
| 428 | extern int __pthread_attr_init (pthread_attr_t *__attr); |
| 429 | extern int __pthread_create (pthread_t *__restrict __threadp, |
| 430 | const pthread_attr_t *__attr, |
| 431 | void *(*__start_routine) (void *), |
| 432 | void *__restrict __arg); |
| 433 | |
| 434 | /* The functions called the signal events. */ |
| 435 | extern void __linuxthreads_create_event (void); |
| 436 | extern void __linuxthreads_death_event (void); |
| 437 | extern void __linuxthreads_reap_event (void); |
| 438 | |
| 439 | /* This function is called to initialize the pthread library. */ |
| 440 | extern void __pthread_initialize (void); |
| 441 | |
| 442 | /* TSD. */ |
| 443 | extern int __pthread_internal_tsd_set (int key, const void * pointer); |
| 444 | extern void * __pthread_internal_tsd_get (int key); |
| 445 | extern void ** __attribute__ ((__const__)) |
| 446 | __pthread_internal_tsd_address (int key); |
| 447 | |
| 448 | /* Sighandler wrappers. */ |
| 449 | extern void __pthread_sighandler(int signo, SIGCONTEXT ctx); |
| 450 | extern void __pthread_sighandler_rt(int signo, struct siginfo *si, |
| 451 | struct ucontext *uc); |
| 452 | extern void __pthread_null_sighandler(int sig); |
| 453 | extern int __pthread_sigaction (int sig, const struct sigaction *act, |
| 454 | struct sigaction *oact); |
| 455 | extern int __pthread_sigwait (const sigset_t *set, int *sig); |
| 456 | extern int __pthread_raise (int sig); |
| 457 | |
| 458 | /* Cancellation. */ |
| 459 | extern int __pthread_enable_asynccancel (void) attribute_hidden; |
| 460 | extern void __pthread_disable_asynccancel (int oldtype) |
| 461 | internal_function attribute_hidden; |
| 462 | |
| 463 | /* The two functions are in libc.so and not exported. */ |
| 464 | extern int __libc_enable_asynccancel (void) attribute_hidden; |
| 465 | extern void __libc_disable_asynccancel (int oldtype) |
| 466 | internal_function attribute_hidden; |
| 467 | |
| 468 | /* The two functions are in libc.so and are exported. */ |
| 469 | extern int __librt_enable_asynccancel (void); |
| 470 | extern void __librt_disable_asynccancel (int oldtype) internal_function; |
| 471 | |
| 472 | extern void __pthread_cleanup_upto (__jmp_buf target, |
| 473 | char *targetframe) attribute_hidden; |
| 474 | extern pid_t __pthread_fork (struct fork_block *b) attribute_hidden; |
| 475 | |
| 476 | #define asm_handle(name) _asm_handle(name) |
| 477 | #define _asm_handle(name) #name |
| 478 | #define ASM_GLOBAL asm_handle(ASM_GLOBAL_DIRECTIVE) |
| 479 | #define ASM_CANCEL(name) asm_handle(C_SYMBOL_NAME(name)) |
| 480 | |
| 481 | #if !defined NOT_IN_libc |
| 482 | # define LIBC_CANCEL_ASYNC() \ |
| 483 | __libc_enable_asynccancel () |
| 484 | # define LIBC_CANCEL_RESET(oldtype) \ |
| 485 | __libc_disable_asynccancel (oldtype) |
| 486 | # define LIBC_CANCEL_HANDLED() \ |
| 487 | __asm__ (ASM_GLOBAL " " ASM_CANCEL(__libc_enable_asynccancel)); \ |
| 488 | __asm__ (ASM_GLOBAL " " ASM_CANCEL(__libc_disable_asynccancel)) |
| 489 | #elif defined IS_IN_libpthread |
| 490 | # define LIBC_CANCEL_ASYNC() \ |
| 491 | __pthread_enable_asynccancel () |
| 492 | # define LIBC_CANCEL_RESET(oldtype) \ |
| 493 | __pthread_disable_asynccancel (oldtype) |
| 494 | # define LIBC_CANCEL_HANDLED() \ |
| 495 | __asm__ (ASM_GLOBAL " " ASM_CANCEL(__pthread_enable_asynccancel)); \ |
| 496 | __asm__ (ASM_GLOBAL " " ASM_CANCEL(__pthread_disable_asynccancel)) |
| 497 | #elif defined IS_IN_librt |
| 498 | # define LIBC_CANCEL_ASYNC() \ |
| 499 | __librt_enable_asynccancel () |
| 500 | # define LIBC_CANCEL_RESET(oldtype) \ |
| 501 | __librt_disable_asynccancel (oldtype) |
| 502 | # define LIBC_CANCEL_HANDLED() \ |
| 503 | __asm__ (ASM_GLOBAL " " ASM_CANCEL(__librt_enable_asynccancel)); \ |
| 504 | __asm__ (ASM_GLOBAL " " ASM_CANCEL(__librt_disable_asynccancel)) |
| 505 | #else |
| 506 | # define LIBC_CANCEL_ASYNC() 0 /* Just a dummy value. */ |
| 507 | # define LIBC_CANCEL_RESET(val) ((void)(val)) /* Nothing, but evaluate it. */ |
| 508 | # define LIBC_CANCEL_HANDLED() /* Nothing. */ |
| 509 | #endif |
| 510 | |
| 511 | extern int * __libc_pthread_init (const struct pthread_functions *functions); |
| 512 | |
| 513 | #if !defined NOT_IN_libc && !defined FLOATING_STACKS |
| 514 | # ifdef SHARED |
| 515 | # define thread_self() \ |
| 516 | (*__libc_pthread_functions.ptr_pthread_thread_self) () |
| 517 | # else |
| 518 | weak_extern (__pthread_thread_self) |
| 519 | # define thread_self() __pthread_thread_self () |
| 520 | # endif |
| 521 | #endif |
| 522 | |
| 523 | #ifndef USE_TLS |
| 524 | # define __manager_thread (&__pthread_manager_thread) |
| 525 | #else |
| 526 | # define __manager_thread __pthread_manager_threadp |
| 527 | #endif |
| 528 | |
| 529 | static __always_inline pthread_descr |
| 530 | check_thread_self (void); |
| 531 | static __always_inline pthread_descr |
| 532 | check_thread_self (void) |
| 533 | { |
| 534 | pthread_descr self = thread_self (); |
| 535 | #if defined THREAD_SELF && defined INIT_THREAD_SELF |
| 536 | if (self == __manager_thread) |
| 537 | { |
| 538 | /* A new thread might get a cancel signal before it is fully |
| 539 | initialized, so that the thread register might still point to the |
| 540 | manager thread. Double check that this is really the manager |
| 541 | thread. */ |
| 542 | self = __pthread_self_stack(); |
| 543 | if (self != __manager_thread) |
| 544 | /* Oops, thread_self() isn't working yet.. */ |
| 545 | INIT_THREAD_SELF(self, self->p_nr); |
| 546 | } |
| 547 | #endif |
| 548 | return self; |
| 549 | } |
| 550 | |
| 551 | #endif /* internals.h */ |