| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /* |
| 2 | * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>. | |
| 3 | * All rights reserved. | |
| 4 | * | |
| 5 | * Redistribution and use in source and binary forms, with or without | |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 8 | * 1. Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer. | |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 | * notice, this list of conditions and the following disclaimer in the | |
| 12 | * documentation and/or other materials provided with the distribution. | |
| 13 | * 3. All advertising materials mentioning features or use of this software | |
| 14 | * must display the following acknowledgement: | |
| 15 | * This product includes software developed by John Birrell. | |
| 16 | * 4. Neither the name of the author nor the names of any co-contributors | |
| 17 | * may be used to endorse or promote products derived from this software | |
| 18 | * without specific prior written permission. | |
| 19 | * | |
| 20 | * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND | |
| 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
| 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 30 | * SUCH DAMAGE. | |
| 31 | * | |
| 32 | * Private thread definitions for the uthread kernel. | |
| 33 | * | |
| 34 | * $FreeBSD: src/lib/libc_r/uthread/pthread_private.h,v 1.36.2.21 2002/10/22 14:44:02 fjoe Exp $ | |
| 808851ae | 35 | * $DragonFly: src/lib/libc_r/uthread/pthread_private.h,v 1.16 2008/05/25 21:34:49 hasso Exp $ |
| 984263bc MD |
36 | */ |
| 37 | ||
| 38 | #ifndef _PTHREAD_PRIVATE_H | |
| 39 | #define _PTHREAD_PRIVATE_H | |
| 40 | ||
| 41 | /* | |
| 42 | * Evaluate the storage class specifier. | |
| 43 | */ | |
| 44 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 45 | #define SCLASS | |
| 46 | #else | |
| 47 | #define SCLASS extern | |
| 48 | #endif | |
| 49 | ||
| 50 | /* | |
| 51 | * Include files. | |
| 52 | */ | |
| 53 | #include <setjmp.h> | |
| 54 | #include <signal.h> | |
| 55 | #include <stdio.h> | |
| 56 | #include <sys/queue.h> | |
| 57 | #include <sys/types.h> | |
| 58 | #include <sys/time.h> | |
| 59 | #include <sys/cdefs.h> | |
| c4dd4100 | 60 | #include <sys/sched.h> |
| 984263bc MD |
61 | #include <spinlock.h> |
| 62 | #include <pthread_np.h> | |
| 63 | ||
| 40b6c3c5 JS |
64 | #include <machine/tls.h> |
| 65 | ||
| 984263bc MD |
66 | /* |
| 67 | * Define machine dependent macros to get and set the stack pointer | |
| 68 | * from the supported contexts. Also define a macro to set the return | |
| 69 | * address in a jmp_buf context. | |
| 70 | * | |
| 71 | * XXX - These need to be moved into architecture dependent support files. | |
| 72 | */ | |
| 73 | #if defined(__i386__) | |
| 74 | #define GET_STACK_JB(jb) ((unsigned long)((jb)[0]._jb[2])) | |
| 75 | #define GET_STACK_SJB(sjb) ((unsigned long)((sjb)[0]._sjb[2])) | |
| 76 | #define GET_STACK_UC(ucp) ((unsigned long)((ucp)->uc_mcontext.mc_esp)) | |
| 77 | #define SET_STACK_JB(jb, stk) (jb)[0]._jb[2] = (int)(stk) | |
| 78 | #define SET_STACK_SJB(sjb, stk) (sjb)[0]._sjb[2] = (int)(stk) | |
| 79 | #define SET_STACK_UC(ucp, stk) (ucp)->uc_mcontext.mc_esp = (int)(stk) | |
| 984263bc | 80 | #define SET_RETURN_ADDR_JB(jb, ra) (jb)[0]._jb[0] = (int)(ra) |
| c1543a89 | 81 | #elif defined(__x86_64__) |
| 64c2a074 SS |
82 | #define GET_STACK_JB(jb) ((unsigned long)((jb)[0]._jb[2])) |
| 83 | #define GET_STACK_SJB(sjb) ((unsigned long)((sjb)[0]._sjb[2])) | |
| 84 | #define GET_STACK_UC(ucp) ((unsigned long)((ucp)->uc_mcontext.mc_rsp)) | |
| 85 | #define SET_STACK_JB(jb, stk) (jb)[0]._jb[2] = (long)(stk) | |
| 86 | #define SET_STACK_SJB(sjb, stk) (sjb)[0]._sjb[2] = (long)(stk) | |
| 87 | #define SET_STACK_UC(ucp, stk) (ucp)->uc_mcontext.mc_rsp = (long)(stk) | |
| 88 | #define FP_SAVE_UC(ucp) do { \ | |
| 89 | char *fdata; \ | |
| 90 | fdata = (char *) (ucp)->uc_mcontext.mc_fpstate; \ | |
| 91 | __asm__("fxsave %0": :"m"(*fdata)); \ | |
| 92 | } while (0) | |
| 93 | #define FP_RESTORE_UC(ucp) do { \ | |
| 94 | char *fdata; \ | |
| 95 | fdata = (char *) (ucp)->uc_mcontext.mc_fpstate; \ | |
| 96 | __asm__("fxrstor %0": :"m"(*fdata)); \ | |
| 97 | } while (0) | |
| 98 | #define SET_RETURN_ADDR_JB(jb, ra) (jb)[0]._jb[0] = (long)(ra) | |
| 984263bc MD |
99 | #else |
| 100 | #error "Don't recognize this architecture!" | |
| 101 | #endif | |
| 102 | ||
| 103 | /* | |
| 104 | * Kernel fatal error handler macro. | |
| 105 | */ | |
| 106 | #define PANIC(string) _thread_exit(__FILE__,__LINE__,string) | |
| 107 | ||
| 108 | ||
| 109 | /* Output debug messages like this: */ | |
| 110 | #define stdout_debug(args...) do { \ | |
| 111 | char buf[128]; \ | |
| 112 | snprintf(buf, sizeof(buf), ##args); \ | |
| b09fd398 | 113 | __sys_extpwrite(1, buf, strlen(buf), O_FBLOCKING, -1); \ |
| 984263bc MD |
114 | } while (0) |
| 115 | #define stderr_debug(args...) do { \ | |
| 116 | char buf[128]; \ | |
| 117 | snprintf(buf, sizeof(buf), ##args); \ | |
| b09fd398 | 118 | __sys_extpwrite(2, buf, strlen(buf), O_FBLOCKING, -1); \ |
| 984263bc MD |
119 | } while (0) |
| 120 | ||
| 121 | ||
| 122 | ||
| 123 | /* | |
| 124 | * Priority queue manipulation macros (using pqe link): | |
| 125 | */ | |
| 126 | #define PTHREAD_PRIOQ_INSERT_HEAD(thrd) _pq_insert_head(&_readyq,thrd) | |
| 127 | #define PTHREAD_PRIOQ_INSERT_TAIL(thrd) _pq_insert_tail(&_readyq,thrd) | |
| 128 | #define PTHREAD_PRIOQ_REMOVE(thrd) _pq_remove(&_readyq,thrd) | |
| 129 | #define PTHREAD_PRIOQ_FIRST() _pq_first(&_readyq) | |
| 130 | ||
| 131 | /* | |
| 132 | * Waiting queue manipulation macros (using pqe link): | |
| 133 | */ | |
| 134 | #define PTHREAD_WAITQ_REMOVE(thrd) _waitq_remove(thrd) | |
| 135 | #define PTHREAD_WAITQ_INSERT(thrd) _waitq_insert(thrd) | |
| 136 | ||
| 137 | #if defined(_PTHREADS_INVARIANTS) | |
| 138 | #define PTHREAD_WAITQ_CLEARACTIVE() _waitq_clearactive() | |
| 139 | #define PTHREAD_WAITQ_SETACTIVE() _waitq_setactive() | |
| 140 | #else | |
| 141 | #define PTHREAD_WAITQ_CLEARACTIVE() | |
| 142 | #define PTHREAD_WAITQ_SETACTIVE() | |
| 143 | #endif | |
| 144 | ||
| 145 | /* | |
| 146 | * Work queue manipulation macros (using qe link): | |
| 147 | */ | |
| 148 | #define PTHREAD_WORKQ_INSERT(thrd) do { \ | |
| 149 | TAILQ_INSERT_TAIL(&_workq,thrd,qe); \ | |
| 150 | (thrd)->flags |= PTHREAD_FLAGS_IN_WORKQ; \ | |
| 151 | } while (0) | |
| 152 | #define PTHREAD_WORKQ_REMOVE(thrd) do { \ | |
| 153 | TAILQ_REMOVE(&_workq,thrd,qe); \ | |
| 154 | (thrd)->flags &= ~PTHREAD_FLAGS_IN_WORKQ; \ | |
| 155 | } while (0) | |
| 156 | ||
| 157 | ||
| 158 | /* | |
| 159 | * State change macro without scheduling queue change: | |
| 160 | */ | |
| 161 | #define PTHREAD_SET_STATE(thrd, newstate) do { \ | |
| 162 | (thrd)->state = newstate; \ | |
| 163 | (thrd)->fname = __FILE__; \ | |
| 164 | (thrd)->lineno = __LINE__; \ | |
| 165 | } while (0) | |
| 166 | ||
| 167 | /* | |
| 168 | * State change macro with scheduling queue change - This must be | |
| 169 | * called with preemption deferred (see thread_kern_sched_[un]defer). | |
| 170 | */ | |
| 171 | #if defined(_PTHREADS_INVARIANTS) | |
| 172 | #include <assert.h> | |
| 173 | #define PTHREAD_ASSERT(cond, msg) do { \ | |
| 174 | if (!(cond)) \ | |
| 175 | PANIC(msg); \ | |
| 176 | } while (0) | |
| 177 | #define PTHREAD_ASSERT_NOT_IN_SYNCQ(thrd) \ | |
| 178 | PTHREAD_ASSERT((((thrd)->flags & PTHREAD_FLAGS_IN_SYNCQ) == 0), \ | |
| 179 | "Illegal call from signal handler"); | |
| 180 | #define PTHREAD_NEW_STATE(thrd, newstate) do { \ | |
| 181 | if (_thread_kern_new_state != 0) \ | |
| 182 | PANIC("Recursive PTHREAD_NEW_STATE"); \ | |
| 183 | _thread_kern_new_state = 1; \ | |
| 184 | if ((thrd)->state != newstate) { \ | |
| 185 | if ((thrd)->state == PS_RUNNING) { \ | |
| 186 | PTHREAD_PRIOQ_REMOVE(thrd); \ | |
| 187 | PTHREAD_SET_STATE(thrd, newstate); \ | |
| 188 | PTHREAD_WAITQ_INSERT(thrd); \ | |
| 189 | } else if (newstate == PS_RUNNING) { \ | |
| 190 | PTHREAD_WAITQ_REMOVE(thrd); \ | |
| 191 | PTHREAD_SET_STATE(thrd, newstate); \ | |
| 192 | PTHREAD_PRIOQ_INSERT_TAIL(thrd); \ | |
| 193 | } \ | |
| 194 | } \ | |
| 195 | _thread_kern_new_state = 0; \ | |
| 196 | } while (0) | |
| 197 | #else | |
| 198 | #define PTHREAD_ASSERT(cond, msg) | |
| 199 | #define PTHREAD_ASSERT_NOT_IN_SYNCQ(thrd) | |
| 200 | #define PTHREAD_NEW_STATE(thrd, newstate) do { \ | |
| 201 | if ((thrd)->state != newstate) { \ | |
| 202 | if ((thrd)->state == PS_RUNNING) { \ | |
| 203 | PTHREAD_PRIOQ_REMOVE(thrd); \ | |
| 204 | PTHREAD_WAITQ_INSERT(thrd); \ | |
| 205 | } else if (newstate == PS_RUNNING) { \ | |
| 206 | PTHREAD_WAITQ_REMOVE(thrd); \ | |
| 207 | PTHREAD_PRIOQ_INSERT_TAIL(thrd); \ | |
| 208 | } \ | |
| 209 | } \ | |
| 210 | PTHREAD_SET_STATE(thrd, newstate); \ | |
| 211 | } while (0) | |
| 212 | #endif | |
| 213 | ||
| 214 | /* | |
| 215 | * Define the signals to be used for scheduling. | |
| 216 | */ | |
| 217 | #if defined(_PTHREADS_COMPAT_SCHED) | |
| 218 | #define _ITIMER_SCHED_TIMER ITIMER_VIRTUAL | |
| 219 | #define _SCHED_SIGNAL SIGVTALRM | |
| 220 | #else | |
| 221 | #define _ITIMER_SCHED_TIMER ITIMER_PROF | |
| 222 | #define _SCHED_SIGNAL SIGPROF | |
| 223 | #endif | |
| 224 | ||
| 225 | /* | |
| 226 | * Priority queues. | |
| 227 | * | |
| 228 | * XXX It'd be nice if these were contained in uthread_priority_queue.[ch]. | |
| 229 | */ | |
| 230 | typedef struct pq_list { | |
| 231 | TAILQ_HEAD(, pthread) pl_head; /* list of threads at this priority */ | |
| 232 | TAILQ_ENTRY(pq_list) pl_link; /* link for queue of priority lists */ | |
| 233 | int pl_prio; /* the priority of this list */ | |
| 234 | int pl_queued; /* is this in the priority queue */ | |
| 235 | } pq_list_t; | |
| 236 | ||
| 237 | typedef struct pq_queue { | |
| 238 | TAILQ_HEAD(, pq_list) pq_queue; /* queue of priority lists */ | |
| 239 | pq_list_t *pq_lists; /* array of all priority lists */ | |
| 240 | int pq_size; /* number of priority lists */ | |
| 241 | } pq_queue_t; | |
| 242 | ||
| 243 | ||
| 244 | /* | |
| 245 | * TailQ initialization values. | |
| 246 | */ | |
| 247 | #define TAILQ_INITIALIZER { NULL, NULL } | |
| 248 | ||
| 249 | /* | |
| 250 | * Mutex definitions. | |
| 251 | */ | |
| 252 | union pthread_mutex_data { | |
| 253 | void *m_ptr; | |
| 254 | int m_count; | |
| 255 | }; | |
| 256 | ||
| 257 | struct pthread_mutex { | |
| 258 | enum pthread_mutextype m_type; | |
| 259 | int m_protocol; | |
| 260 | TAILQ_HEAD(mutex_head, pthread) m_queue; | |
| 261 | struct pthread *m_owner; | |
| 262 | union pthread_mutex_data m_data; | |
| 263 | long m_flags; | |
| 264 | int m_refcount; | |
| 265 | ||
| 266 | /* | |
| 267 | * Used for priority inheritence and protection. | |
| 268 | * | |
| 269 | * m_prio - For priority inheritence, the highest active | |
| 270 | * priority (threads locking the mutex inherit | |
| 271 | * this priority). For priority protection, the | |
| 272 | * ceiling priority of this mutex. | |
| 273 | * m_saved_prio - mutex owners inherited priority before | |
| 274 | * taking the mutex, restored when the owner | |
| 275 | * unlocks the mutex. | |
| 276 | */ | |
| 277 | int m_prio; | |
| 278 | int m_saved_prio; | |
| 279 | ||
| 280 | /* | |
| 281 | * Link for list of all mutexes a thread currently owns. | |
| 282 | */ | |
| 283 | TAILQ_ENTRY(pthread_mutex) m_qe; | |
| 284 | ||
| 285 | /* | |
| 286 | * Lock for accesses to this structure. | |
| 287 | */ | |
| 288 | spinlock_t lock; | |
| 289 | }; | |
| 290 | ||
| 291 | /* | |
| 292 | * Flags for mutexes. | |
| 293 | */ | |
| 294 | #define MUTEX_FLAGS_PRIVATE 0x01 | |
| 295 | #define MUTEX_FLAGS_INITED 0x02 | |
| 296 | #define MUTEX_FLAGS_BUSY 0x04 | |
| 297 | ||
| 298 | /* | |
| 299 | * Static mutex initialization values. | |
| 300 | */ | |
| 301 | #define PTHREAD_MUTEX_STATIC_INITIALIZER \ | |
| 302 | { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, TAILQ_INITIALIZER, \ | |
| 303 | NULL, { NULL }, MUTEX_FLAGS_PRIVATE, 0, 0, 0, TAILQ_INITIALIZER, \ | |
| 304 | _SPINLOCK_INITIALIZER } | |
| 305 | ||
| 306 | struct pthread_mutex_attr { | |
| 307 | enum pthread_mutextype m_type; | |
| 308 | int m_protocol; | |
| 309 | int m_ceiling; | |
| 310 | long m_flags; | |
| 311 | }; | |
| 312 | ||
| 313 | /* | |
| 314 | * Condition variable definitions. | |
| 315 | */ | |
| 316 | enum pthread_cond_type { | |
| 317 | COND_TYPE_FAST, | |
| 318 | COND_TYPE_MAX | |
| 319 | }; | |
| 320 | ||
| 321 | struct pthread_cond { | |
| 322 | enum pthread_cond_type c_type; | |
| 323 | TAILQ_HEAD(cond_head, pthread) c_queue; | |
| 324 | pthread_mutex_t c_mutex; | |
| 325 | void *c_data; | |
| 326 | long c_flags; | |
| 327 | int c_seqno; | |
| 328 | ||
| 329 | /* | |
| 330 | * Lock for accesses to this structure. | |
| 331 | */ | |
| 332 | spinlock_t lock; | |
| 333 | }; | |
| 334 | ||
| 335 | struct pthread_cond_attr { | |
| 336 | enum pthread_cond_type c_type; | |
| 337 | long c_flags; | |
| 338 | }; | |
| 339 | ||
| 340 | /* | |
| 341 | * Flags for condition variables. | |
| 342 | */ | |
| 343 | #define COND_FLAGS_PRIVATE 0x01 | |
| 344 | #define COND_FLAGS_INITED 0x02 | |
| 345 | #define COND_FLAGS_BUSY 0x04 | |
| 346 | ||
| 347 | /* | |
| 348 | * Static cond initialization values. | |
| 349 | */ | |
| 350 | #define PTHREAD_COND_STATIC_INITIALIZER \ | |
| 351 | { COND_TYPE_FAST, TAILQ_INITIALIZER, NULL, NULL, \ | |
| 352 | 0, 0, _SPINLOCK_INITIALIZER } | |
| 353 | ||
| 354 | /* | |
| 355 | * Semaphore definitions. | |
| 356 | */ | |
| 357 | struct sem { | |
| 358 | #define SEM_MAGIC ((u_int32_t) 0x09fa4012) | |
| 359 | u_int32_t magic; | |
| 360 | pthread_mutex_t lock; | |
| 361 | pthread_cond_t gtzero; | |
| 362 | u_int32_t count; | |
| 363 | u_int32_t nwaiters; | |
| 364 | }; | |
| 365 | ||
| 366 | /* | |
| 367 | * Cleanup definitions. | |
| 368 | */ | |
| 369 | struct pthread_cleanup { | |
| 370 | struct pthread_cleanup *next; | |
| ed298f34 | 371 | void (*routine)(void *); |
| 984263bc MD |
372 | void *routine_arg; |
| 373 | }; | |
| 374 | ||
| 808851ae HT |
375 | struct pthread_atfork { |
| 376 | TAILQ_ENTRY(pthread_atfork) qe; | |
| 377 | void (*prepare)(void); | |
| 378 | void (*parent)(void); | |
| 379 | void (*child)(void); | |
| 380 | }; | |
| 381 | ||
| 984263bc MD |
382 | struct pthread_attr { |
| 383 | int sched_policy; | |
| 384 | int sched_inherit; | |
| 385 | int sched_interval; | |
| 386 | int prio; | |
| 387 | int suspend; | |
| 388 | int flags; | |
| 389 | void *arg_attr; | |
| ed298f34 | 390 | void (*cleanup_attr)(void *); |
| 984263bc MD |
391 | void *stackaddr_attr; |
| 392 | size_t stacksize_attr; | |
| 393 | }; | |
| 394 | ||
| 395 | /* | |
| 396 | * Thread creation state attributes. | |
| 397 | */ | |
| 398 | #define PTHREAD_CREATE_RUNNING 0 | |
| 399 | #define PTHREAD_CREATE_SUSPENDED 1 | |
| 400 | ||
| 401 | /* | |
| 402 | * Miscellaneous definitions. | |
| 403 | */ | |
| 404 | #define PTHREAD_STACK_DEFAULT 65536 | |
| 405 | /* | |
| 406 | * Size of red zone at the end of each stack. In actuality, this "red zone" is | |
| 407 | * merely an unmapped region, except in the case of the initial stack. Since | |
| 408 | * mmap() makes it possible to specify the maximum growth of a MAP_STACK region, | |
| 409 | * an unmapped gap between thread stacks achieves the same effect as explicitly | |
| 410 | * mapped red zones. | |
| 411 | */ | |
| 412 | #define PTHREAD_STACK_GUARD PAGE_SIZE | |
| 413 | ||
| 414 | /* | |
| 415 | * Maximum size of initial thread's stack. This perhaps deserves to be larger | |
| 416 | * than the stacks of other threads, since many applications are likely to run | |
| 417 | * almost entirely on this stack. | |
| 418 | */ | |
| 419 | #define PTHREAD_STACK_INITIAL 0x100000 | |
| 420 | ||
| 421 | /* Size of the scheduler stack: */ | |
| 422 | #define SCHED_STACK_SIZE PAGE_SIZE | |
| 423 | ||
| 424 | /* | |
| 425 | * Define the different priority ranges. All applications have thread | |
| 426 | * priorities constrained within 0-31. The threads library raises the | |
| 427 | * priority when delivering signals in order to ensure that signal | |
| 428 | * delivery happens (from the POSIX spec) "as soon as possible". | |
| 429 | * In the future, the threads library will also be able to map specific | |
| 430 | * threads into real-time (cooperating) processes or kernel threads. | |
| 431 | * The RT and SIGNAL priorities will be used internally and added to | |
| 432 | * thread base priorities so that the scheduling queue can handle both | |
| 433 | * normal and RT priority threads with and without signal handling. | |
| 434 | * | |
| 435 | * The approach taken is that, within each class, signal delivery | |
| 436 | * always has priority over thread execution. | |
| 437 | */ | |
| 438 | #define PTHREAD_DEFAULT_PRIORITY 15 | |
| 439 | #define PTHREAD_MIN_PRIORITY 0 | |
| 440 | #define PTHREAD_MAX_PRIORITY 31 /* 0x1F */ | |
| 441 | #define PTHREAD_SIGNAL_PRIORITY 32 /* 0x20 */ | |
| 442 | #define PTHREAD_RT_PRIORITY 64 /* 0x40 */ | |
| 443 | #define PTHREAD_FIRST_PRIORITY PTHREAD_MIN_PRIORITY | |
| 444 | #define PTHREAD_LAST_PRIORITY \ | |
| 445 | (PTHREAD_MAX_PRIORITY + PTHREAD_SIGNAL_PRIORITY + PTHREAD_RT_PRIORITY) | |
| 446 | #define PTHREAD_BASE_PRIORITY(prio) ((prio) & PTHREAD_MAX_PRIORITY) | |
| 447 | ||
| 448 | /* | |
| 449 | * Clock resolution in microseconds. | |
| 450 | */ | |
| 451 | #define CLOCK_RES_USEC 10000 | |
| 452 | #define CLOCK_RES_USEC_MIN 1000 | |
| 453 | ||
| 454 | /* | |
| 455 | * Time slice period in microseconds. | |
| 456 | */ | |
| 457 | #define TIMESLICE_USEC 20000 | |
| 458 | ||
| 459 | /* | |
| 460 | * Define a thread-safe macro to get the current time of day | |
| 461 | * which is updated at regular intervals by the scheduling signal | |
| 462 | * handler. | |
| 463 | */ | |
| 464 | #define GET_CURRENT_TOD(tv) \ | |
| 465 | do { \ | |
| 466 | tv.tv_sec = _sched_tod.tv_sec; \ | |
| 467 | tv.tv_usec = _sched_tod.tv_usec; \ | |
| 468 | } while (tv.tv_sec != _sched_tod.tv_sec) | |
| 469 | ||
| 470 | ||
| 471 | struct pthread_key { | |
| 472 | spinlock_t lock; | |
| 473 | volatile int allocated; | |
| 474 | volatile int count; | |
| ed298f34 | 475 | void (*destructor)(void *); |
| 984263bc MD |
476 | }; |
| 477 | ||
| 478 | struct pthread_rwlockattr { | |
| 479 | int pshared; | |
| 480 | }; | |
| 481 | ||
| 482 | struct pthread_rwlock { | |
| 483 | pthread_mutex_t lock; /* monitor lock */ | |
| 484 | int state; /* 0 = idle >0 = # of readers -1 = writer */ | |
| 485 | pthread_cond_t read_signal; | |
| 486 | pthread_cond_t write_signal; | |
| 487 | int blocked_writers; | |
| 488 | }; | |
| 489 | ||
| 490 | /* | |
| 491 | * Thread states. | |
| 492 | */ | |
| 493 | enum pthread_state { | |
| 494 | PS_RUNNING, | |
| 495 | PS_SIGTHREAD, | |
| 496 | PS_MUTEX_WAIT, | |
| 497 | PS_COND_WAIT, | |
| 498 | PS_FDLR_WAIT, | |
| 499 | PS_FDLW_WAIT, | |
| 500 | PS_FDR_WAIT, | |
| 501 | PS_FDW_WAIT, | |
| 984263bc MD |
502 | PS_POLL_WAIT, |
| 503 | PS_SELECT_WAIT, | |
| 504 | PS_SLEEP_WAIT, | |
| 505 | PS_WAIT_WAIT, | |
| 506 | PS_SIGSUSPEND, | |
| 507 | PS_SIGWAIT, | |
| 508 | PS_SPINBLOCK, | |
| 509 | PS_JOIN, | |
| 510 | PS_SUSPENDED, | |
| 511 | PS_DEAD, | |
| 512 | PS_DEADLOCK, | |
| 513 | PS_STATE_MAX | |
| 514 | }; | |
| 515 | ||
| 516 | ||
| 517 | /* | |
| 518 | * File descriptor locking definitions. | |
| 519 | */ | |
| 520 | #define FD_READ 0x1 | |
| 521 | #define FD_WRITE 0x2 | |
| 522 | #define FD_RDWR (FD_READ | FD_WRITE) | |
| 523 | ||
| 524 | /* | |
| 525 | * File descriptor table structure. | |
| 526 | */ | |
| 527 | struct fd_table_entry { | |
| 528 | /* | |
| 529 | * Lock for accesses to this file descriptor table | |
| 530 | * entry. This is passed to _spinlock() to provide atomic | |
| 531 | * access to this structure. It does *not* represent the | |
| 532 | * state of the lock on the file descriptor. | |
| 533 | */ | |
| 534 | spinlock_t lock; | |
| 535 | TAILQ_HEAD(, pthread) r_queue; /* Read queue. */ | |
| 536 | TAILQ_HEAD(, pthread) w_queue; /* Write queue. */ | |
| 537 | struct pthread *r_owner; /* Ptr to thread owning read lock. */ | |
| 538 | struct pthread *w_owner; /* Ptr to thread owning write lock. */ | |
| 539 | char *r_fname; /* Ptr to read lock source file name */ | |
| 540 | int r_lineno; /* Read lock source line number. */ | |
| 541 | char *w_fname; /* Ptr to write lock source file name */ | |
| 542 | int w_lineno; /* Write lock source line number. */ | |
| 543 | int r_lockcount; /* Count for FILE read locks. */ | |
| 544 | int w_lockcount; /* Count for FILE write locks. */ | |
| 545 | int flags; /* Flags used in open. */ | |
| 546 | }; | |
| 547 | ||
| 548 | struct pthread_poll_data { | |
| 549 | int nfds; | |
| 550 | struct pollfd *fds; | |
| 551 | }; | |
| 552 | ||
| 553 | union pthread_wait_data { | |
| 554 | pthread_mutex_t mutex; | |
| 555 | pthread_cond_t cond; | |
| 556 | const sigset_t *sigwait; /* Waiting on a signal in sigwait */ | |
| 557 | struct { | |
| 558 | short fd; /* Used when thread waiting on fd */ | |
| 559 | short branch; /* Line number, for debugging. */ | |
| 560 | char *fname; /* Source file name for debugging.*/ | |
| 561 | } fd; | |
| 562 | FILE *fp; | |
| 563 | struct pthread_poll_data *poll_data; | |
| 564 | spinlock_t *spinlock; | |
| 565 | struct pthread *thread; | |
| 566 | }; | |
| 567 | ||
| 568 | /* | |
| 569 | * Define a continuation routine that can be used to perform a | |
| 570 | * transfer of control: | |
| 571 | */ | |
| 572 | typedef void (*thread_continuation_t) (void *); | |
| 573 | ||
| 574 | struct pthread_signal_frame; | |
| 575 | ||
| 576 | struct pthread_state_data { | |
| 577 | struct pthread_signal_frame *psd_curframe; | |
| 578 | sigset_t psd_sigmask; | |
| 579 | struct timespec psd_wakeup_time; | |
| 580 | union pthread_wait_data psd_wait_data; | |
| 581 | enum pthread_state psd_state; | |
| 582 | int psd_flags; | |
| 583 | int psd_interrupted; | |
| 584 | int psd_longjmp_val; | |
| 585 | int psd_sigmask_seqno; | |
| 586 | int psd_signo; | |
| 587 | int psd_sig_defer_count; | |
| 588 | /* XXX - What about thread->timeout and/or thread->error? */ | |
| 589 | }; | |
| 590 | ||
| 591 | struct join_status { | |
| 592 | struct pthread *thread; | |
| 593 | void *ret; | |
| 594 | int error; | |
| 595 | }; | |
| 596 | ||
| 597 | /* | |
| 598 | * The frame that is added to the top of a threads stack when setting up | |
| 599 | * up the thread to run a signal handler. | |
| 600 | */ | |
| 601 | struct pthread_signal_frame { | |
| 602 | /* | |
| 603 | * This stores the threads state before the signal. | |
| 604 | */ | |
| 605 | struct pthread_state_data saved_state; | |
| 606 | ||
| 607 | /* | |
| 608 | * Threads return context; we use only jmp_buf's for now. | |
| 609 | */ | |
| 610 | union { | |
| 611 | jmp_buf jb; | |
| 612 | ucontext_t uc; | |
| 613 | } ctx; | |
| 614 | int signo; /* signal, arg 1 to sighandler */ | |
| 615 | int sig_has_args; /* use signal args if true */ | |
| 616 | ucontext_t uc; | |
| 617 | siginfo_t siginfo; | |
| 618 | }; | |
| 619 | ||
| 620 | /* | |
| 621 | * Thread structure. | |
| 622 | */ | |
| 623 | struct pthread { | |
| 624 | /* | |
| 625 | * Magic value to help recognize a valid thread structure | |
| 626 | * from an invalid one: | |
| 627 | */ | |
| 628 | #define PTHREAD_MAGIC ((u_int32_t) 0xd09ba115) | |
| 629 | u_int32_t magic; | |
| 630 | char *name; | |
| 631 | u_int64_t uniqueid; /* for gdb */ | |
| 40b6c3c5 | 632 | struct tls_tcb *tcb; |
| 984263bc MD |
633 | |
| 634 | /* | |
| 635 | * Lock for accesses to this thread structure. | |
| 636 | */ | |
| 637 | spinlock_t lock; | |
| 638 | ||
| 639 | /* Queue entry for list of all threads: */ | |
| 640 | TAILQ_ENTRY(pthread) tle; | |
| 641 | ||
| 642 | /* Queue entry for list of dead threads: */ | |
| 643 | TAILQ_ENTRY(pthread) dle; | |
| 644 | ||
| 645 | /* | |
| 646 | * Thread start routine, argument, stack pointer and thread | |
| 647 | * attributes. | |
| 648 | */ | |
| 649 | void *(*start_routine)(void *); | |
| 650 | void *arg; | |
| 651 | void *stack; | |
| 652 | struct pthread_attr attr; | |
| 653 | ||
| 654 | /* | |
| 655 | * Threads return context; we use only jmp_buf's for now. | |
| 656 | */ | |
| 657 | union { | |
| 658 | jmp_buf jb; | |
| 659 | ucontext_t uc; | |
| 660 | } ctx; | |
| 661 | ||
| 662 | /* | |
| 663 | * Used for tracking delivery of signal handlers. | |
| 664 | */ | |
| 665 | struct pthread_signal_frame *curframe; | |
| 666 | ||
| 667 | /* | |
| 668 | * Cancelability flags - the lower 2 bits are used by cancel | |
| 669 | * definitions in pthread.h | |
| 670 | */ | |
| 671 | #define PTHREAD_AT_CANCEL_POINT 0x0004 | |
| 672 | #define PTHREAD_CANCELLING 0x0008 | |
| 673 | #define PTHREAD_CANCEL_NEEDED 0x0010 | |
| 674 | int cancelflags; | |
| 675 | ||
| 676 | thread_continuation_t continuation; | |
| 677 | ||
| 678 | /* | |
| 679 | * Current signal mask and pending signals. | |
| 680 | */ | |
| 681 | sigset_t sigmask; | |
| 682 | sigset_t sigpend; | |
| 683 | int sigmask_seqno; | |
| 684 | int check_pending; | |
| 685 | ||
| 686 | /* Thread state: */ | |
| 687 | enum pthread_state state; | |
| 688 | ||
| 689 | /* Scheduling clock when this thread was last made active. */ | |
| 690 | long last_active; | |
| 691 | ||
| 692 | /* Scheduling clock when this thread was last made inactive. */ | |
| 693 | long last_inactive; | |
| 694 | ||
| 695 | /* | |
| 696 | * Number of microseconds accumulated by this thread when | |
| 697 | * time slicing is active. | |
| 698 | */ | |
| 699 | long slice_usec; | |
| 700 | ||
| 701 | /* | |
| 702 | * Time to wake up thread. This is used for sleeping threads and | |
| 703 | * for any operation which may time out (such as select). | |
| 704 | */ | |
| 705 | struct timespec wakeup_time; | |
| 706 | ||
| 707 | /* TRUE if operation has timed out. */ | |
| 708 | int timeout; | |
| 709 | ||
| 710 | /* | |
| 984263bc MD |
711 | * The joiner is the thread that is joining to this thread. The |
| 712 | * join status keeps track of a join operation to another thread. | |
| 713 | */ | |
| 714 | struct pthread *joiner; | |
| 715 | struct join_status join_status; | |
| 716 | ||
| 717 | /* | |
| 718 | * The current thread can belong to only one scheduling queue at | |
| 719 | * a time (ready or waiting queue). It can also belong to: | |
| 720 | * | |
| 721 | * o A queue of threads waiting for a mutex | |
| 722 | * o A queue of threads waiting for a condition variable | |
| 723 | * o A queue of threads waiting for a file descriptor lock | |
| 724 | * o A queue of threads needing work done by the kernel thread | |
| 725 | * (waiting for a spinlock or file I/O) | |
| 726 | * | |
| 727 | * A thread can also be joining a thread (the joiner field above). | |
| 728 | * | |
| 729 | * It must not be possible for a thread to belong to any of the | |
| 730 | * above queues while it is handling a signal. Signal handlers | |
| 731 | * may longjmp back to previous stack frames circumventing normal | |
| 732 | * control flow. This could corrupt queue integrity if the thread | |
| 733 | * retains membership in the queue. Therefore, if a thread is a | |
| 734 | * member of one of these queues when a signal handler is invoked, | |
| 735 | * it must remove itself from the queue before calling the signal | |
| 736 | * handler and reinsert itself after normal return of the handler. | |
| 737 | * | |
| 738 | * Use pqe for the scheduling queue link (both ready and waiting), | |
| 739 | * sqe for synchronization (mutex and condition variable) queue | |
| 740 | * links, and qe for all other links. | |
| 741 | */ | |
| 742 | TAILQ_ENTRY(pthread) pqe; /* priority queue link */ | |
| 743 | TAILQ_ENTRY(pthread) sqe; /* synchronization queue link */ | |
| 744 | TAILQ_ENTRY(pthread) qe; /* all other queues link */ | |
| 745 | ||
| 746 | /* Wait data. */ | |
| 747 | union pthread_wait_data data; | |
| 748 | ||
| 749 | /* | |
| 750 | * Allocated for converting select into poll. | |
| 751 | */ | |
| 752 | struct pthread_poll_data poll_data; | |
| 753 | ||
| 754 | /* | |
| 755 | * Set to TRUE if a blocking operation was | |
| 756 | * interrupted by a signal: | |
| 757 | */ | |
| 758 | int interrupted; | |
| 759 | ||
| 760 | /* Signal number when in state PS_SIGWAIT: */ | |
| 761 | int signo; | |
| 762 | ||
| 763 | /* | |
| 764 | * Set to non-zero when this thread has deferred signals. | |
| 765 | * We allow for recursive deferral. | |
| 766 | */ | |
| 767 | int sig_defer_count; | |
| 768 | ||
| 769 | /* | |
| 770 | * Set to TRUE if this thread should yield after undeferring | |
| 771 | * signals. | |
| 772 | */ | |
| 773 | int yield_on_sig_undefer; | |
| 774 | ||
| 775 | /* Miscellaneous flags; only set with signals deferred. */ | |
| 776 | int flags; | |
| 777 | #define PTHREAD_FLAGS_PRIVATE 0x0001 | |
| 778 | #define PTHREAD_EXITING 0x0002 | |
| 779 | #define PTHREAD_FLAGS_IN_WAITQ 0x0004 /* in waiting queue using pqe link */ | |
| 780 | #define PTHREAD_FLAGS_IN_PRIOQ 0x0008 /* in priority queue using pqe link */ | |
| 781 | #define PTHREAD_FLAGS_IN_WORKQ 0x0010 /* in work queue using qe link */ | |
| 782 | #define PTHREAD_FLAGS_IN_FILEQ 0x0020 /* in file lock queue using qe link */ | |
| 783 | #define PTHREAD_FLAGS_IN_FDQ 0x0040 /* in fd lock queue using qe link */ | |
| 784 | #define PTHREAD_FLAGS_IN_CONDQ 0x0080 /* in condition queue using sqe link*/ | |
| 785 | #define PTHREAD_FLAGS_IN_MUTEXQ 0x0100 /* in mutex queue using sqe link */ | |
| 786 | #define PTHREAD_FLAGS_SUSPENDED 0x0200 /* thread is suspended */ | |
| 787 | #define PTHREAD_FLAGS_TRACE 0x0400 /* for debugging purposes */ | |
| 788 | #define PTHREAD_FLAGS_IN_SYNCQ \ | |
| 789 | (PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ) | |
| 790 | ||
| 791 | /* | |
| 792 | * Base priority is the user setable and retrievable priority | |
| 793 | * of the thread. It is only affected by explicit calls to | |
| 794 | * set thread priority and upon thread creation via a thread | |
| 795 | * attribute or default priority. | |
| 796 | */ | |
| 797 | char base_priority; | |
| 798 | ||
| 799 | /* | |
| 800 | * Inherited priority is the priority a thread inherits by | |
| 801 | * taking a priority inheritence or protection mutex. It | |
| 802 | * is not affected by base priority changes. Inherited | |
| 803 | * priority defaults to and remains 0 until a mutex is taken | |
| 804 | * that is being waited on by any other thread whose priority | |
| 805 | * is non-zero. | |
| 806 | */ | |
| 807 | char inherited_priority; | |
| 808 | ||
| 809 | /* | |
| 810 | * Active priority is always the maximum of the threads base | |
| 811 | * priority and inherited priority. When there is a change | |
| 812 | * in either the base or inherited priority, the active | |
| 813 | * priority must be recalculated. | |
| 814 | */ | |
| 815 | char active_priority; | |
| 816 | ||
| 817 | /* Number of priority ceiling or protection mutexes owned. */ | |
| 818 | int priority_mutex_count; | |
| 819 | ||
| 820 | /* | |
| 821 | * Queue of currently owned mutexes. | |
| 822 | */ | |
| 823 | TAILQ_HEAD(, pthread_mutex) mutexq; | |
| 824 | ||
| 825 | void *ret; | |
| 826 | const void **specific_data; | |
| 827 | int specific_data_count; | |
| 828 | ||
| 829 | /* Cleanup handlers Link List */ | |
| 830 | struct pthread_cleanup *cleanup; | |
| 831 | char *fname; /* Ptr to source file name */ | |
| 832 | int lineno; /* Source line number. */ | |
| 833 | }; | |
| 834 | ||
| 835 | /* Spare thread stack. */ | |
| 836 | struct stack { | |
| 837 | SLIST_ENTRY(stack) qe; /* Queue entry for this stack. */ | |
| 838 | }; | |
| 839 | ||
| 840 | /* | |
| 841 | * Global variables for the uthread kernel. | |
| 842 | */ | |
| 843 | ||
| 844 | SCLASS void *_usrstack | |
| 845 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 846 | = (void *) USRSTACK; | |
| 847 | #else | |
| 848 | ; | |
| 849 | #endif | |
| 850 | ||
| 851 | /* Kernel thread structure used when there are no running threads: */ | |
| 852 | SCLASS struct pthread _thread_kern_thread; | |
| 853 | ||
| 854 | /* Ptr to the thread structure for the running thread: */ | |
| 855 | SCLASS struct pthread * volatile _thread_run | |
| 856 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 857 | = &_thread_kern_thread; | |
| 858 | #else | |
| 859 | ; | |
| 860 | #endif | |
| 861 | ||
| 862 | /* Ptr to the thread structure for the last user thread to run: */ | |
| 863 | SCLASS struct pthread * volatile _last_user_thread | |
| 864 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 865 | = &_thread_kern_thread; | |
| 866 | #else | |
| 867 | ; | |
| 868 | #endif | |
| 869 | ||
| 870 | /* List of all threads: */ | |
| 871 | SCLASS TAILQ_HEAD(, pthread) _thread_list | |
| 872 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 873 | = TAILQ_HEAD_INITIALIZER(_thread_list); | |
| 874 | #else | |
| 875 | ; | |
| 876 | #endif | |
| 877 | ||
| 878 | /* | |
| 879 | * Array of kernel pipe file descriptors that are used to ensure that | |
| 880 | * no signals are missed in calls to _select. | |
| 881 | */ | |
| 882 | SCLASS int _thread_kern_pipe[2] | |
| 883 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 884 | = { | |
| 885 | -1, | |
| 886 | -1 | |
| 887 | }; | |
| 888 | #else | |
| 889 | ; | |
| 890 | #endif | |
| 891 | SCLASS int volatile _queue_signals | |
| 892 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 893 | = 0; | |
| 894 | #else | |
| 895 | ; | |
| 896 | #endif | |
| 897 | SCLASS int _thread_kern_in_sched | |
| 898 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 899 | = 0; | |
| 900 | #else | |
| 901 | ; | |
| 902 | #endif | |
| 903 | ||
| 904 | SCLASS int _sig_in_handler | |
| 905 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 906 | = 0; | |
| 907 | #else | |
| 908 | ; | |
| 909 | #endif | |
| 910 | ||
| 911 | /* Time of day at last scheduling timer signal: */ | |
| 912 | SCLASS struct timeval volatile _sched_tod | |
| 913 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 914 | = { 0, 0 }; | |
| 915 | #else | |
| 916 | ; | |
| 917 | #endif | |
| 918 | ||
| 919 | /* | |
| 920 | * Current scheduling timer ticks; used as resource usage. | |
| 921 | */ | |
| 922 | SCLASS unsigned int volatile _sched_ticks | |
| 923 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 924 | = 0; | |
| 925 | #else | |
| 926 | ; | |
| 927 | #endif | |
| 928 | ||
| 929 | /* Dead threads: */ | |
| 930 | SCLASS TAILQ_HEAD(, pthread) _dead_list | |
| 931 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 932 | = TAILQ_HEAD_INITIALIZER(_dead_list); | |
| 933 | #else | |
| 934 | ; | |
| 935 | #endif | |
| 936 | ||
| 937 | /* Initial thread: */ | |
| 938 | SCLASS struct pthread *_thread_initial | |
| 939 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 940 | = NULL; | |
| 941 | #else | |
| 942 | ; | |
| 943 | #endif | |
| 944 | ||
| 808851ae HT |
945 | SCLASS TAILQ_HEAD(atfork_head, pthread_atfork) _atfork_list; |
| 946 | SCLASS pthread_mutex_t _atfork_mutex; | |
| 947 | ||
| 984263bc MD |
948 | /* Default thread attributes: */ |
| 949 | SCLASS struct pthread_attr pthread_attr_default | |
| 950 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 951 | = { SCHED_RR, 0, TIMESLICE_USEC, PTHREAD_DEFAULT_PRIORITY, PTHREAD_CREATE_RUNNING, | |
| 952 | PTHREAD_CREATE_JOINABLE, NULL, NULL, NULL, PTHREAD_STACK_DEFAULT }; | |
| 953 | #else | |
| 954 | ; | |
| 955 | #endif | |
| 956 | ||
| 957 | /* Default mutex attributes: */ | |
| 958 | SCLASS struct pthread_mutex_attr pthread_mutexattr_default | |
| 959 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 960 | = { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, 0 }; | |
| 961 | #else | |
| 962 | ; | |
| 963 | #endif | |
| 964 | ||
| 965 | /* Default condition variable attributes: */ | |
| 966 | SCLASS struct pthread_cond_attr pthread_condattr_default | |
| 967 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 968 | = { COND_TYPE_FAST, 0 }; | |
| 969 | #else | |
| 970 | ; | |
| 971 | #endif | |
| 972 | ||
| 973 | /* | |
| 974 | * Standard I/O file descriptors need special flag treatment since | |
| 975 | * setting one to non-blocking does all on *BSD. Sigh. This array | |
| 976 | * is used to store the initial flag settings. | |
| 977 | */ | |
| 978 | SCLASS int _pthread_stdio_flags[3]; | |
| 979 | ||
| 980 | /* File table information: */ | |
| 981 | SCLASS struct fd_table_entry **_thread_fd_table | |
| 982 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 983 | = NULL; | |
| 984 | #else | |
| 985 | ; | |
| 986 | #endif | |
| 987 | ||
| 988 | /* Table for polling file descriptors: */ | |
| 989 | SCLASS struct pollfd *_thread_pfd_table | |
| 990 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 991 | = NULL; | |
| 992 | #else | |
| 993 | ; | |
| 994 | #endif | |
| 995 | ||
| 996 | SCLASS const int dtablecount | |
| 997 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 998 | = 4096/sizeof(struct fd_table_entry); | |
| 999 | #else | |
| 1000 | ; | |
| 1001 | #endif | |
| 1002 | SCLASS int _thread_dtablesize /* Descriptor table size. */ | |
| 1003 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 1004 | = 0; | |
| 1005 | #else | |
| 1006 | ; | |
| 1007 | #endif | |
| 1008 | ||
| 1009 | SCLASS int _clock_res_usec /* Clock resolution in usec. */ | |
| 1010 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 1011 | = CLOCK_RES_USEC; | |
| 1012 | #else | |
| 1013 | ; | |
| 1014 | #endif | |
| 1015 | ||
| 1016 | /* Garbage collector mutex and condition variable. */ | |
| 1017 | SCLASS pthread_mutex_t _gc_mutex | |
| 1018 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 1019 | = NULL | |
| 1020 | #endif | |
| 1021 | ; | |
| 1022 | SCLASS pthread_cond_t _gc_cond | |
| 1023 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 1024 | = NULL | |
| 1025 | #endif | |
| 1026 | ; | |
| 1027 | ||
| 1028 | /* | |
| 1029 | * Array of signal actions for this process. | |
| 1030 | */ | |
| 1031 | SCLASS struct sigaction _thread_sigact[NSIG]; | |
| 1032 | ||
| 1033 | /* | |
| 1034 | * Array of counts of dummy handlers for SIG_DFL signals. This is used to | |
| 1035 | * assure that there is always a dummy signal handler installed while there is a | |
| 1036 | * thread sigwait()ing on the corresponding signal. | |
| 1037 | */ | |
| 1038 | SCLASS int _thread_dfl_count[NSIG]; | |
| 1039 | ||
| 1040 | /* | |
| 1041 | * Pending signals and mask for this process: | |
| 1042 | */ | |
| 1043 | SCLASS sigset_t _process_sigpending; | |
| 1044 | SCLASS sigset_t _process_sigmask | |
| 1045 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 1046 | = { {0, 0, 0, 0} } | |
| 1047 | #endif | |
| 1048 | ; | |
| 1049 | ||
| 1050 | /* | |
| 1051 | * Scheduling queues: | |
| 1052 | */ | |
| 1053 | SCLASS pq_queue_t _readyq; | |
| 1054 | SCLASS TAILQ_HEAD(, pthread) _waitingq; | |
| 1055 | ||
| 1056 | /* | |
| 1057 | * Work queue: | |
| 1058 | */ | |
| 1059 | SCLASS TAILQ_HEAD(, pthread) _workq; | |
| 1060 | ||
| 1061 | /* Tracks the number of threads blocked while waiting for a spinlock. */ | |
| 1062 | SCLASS volatile int _spinblock_count | |
| 1063 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 1064 | = 0 | |
| 1065 | #endif | |
| 1066 | ; | |
| 1067 | ||
| 1068 | /* Used to maintain pending and active signals: */ | |
| 1069 | struct sigstatus { | |
| 1070 | int pending; /* Is this a pending signal? */ | |
| 1071 | int blocked; /* | |
| 1072 | * A handler is currently active for | |
| 1073 | * this signal; ignore subsequent | |
| 1074 | * signals until the handler is done. | |
| 1075 | */ | |
| 1076 | int signo; /* arg 1 to signal handler */ | |
| 1077 | siginfo_t siginfo; /* arg 2 to signal handler */ | |
| 1078 | ucontext_t uc; /* arg 3 to signal handler */ | |
| 1079 | }; | |
| 1080 | ||
| 1081 | SCLASS struct sigstatus _thread_sigq[NSIG]; | |
| 1082 | ||
| 1083 | /* Indicates that the signal queue needs to be checked. */ | |
| 1084 | SCLASS volatile int _sigq_check_reqd | |
| 1085 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 1086 | = 0 | |
| 1087 | #endif | |
| 1088 | ; | |
| 1089 | ||
| 1090 | /* Thread switch hook. */ | |
| 1091 | SCLASS pthread_switch_routine_t _sched_switch_hook | |
| 1092 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 1093 | = NULL | |
| 1094 | #endif | |
| 1095 | ; | |
| 1096 | ||
| 1097 | /* | |
| 1098 | * Spare stack queue. Stacks of default size are cached in order to reduce | |
| 1099 | * thread creation time. Spare stacks are used in LIFO order to increase cache | |
| 1100 | * locality. | |
| 1101 | */ | |
| 1102 | SCLASS SLIST_HEAD(, stack) _stackq; | |
| 1103 | ||
| 1104 | /* | |
| 1105 | * Base address of next unallocated default-size {stack, red zone}. Stacks are | |
| 1106 | * allocated contiguously, starting below the bottom of the main stack. When a | |
| 1107 | * new stack is created, a red zone is created (actually, the red zone is simply | |
| 1108 | * left unmapped) below the bottom of the stack, such that the stack will not be | |
| 1109 | * able to grow all the way to the top of the next stack. This isn't | |
| 1110 | * fool-proof. It is possible for a stack to grow by a large amount, such that | |
| 1111 | * it grows into the next stack, and as long as the memory within the red zone | |
| 1112 | * is never accessed, nothing will prevent one thread stack from trouncing all | |
| 1113 | * over the next. | |
| 1114 | */ | |
| 1115 | SCLASS void * _next_stack | |
| 1116 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 1117 | /* main stack top - main stack size - stack size - (red zone + main stack red zone) */ | |
| 1118 | = (void *) USRSTACK - PTHREAD_STACK_INITIAL - PTHREAD_STACK_DEFAULT - (2 * PTHREAD_STACK_GUARD) | |
| 1119 | #endif | |
| 1120 | ; | |
| 1121 | ||
| 1122 | /* | |
| 1123 | * Declare the kernel scheduler jump buffer and stack: | |
| 1124 | */ | |
| 1125 | SCLASS jmp_buf _thread_kern_sched_jb; | |
| 1126 | ||
| 1127 | SCLASS void * _thread_kern_sched_stack | |
| 1128 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 1129 | = NULL | |
| 1130 | #endif | |
| 1131 | ; | |
| 1132 | ||
| 1133 | ||
| 1134 | /* Used for _PTHREADS_INVARIANTS checking. */ | |
| 1135 | SCLASS int _thread_kern_new_state | |
| 1136 | #ifdef GLOBAL_PTHREAD_PRIVATE | |
| 1137 | = 0 | |
| 1138 | #endif | |
| 1139 | ; | |
| 1140 | ||
| 1141 | /* Undefine the storage class specifier: */ | |
| 1142 | #undef SCLASS | |
| 1143 | ||
| 1144 | #ifdef _LOCK_DEBUG | |
| 1145 | #define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock_debug(_fd, _type, \ | |
| 1146 | _ts, __FILE__, __LINE__) | |
| 1147 | #define _FD_UNLOCK(_fd,_type) _thread_fd_unlock_debug(_fd, _type, \ | |
| 1148 | __FILE__, __LINE__) | |
| 1149 | #else | |
| 1150 | #define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock(_fd, _type, _ts) | |
| 1151 | #define _FD_UNLOCK(_fd,_type) _thread_fd_unlock(_fd, _type) | |
| 1152 | #endif | |
| 1153 | ||
| 1154 | /* | |
| 1155 | * Function prototype definitions. | |
| 1156 | */ | |
| 1157 | __BEGIN_DECLS | |
| 1158 | char *__ttyname_basic(int); | |
| 984263bc MD |
1159 | void _cond_wait_backout(pthread_t); |
| 1160 | void _fd_lock_backout(pthread_t); | |
| 1161 | int _find_thread(pthread_t); | |
| 1162 | struct pthread *_get_curthread(void); | |
| 1163 | void _set_curthread(struct pthread *); | |
| 1164 | void _flockfile_backout(struct pthread *); | |
| 1165 | void _funlock_owned(struct pthread *); | |
| 1166 | int _thread_create(pthread_t *,const pthread_attr_t *,void *(*start_routine)(void *),void *,pthread_t); | |
| 1167 | int _mutex_cv_lock(pthread_mutex_t *); | |
| 1168 | int _mutex_cv_unlock(pthread_mutex_t *); | |
| 1169 | void _mutex_lock_backout(pthread_t); | |
| 1170 | void _mutex_notify_priochange(pthread_t); | |
| 1171 | int _mutex_reinit(pthread_mutex_t *); | |
| 1172 | void _mutex_unlock_private(pthread_t); | |
| 1173 | int _cond_reinit(pthread_cond_t *); | |
| 1174 | int _pq_alloc(struct pq_queue *, int, int); | |
| 1175 | int _pq_init(struct pq_queue *); | |
| 1176 | void _pq_remove(struct pq_queue *pq, struct pthread *); | |
| 1177 | void _pq_insert_head(struct pq_queue *pq, struct pthread *); | |
| 1178 | void _pq_insert_tail(struct pq_queue *pq, struct pthread *); | |
| 1179 | struct pthread *_pq_first(struct pq_queue *pq); | |
| 1180 | void *_pthread_getspecific(pthread_key_t); | |
| 1181 | int _pthread_key_create(pthread_key_t *, void (*) (void *)); | |
| 1182 | int _pthread_key_delete(pthread_key_t); | |
| 1183 | int _pthread_mutex_destroy(pthread_mutex_t *); | |
| 1184 | int _pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *); | |
| 1185 | int _pthread_mutex_lock(pthread_mutex_t *); | |
| 1186 | int _pthread_mutex_trylock(pthread_mutex_t *); | |
| 1187 | int _pthread_mutex_unlock(pthread_mutex_t *); | |
| 1188 | int _pthread_once(pthread_once_t *, void (*) (void)); | |
| 1189 | int _pthread_setspecific(pthread_key_t, const void *); | |
| 1190 | int _pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *); | |
| 1191 | int _pthread_cond_destroy(pthread_cond_t *); | |
| 1192 | int _pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *); | |
| 1193 | int _pthread_cond_timedwait(pthread_cond_t *, pthread_mutex_t *, | |
| 1194 | const struct timespec *); | |
| 1195 | int _pthread_cond_signal(pthread_cond_t *); | |
| 1196 | int _pthread_cond_broadcast(pthread_cond_t *); | |
| 1197 | void _waitq_insert(pthread_t pthread); | |
| 1198 | void _waitq_remove(pthread_t pthread); | |
| 1199 | #if defined(_PTHREADS_INVARIANTS) | |
| 1200 | void _waitq_setactive(void); | |
| 1201 | void _waitq_clearactive(void); | |
| 1202 | #endif | |
| 1203 | void _thread_exit(char *, int, char *); | |
| 1204 | void _thread_exit_cleanup(void); | |
| 1205 | int _thread_fd_getflags(int); | |
| 1206 | int _thread_fd_lock(int, int, struct timespec *); | |
| 1207 | int _thread_fd_lock_debug(int, int, struct timespec *,char *fname,int lineno); | |
| 1208 | void _thread_fd_setflags(int, int); | |
| 1209 | int _thread_fd_table_init(int fd); | |
| 1210 | void _thread_fd_unlock(int, int); | |
| 1211 | void _thread_fd_unlock_debug(int, int, char *, int); | |
| 1212 | void _thread_fd_unlock_owned(pthread_t); | |
| 1213 | void *_thread_cleanup(pthread_t); | |
| 1214 | void _thread_cleanupspecific(void); | |
| 1215 | void _thread_dump_info(void); | |
| 1216 | void _thread_init(void); | |
| 1217 | void _thread_kern_sched(ucontext_t *); | |
| 1218 | void _thread_kern_scheduler(void); | |
| 1219 | void _thread_kern_sched_frame(struct pthread_signal_frame *psf); | |
| 1220 | void _thread_kern_sched_sig(void); | |
| 1221 | void _thread_kern_sched_state(enum pthread_state, char *fname, int lineno); | |
| 1222 | void _thread_kern_sched_state_unlock(enum pthread_state state, | |
| 1223 | spinlock_t *lock, char *fname, int lineno); | |
| 1224 | void _thread_kern_set_timeout(const struct timespec *); | |
| 1225 | void _thread_kern_sig_defer(void); | |
| 1226 | void _thread_kern_sig_undefer(void); | |
| c07c16ed | 1227 | void _thread_mksigpipe(void); |
| 984263bc MD |
1228 | void _thread_sig_handler(int, siginfo_t *, ucontext_t *); |
| 1229 | void _thread_sig_check_pending(struct pthread *pthread); | |
| 1230 | void _thread_sig_handle_pending(void); | |
| 1231 | void _thread_sig_send(struct pthread *pthread, int sig); | |
| 1232 | void _thread_sig_wrapper(void); | |
| 1233 | void _thread_sigframe_restore(struct pthread *thread, | |
| 1234 | struct pthread_signal_frame *psf); | |
| 1235 | void _thread_start(void); | |
| 984263bc MD |
1236 | pthread_addr_t _thread_gc(pthread_addr_t); |
| 1237 | void _thread_enter_cancellation_point(void); | |
| 1238 | void _thread_leave_cancellation_point(void); | |
| 1239 | void _thread_cancellation_point(void); | |
| 1240 | ||
| 1241 | /* #include <aio.h> */ | |
| 1242 | #ifdef _SYS_AIO_H_ | |
| 1243 | int __sys_aio_suspend(const struct aiocb * const[], int, const struct timespec *); | |
| 1244 | #endif | |
| 1245 | ||
| 1246 | /* #include <sys/event.h> */ | |
| 1247 | #ifdef _SYS_EVENT_H_ | |
| 1248 | int __sys_kevent(int, const struct kevent *, int, struct kevent *, | |
| 1249 | int, const struct timespec *); | |
| 1250 | #endif | |
| 1251 | ||
| 1252 | /* #include <sys/ioctl.h> */ | |
| 1253 | #ifdef _SYS_IOCTL_H_ | |
| 1254 | int __sys_ioctl(int, unsigned long, ...); | |
| 1255 | #endif | |
| 1256 | ||
| 1257 | /* #include <sys/mman.h> */ | |
| 1258 | #ifdef _SYS_MMAN_H_ | |
| 1259 | int __sys_msync(void *, size_t, int); | |
| 1260 | #endif | |
| 1261 | ||
| 1262 | /* #include <sys/mount.h> */ | |
| 1263 | #ifdef _SYS_MOUNT_H_ | |
| 1264 | int __sys_fstatfs(int, struct statfs *); | |
| 1265 | #endif | |
| 1266 | ||
| 1267 | /* #include <sys/socket.h> */ | |
| 1268 | #ifdef _SYS_SOCKET_H_ | |
| 1269 | int __sys_accept(int, struct sockaddr *, socklen_t *); | |
| b09fd398 | 1270 | int __sys_extaccept(int, int, struct sockaddr *, socklen_t *); |
| 984263bc MD |
1271 | int __sys_bind(int, const struct sockaddr *, socklen_t); |
| 1272 | int __sys_connect(int, const struct sockaddr *, socklen_t); | |
| b09fd398 | 1273 | int __sys_extconnect(int, int, const struct sockaddr *, socklen_t); |
| 984263bc MD |
1274 | int __sys_getpeername(int, struct sockaddr *, socklen_t *); |
| 1275 | int __sys_getsockname(int, struct sockaddr *, socklen_t *); | |
| 1276 | int __sys_getsockopt(int, int, int, void *, socklen_t *); | |
| 1277 | int __sys_listen(int, int); | |
| 1278 | ssize_t __sys_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *); | |
| 1279 | ssize_t __sys_recvmsg(int, struct msghdr *, int); | |
| 1280 | int __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *, off_t *, int); | |
| 1281 | ssize_t __sys_sendmsg(int, const struct msghdr *, int); | |
| 1282 | ssize_t __sys_sendto(int, const void *,size_t, int, const struct sockaddr *, socklen_t); | |
| 1283 | int __sys_setsockopt(int, int, int, const void *, socklen_t); | |
| 1284 | int __sys_shutdown(int, int); | |
| 1285 | int __sys_socket(int, int, int); | |
| 1286 | int __sys_socketpair(int, int, int, int *); | |
| 1287 | #endif | |
| 1288 | ||
| 1289 | /* #include <sys/stat.h> */ | |
| 1290 | #ifdef _SYS_STAT_H_ | |
| 1291 | int __sys_fchflags(int, u_long); | |
| 1292 | int __sys_fchmod(int, mode_t); | |
| 1293 | int __sys_fstat(int, struct stat *); | |
| 1294 | #endif | |
| 1295 | ||
| 1296 | /* #include <sys/uio.h> */ | |
| 1297 | #ifdef _SYS_UIO_H_ | |
| 1298 | ssize_t __sys_readv(int, const struct iovec *, int); | |
| 1299 | ssize_t __sys_writev(int, const struct iovec *, int); | |
| b09fd398 MD |
1300 | ssize_t __sys_extpreadv(int, const struct iovec *, int, int, off_t); |
| 1301 | ssize_t __sys_extpwritev(int, const struct iovec *, int, int, off_t); | |
| 984263bc MD |
1302 | #endif |
| 1303 | ||
| 1304 | /* #include <sys/wait.h> */ | |
| 1305 | #ifdef WNOHANG | |
| 1306 | pid_t __sys_wait4(pid_t, int *, int, struct rusage *); | |
| 1307 | #endif | |
| 1308 | ||
| 1309 | /* #include <dirent.h> */ | |
| 1310 | #ifdef _DIRENT_H_ | |
| 1311 | int __sys_getdirentries(int, char *, int, long *); | |
| 1312 | #endif | |
| 1313 | ||
| 1314 | /* #include <fcntl.h> */ | |
| 1315 | #ifdef _SYS_FCNTL_H_ | |
| 1316 | int __sys_fcntl(int, int, ...); | |
| 1317 | int __sys_flock(int, int); | |
| 1318 | int __sys_open(const char *, int, ...); | |
| 1319 | #endif | |
| 1320 | ||
| 1321 | /* #include <poll.h> */ | |
| 1322 | #ifdef _SYS_POLL_H_ | |
| 1323 | int __sys_poll(struct pollfd *, unsigned, int); | |
| 1324 | #endif | |
| 1325 | ||
| 1326 | /* #include <signal.h> */ | |
| 1327 | #ifdef _SIGNAL_H_ | |
| 1328 | int __sys_sigaction(int, const struct sigaction *, struct sigaction *); | |
| 1329 | int __sys_sigprocmask(int, const sigset_t *, sigset_t *); | |
| 1330 | int __sys_sigreturn(ucontext_t *); | |
| 1331 | #endif | |
| 1332 | ||
| 1333 | /* #include <unistd.h> */ | |
| 1334 | #ifdef _UNISTD_H_ | |
| 6028d5c3 | 1335 | void __sys_exit(int); |
| 984263bc | 1336 | int __sys_close(int); |
| 9d315dd3 | 1337 | int __sys_closefrom(int); |
| 984263bc MD |
1338 | int __sys_dup(int); |
| 1339 | int __sys_dup2(int, int); | |
| 1340 | int __sys_execve(const char *, char * const *, char * const *); | |
| 1341 | int __sys_fchown(int, uid_t, gid_t); | |
| 1342 | pid_t __sys_fork(void); | |
| 1343 | long __sys_fpathconf(int, int); | |
| 1344 | int __sys_fsync(int); | |
| 1345 | int __sys_pipe(int *); | |
| 1346 | ssize_t __sys_read(int, void *, size_t); | |
| b09fd398 | 1347 | ssize_t __sys_extpread(int, void *, size_t, int, off_t); |
| 984263bc | 1348 | ssize_t __sys_write(int, const void *, size_t); |
| b09fd398 | 1349 | ssize_t __sys_extpwrite(int, const void *, size_t, int, off_t); |
| 984263bc MD |
1350 | #endif |
| 1351 | ||
| 1352 | /* #include <setjmp.h> */ | |
| 1353 | #ifdef _SETJMP_H_ | |
| 1354 | extern void __siglongjmp(sigjmp_buf, int) __dead2; | |
| 1355 | extern void __longjmp(jmp_buf, int) __dead2; | |
| 1356 | extern void ___longjmp(jmp_buf, int) __dead2; | |
| 1357 | #endif | |
| 1358 | __END_DECLS | |
| 1359 | ||
| 1360 | #endif /* !_PTHREAD_PRIVATE_H */ |