Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
michael@0 | 1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #ifndef nspr_pth_defs_h_ |
michael@0 | 7 | #define nspr_pth_defs_h_ |
michael@0 | 8 | |
michael@0 | 9 | /* |
michael@0 | 10 | ** Appropriate definitions of entry points not used in a pthreads world |
michael@0 | 11 | */ |
michael@0 | 12 | #define _PR_MD_BLOCK_CLOCK_INTERRUPTS() |
michael@0 | 13 | #define _PR_MD_UNBLOCK_CLOCK_INTERRUPTS() |
michael@0 | 14 | #define _PR_MD_DISABLE_CLOCK_INTERRUPTS() |
michael@0 | 15 | #define _PR_MD_ENABLE_CLOCK_INTERRUPTS() |
michael@0 | 16 | |
michael@0 | 17 | /* In good standards fashion, the DCE threads (based on posix-4) are not |
michael@0 | 18 | * quite the same as newer posix implementations. These are mostly name |
michael@0 | 19 | * changes and small differences, so macros usually do the trick |
michael@0 | 20 | */ |
michael@0 | 21 | #ifdef _PR_DCETHREADS |
michael@0 | 22 | #define _PT_PTHREAD_MUTEXATTR_INIT pthread_mutexattr_create |
michael@0 | 23 | #define _PT_PTHREAD_MUTEXATTR_DESTROY pthread_mutexattr_delete |
michael@0 | 24 | #define _PT_PTHREAD_MUTEX_INIT(m, a) pthread_mutex_init(&(m), a) |
michael@0 | 25 | #define _PT_PTHREAD_MUTEX_IS_LOCKED(m) (0 == pthread_mutex_trylock(&(m))) |
michael@0 | 26 | #define _PT_PTHREAD_CONDATTR_INIT pthread_condattr_create |
michael@0 | 27 | #define _PT_PTHREAD_COND_INIT(m, a) pthread_cond_init(&(m), a) |
michael@0 | 28 | #define _PT_PTHREAD_CONDATTR_DESTROY pthread_condattr_delete |
michael@0 | 29 | |
michael@0 | 30 | /* Notes about differences between DCE threads and pthreads 10: |
michael@0 | 31 | * 1. pthread_mutex_trylock returns 1 when it locks the mutex |
michael@0 | 32 | * 0 when it does not. The latest pthreads has a set of errno-like |
michael@0 | 33 | * return values. |
michael@0 | 34 | * 2. return values from pthread_cond_timedwait are different. |
michael@0 | 35 | * |
michael@0 | 36 | * |
michael@0 | 37 | * |
michael@0 | 38 | */ |
michael@0 | 39 | #elif defined(BSDI) |
michael@0 | 40 | /* |
michael@0 | 41 | * Mutex and condition attributes are not supported. The attr |
michael@0 | 42 | * argument to pthread_mutex_init() and pthread_cond_init() must |
michael@0 | 43 | * be passed as NULL. |
michael@0 | 44 | * |
michael@0 | 45 | * The memset calls in _PT_PTHREAD_MUTEX_INIT and _PT_PTHREAD_COND_INIT |
michael@0 | 46 | * are to work around BSDI's using a single bit to indicate a mutex |
michael@0 | 47 | * or condition variable is initialized. This entire BSDI section |
michael@0 | 48 | * will go away when BSDI releases updated threads libraries for |
michael@0 | 49 | * BSD/OS 3.1 and 4.0. |
michael@0 | 50 | */ |
michael@0 | 51 | #define _PT_PTHREAD_MUTEXATTR_INIT(x) 0 |
michael@0 | 52 | #define _PT_PTHREAD_MUTEXATTR_DESTROY(x) /* */ |
michael@0 | 53 | #define _PT_PTHREAD_MUTEX_INIT(m, a) (memset(&(m), 0, sizeof(m)), \ |
michael@0 | 54 | pthread_mutex_init(&(m), NULL)) |
michael@0 | 55 | #define _PT_PTHREAD_MUTEX_IS_LOCKED(m) (EBUSY == pthread_mutex_trylock(&(m))) |
michael@0 | 56 | #define _PT_PTHREAD_CONDATTR_INIT(x) 0 |
michael@0 | 57 | #define _PT_PTHREAD_CONDATTR_DESTROY(x) /* */ |
michael@0 | 58 | #define _PT_PTHREAD_COND_INIT(m, a) (memset(&(m), 0, sizeof(m)), \ |
michael@0 | 59 | pthread_cond_init(&(m), NULL)) |
michael@0 | 60 | #else |
michael@0 | 61 | #define _PT_PTHREAD_MUTEXATTR_INIT pthread_mutexattr_init |
michael@0 | 62 | #define _PT_PTHREAD_MUTEXATTR_DESTROY pthread_mutexattr_destroy |
michael@0 | 63 | #define _PT_PTHREAD_MUTEX_INIT(m, a) pthread_mutex_init(&(m), &(a)) |
michael@0 | 64 | #if defined(FREEBSD) |
michael@0 | 65 | #define _PT_PTHREAD_MUTEX_IS_LOCKED(m) pt_pthread_mutex_is_locked(&(m)) |
michael@0 | 66 | #else |
michael@0 | 67 | #define _PT_PTHREAD_MUTEX_IS_LOCKED(m) (EBUSY == pthread_mutex_trylock(&(m))) |
michael@0 | 68 | #endif |
michael@0 | 69 | #if defined(ANDROID) |
michael@0 | 70 | /* Conditional attribute init and destroy aren't implemented in bionic. */ |
michael@0 | 71 | #define _PT_PTHREAD_CONDATTR_INIT(x) 0 |
michael@0 | 72 | #define _PT_PTHREAD_CONDATTR_DESTROY(x) /* */ |
michael@0 | 73 | #else |
michael@0 | 74 | #define _PT_PTHREAD_CONDATTR_INIT pthread_condattr_init |
michael@0 | 75 | #define _PT_PTHREAD_CONDATTR_DESTROY pthread_condattr_destroy |
michael@0 | 76 | #endif |
michael@0 | 77 | #define _PT_PTHREAD_COND_INIT(m, a) pthread_cond_init(&(m), &(a)) |
michael@0 | 78 | #endif |
michael@0 | 79 | |
michael@0 | 80 | /* The pthreads standard does not specify an invalid value for the |
michael@0 | 81 | * pthread_t handle. (0 is usually an invalid pthread identifier |
michael@0 | 82 | * but there are exceptions, for example, DG/UX.) These macros |
michael@0 | 83 | * define a way to set the handle to or compare the handle with an |
michael@0 | 84 | * invalid identifier. These macros are not portable and may be |
michael@0 | 85 | * more of a problem as we adapt to more pthreads implementations. |
michael@0 | 86 | * They are only used in the PRMonitor functions. Do not use them |
michael@0 | 87 | * in new code. |
michael@0 | 88 | * |
michael@0 | 89 | * Unfortunately some of our clients depend on certain properties |
michael@0 | 90 | * of our PRMonitor implementation, preventing us from replacing |
michael@0 | 91 | * it by a portable implementation. |
michael@0 | 92 | * - High-performance servers like the fact that PR_EnterMonitor |
michael@0 | 93 | * only calls PR_Lock and PR_ExitMonitor only calls PR_Unlock. |
michael@0 | 94 | * (A portable implementation would use a PRLock and a PRCondVar |
michael@0 | 95 | * to implement the recursive lock in a monitor and call both |
michael@0 | 96 | * PR_Lock and PR_Unlock in PR_EnterMonitor and PR_ExitMonitor.) |
michael@0 | 97 | * Unfortunately this forces us to read the monitor owner field |
michael@0 | 98 | * without holding a lock. |
michael@0 | 99 | * - One way to make it safe to read the monitor owner field |
michael@0 | 100 | * without holding a lock is to make that field a PRThread* |
michael@0 | 101 | * (one should be able to read a pointer with a single machine |
michael@0 | 102 | * instruction). However, PR_GetCurrentThread calls calloc if |
michael@0 | 103 | * it is called by a thread that was not created by NSPR. The |
michael@0 | 104 | * malloc tracing tools in the Mozilla client use PRMonitor for |
michael@0 | 105 | * locking in their malloc, calloc, and free functions. If |
michael@0 | 106 | * PR_EnterMonitor calls any of these functions, infinite |
michael@0 | 107 | * recursion ensues. |
michael@0 | 108 | */ |
michael@0 | 109 | #if defined(_PR_DCETHREADS) |
michael@0 | 110 | #define _PT_PTHREAD_INVALIDATE_THR_HANDLE(t) \ |
michael@0 | 111 | memset(&(t), 0, sizeof(pthread_t)) |
michael@0 | 112 | #define _PT_PTHREAD_THR_HANDLE_IS_INVALID(t) \ |
michael@0 | 113 | (!memcmp(&(t), &pt_zero_tid, sizeof(pthread_t))) |
michael@0 | 114 | #define _PT_PTHREAD_COPY_THR_HANDLE(st, dt) (dt) = (st) |
michael@0 | 115 | #elif defined(IRIX) || defined(OSF1) || defined(AIX) || defined(SOLARIS) \ |
michael@0 | 116 | || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \ |
michael@0 | 117 | || defined(HPUX) || defined(FREEBSD) \ |
michael@0 | 118 | || defined(NETBSD) || defined(OPENBSD) || defined(BSDI) \ |
michael@0 | 119 | || defined(NTO) || defined(DARWIN) \ |
michael@0 | 120 | || defined(UNIXWARE) || defined(RISCOS) || defined(SYMBIAN) |
michael@0 | 121 | #define _PT_PTHREAD_INVALIDATE_THR_HANDLE(t) (t) = 0 |
michael@0 | 122 | #define _PT_PTHREAD_THR_HANDLE_IS_INVALID(t) (t) == 0 |
michael@0 | 123 | #define _PT_PTHREAD_COPY_THR_HANDLE(st, dt) (dt) = (st) |
michael@0 | 124 | #else |
michael@0 | 125 | #error "pthreads is not supported for this architecture" |
michael@0 | 126 | #endif |
michael@0 | 127 | |
michael@0 | 128 | #if defined(_PR_DCETHREADS) |
michael@0 | 129 | #define _PT_PTHREAD_ATTR_INIT pthread_attr_create |
michael@0 | 130 | #define _PT_PTHREAD_ATTR_DESTROY pthread_attr_delete |
michael@0 | 131 | #define _PT_PTHREAD_CREATE(t, a, f, r) pthread_create(t, a, f, r) |
michael@0 | 132 | #define _PT_PTHREAD_KEY_CREATE pthread_keycreate |
michael@0 | 133 | #define _PT_PTHREAD_ATTR_SETSCHEDPOLICY pthread_attr_setsched |
michael@0 | 134 | #define _PT_PTHREAD_ATTR_GETSTACKSIZE(a, s) \ |
michael@0 | 135 | (*(s) = pthread_attr_getstacksize(*(a)), 0) |
michael@0 | 136 | #define _PT_PTHREAD_GETSPECIFIC(k, r) \ |
michael@0 | 137 | pthread_getspecific((k), (pthread_addr_t *) &(r)) |
michael@0 | 138 | #elif defined(_PR_PTHREADS) |
michael@0 | 139 | #define _PT_PTHREAD_ATTR_INIT pthread_attr_init |
michael@0 | 140 | #define _PT_PTHREAD_ATTR_DESTROY pthread_attr_destroy |
michael@0 | 141 | #define _PT_PTHREAD_CREATE(t, a, f, r) pthread_create(t, &a, f, r) |
michael@0 | 142 | #define _PT_PTHREAD_KEY_CREATE pthread_key_create |
michael@0 | 143 | #define _PT_PTHREAD_ATTR_SETSCHEDPOLICY pthread_attr_setschedpolicy |
michael@0 | 144 | #define _PT_PTHREAD_ATTR_GETSTACKSIZE(a, s) pthread_attr_getstacksize(a, s) |
michael@0 | 145 | #define _PT_PTHREAD_GETSPECIFIC(k, r) (r) = pthread_getspecific(k) |
michael@0 | 146 | #else |
michael@0 | 147 | #error "Cannot determine pthread strategy" |
michael@0 | 148 | #endif |
michael@0 | 149 | |
michael@0 | 150 | #if defined(_PR_DCETHREADS) |
michael@0 | 151 | #define _PT_PTHREAD_EXPLICIT_SCHED _PT_PTHREAD_DEFAULT_SCHED |
michael@0 | 152 | #endif |
michael@0 | 153 | |
michael@0 | 154 | /* |
michael@0 | 155 | * pthread_mutex_trylock returns different values in DCE threads and |
michael@0 | 156 | * pthreads. |
michael@0 | 157 | */ |
michael@0 | 158 | #if defined(_PR_DCETHREADS) |
michael@0 | 159 | #define PT_TRYLOCK_SUCCESS 1 |
michael@0 | 160 | #define PT_TRYLOCK_BUSY 0 |
michael@0 | 161 | #else |
michael@0 | 162 | #define PT_TRYLOCK_SUCCESS 0 |
michael@0 | 163 | #define PT_TRYLOCK_BUSY EBUSY |
michael@0 | 164 | #endif |
michael@0 | 165 | |
michael@0 | 166 | /* |
michael@0 | 167 | * These platforms don't have sigtimedwait() |
michael@0 | 168 | */ |
michael@0 | 169 | #if (defined(AIX) && !defined(AIX4_3_PLUS)) \ |
michael@0 | 170 | || defined(LINUX) || defined(__GNU__)|| defined(__GLIBC__) \ |
michael@0 | 171 | || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \ |
michael@0 | 172 | || defined(BSDI) || defined(UNIXWARE) \ |
michael@0 | 173 | || defined(DARWIN) || defined(SYMBIAN) |
michael@0 | 174 | #define PT_NO_SIGTIMEDWAIT |
michael@0 | 175 | #endif |
michael@0 | 176 | |
michael@0 | 177 | #if defined(OSF1) |
michael@0 | 178 | #define PT_PRIO_MIN PRI_OTHER_MIN |
michael@0 | 179 | #define PT_PRIO_MAX PRI_OTHER_MAX |
michael@0 | 180 | #elif defined(IRIX) |
michael@0 | 181 | #include <sys/sched.h> |
michael@0 | 182 | #define PT_PRIO_MIN PX_PRIO_MIN |
michael@0 | 183 | #define PT_PRIO_MAX PX_PRIO_MAX |
michael@0 | 184 | #elif defined(AIX) |
michael@0 | 185 | #include <sys/priv.h> |
michael@0 | 186 | #include <sys/sched.h> |
michael@0 | 187 | #ifndef PTHREAD_CREATE_JOINABLE |
michael@0 | 188 | #define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED |
michael@0 | 189 | #endif |
michael@0 | 190 | #define PT_PRIO_MIN DEFAULT_PRIO |
michael@0 | 191 | #define PT_PRIO_MAX DEFAULT_PRIO |
michael@0 | 192 | #elif defined(HPUX) |
michael@0 | 193 | |
michael@0 | 194 | #if defined(_PR_DCETHREADS) |
michael@0 | 195 | #define PT_PRIO_MIN PRI_OTHER_MIN |
michael@0 | 196 | #define PT_PRIO_MAX PRI_OTHER_MAX |
michael@0 | 197 | #else /* defined(_PR_DCETHREADS) */ |
michael@0 | 198 | #include <sys/sched.h> |
michael@0 | 199 | #define PT_PRIO_MIN sched_get_priority_min(SCHED_OTHER) |
michael@0 | 200 | #define PT_PRIO_MAX sched_get_priority_max(SCHED_OTHER) |
michael@0 | 201 | #endif /* defined(_PR_DCETHREADS) */ |
michael@0 | 202 | |
michael@0 | 203 | #elif defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \ |
michael@0 | 204 | || defined(FREEBSD) || defined(SYMBIAN) |
michael@0 | 205 | #define PT_PRIO_MIN sched_get_priority_min(SCHED_OTHER) |
michael@0 | 206 | #define PT_PRIO_MAX sched_get_priority_max(SCHED_OTHER) |
michael@0 | 207 | #elif defined(NTO) |
michael@0 | 208 | /* |
michael@0 | 209 | * Neutrino has functions that return the priority range but |
michael@0 | 210 | * they return invalid numbers, so I just hard coded these here |
michael@0 | 211 | * for now. Jerry.Kirk@Nexarecorp.com |
michael@0 | 212 | */ |
michael@0 | 213 | #define PT_PRIO_MIN 0 |
michael@0 | 214 | #define PT_PRIO_MAX 30 |
michael@0 | 215 | #elif defined(SOLARIS) |
michael@0 | 216 | /* |
michael@0 | 217 | * Solaris doesn't seem to have macros for the min/max priorities. |
michael@0 | 218 | * The range of 0-127 is mentioned in the pthread_setschedparam(3T) |
michael@0 | 219 | * man pages, and pthread_setschedparam indeed allows 0-127. However, |
michael@0 | 220 | * pthread_attr_setschedparam does not allow 0; it allows 1-127. |
michael@0 | 221 | */ |
michael@0 | 222 | #define PT_PRIO_MIN 1 |
michael@0 | 223 | #define PT_PRIO_MAX 127 |
michael@0 | 224 | #elif defined(OPENBSD) |
michael@0 | 225 | #define PT_PRIO_MIN 0 |
michael@0 | 226 | #define PT_PRIO_MAX 31 |
michael@0 | 227 | #elif defined(NETBSD) \ |
michael@0 | 228 | || defined(BSDI) || defined(DARWIN) || defined(UNIXWARE) \ |
michael@0 | 229 | || defined(RISCOS) /* XXX */ |
michael@0 | 230 | #define PT_PRIO_MIN 0 |
michael@0 | 231 | #define PT_PRIO_MAX 126 |
michael@0 | 232 | #else |
michael@0 | 233 | #error "pthreads is not supported for this architecture" |
michael@0 | 234 | #endif |
michael@0 | 235 | |
michael@0 | 236 | /* |
michael@0 | 237 | * The _PT_PTHREAD_YIELD function is called from a signal handler. |
michael@0 | 238 | * Needed for garbage collection -- Look at PR_Suspend/PR_Resume |
michael@0 | 239 | * implementation. |
michael@0 | 240 | */ |
michael@0 | 241 | #if defined(_PR_DCETHREADS) |
michael@0 | 242 | #define _PT_PTHREAD_YIELD() pthread_yield() |
michael@0 | 243 | #elif defined(OSF1) |
michael@0 | 244 | /* |
michael@0 | 245 | * sched_yield can't be called from a signal handler. Must use |
michael@0 | 246 | * the _np version. |
michael@0 | 247 | */ |
michael@0 | 248 | #define _PT_PTHREAD_YIELD() pthread_yield_np() |
michael@0 | 249 | #elif defined(AIX) |
michael@0 | 250 | extern int (*_PT_aix_yield_fcn)(); |
michael@0 | 251 | #define _PT_PTHREAD_YIELD() (*_PT_aix_yield_fcn)() |
michael@0 | 252 | #elif defined(IRIX) |
michael@0 | 253 | #include <time.h> |
michael@0 | 254 | #define _PT_PTHREAD_YIELD() \ |
michael@0 | 255 | PR_BEGIN_MACRO \ |
michael@0 | 256 | struct timespec onemillisec = {0}; \ |
michael@0 | 257 | onemillisec.tv_nsec = 1000000L; \ |
michael@0 | 258 | nanosleep(&onemillisec,NULL); \ |
michael@0 | 259 | PR_END_MACRO |
michael@0 | 260 | #elif defined(HPUX) || defined(SOLARIS) \ |
michael@0 | 261 | || defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \ |
michael@0 | 262 | || defined(FREEBSD) || defined(NETBSD) || defined(OPENBSD) \ |
michael@0 | 263 | || defined(BSDI) || defined(NTO) || defined(DARWIN) \ |
michael@0 | 264 | || defined(UNIXWARE) || defined(RISCOS) || defined(SYMBIAN) |
michael@0 | 265 | #define _PT_PTHREAD_YIELD() sched_yield() |
michael@0 | 266 | #else |
michael@0 | 267 | #error "Need to define _PT_PTHREAD_YIELD for this platform" |
michael@0 | 268 | #endif |
michael@0 | 269 | |
michael@0 | 270 | #endif /* nspr_pth_defs_h_ */ |