1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/md/unix/pthreads_user.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,448 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "primpl.h" 1.10 +#include <sys/types.h> 1.11 +#include <unistd.h> 1.12 +#include <signal.h> 1.13 +#include <pthread.h> 1.14 + 1.15 + 1.16 +sigset_t ints_off; 1.17 +pthread_mutex_t _pr_heapLock; 1.18 +pthread_key_t current_thread_key; 1.19 +pthread_key_t current_cpu_key; 1.20 +pthread_key_t last_thread_key; 1.21 +pthread_key_t intsoff_key; 1.22 + 1.23 + 1.24 +PRInt32 _pr_md_pthreads_created, _pr_md_pthreads_failed; 1.25 +PRInt32 _pr_md_pthreads = 1; 1.26 + 1.27 +void _MD_EarlyInit(void) 1.28 +{ 1.29 +extern PRInt32 _nspr_noclock; 1.30 + 1.31 + if (pthread_key_create(¤t_thread_key, NULL) != 0) { 1.32 + perror("pthread_key_create failed"); 1.33 + exit(1); 1.34 + } 1.35 + if (pthread_key_create(¤t_cpu_key, NULL) != 0) { 1.36 + perror("pthread_key_create failed"); 1.37 + exit(1); 1.38 + } 1.39 + if (pthread_key_create(&last_thread_key, NULL) != 0) { 1.40 + perror("pthread_key_create failed"); 1.41 + exit(1); 1.42 + } 1.43 + if (pthread_key_create(&intsoff_key, NULL) != 0) { 1.44 + perror("pthread_key_create failed"); 1.45 + exit(1); 1.46 + } 1.47 + 1.48 + sigemptyset(&ints_off); 1.49 + sigaddset(&ints_off, SIGALRM); 1.50 + sigaddset(&ints_off, SIGIO); 1.51 + sigaddset(&ints_off, SIGCLD); 1.52 + 1.53 + /* 1.54 + * disable clock interrupts 1.55 + */ 1.56 + _nspr_noclock = 1; 1.57 + 1.58 +} 1.59 + 1.60 +void _MD_InitLocks() 1.61 +{ 1.62 + if (pthread_mutex_init(&_pr_heapLock, NULL) != 0) { 1.63 + perror("pthread_mutex_init failed"); 1.64 + exit(1); 1.65 + } 1.66 +} 1.67 + 1.68 +PR_IMPLEMENT(void) _MD_FREE_LOCK(struct _MDLock *lockp) 1.69 +{ 1.70 + PRIntn _is; 1.71 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.72 + 1.73 + if (me && !_PR_IS_NATIVE_THREAD(me)) 1.74 + _PR_INTSOFF(_is); 1.75 + pthread_mutex_destroy(&lockp->mutex); 1.76 + if (me && !_PR_IS_NATIVE_THREAD(me)) 1.77 + _PR_FAST_INTSON(_is); 1.78 +} 1.79 + 1.80 + 1.81 + 1.82 +PR_IMPLEMENT(PRStatus) _MD_NEW_LOCK(struct _MDLock *lockp) 1.83 +{ 1.84 + PRStatus rv; 1.85 + PRIntn is; 1.86 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.87 + 1.88 + if (me && !_PR_IS_NATIVE_THREAD(me)) 1.89 + _PR_INTSOFF(is); 1.90 + rv = pthread_mutex_init(&lockp->mutex, NULL); 1.91 + if (me && !_PR_IS_NATIVE_THREAD(me)) 1.92 + _PR_FAST_INTSON(is); 1.93 + return (rv == 0) ? PR_SUCCESS : PR_FAILURE; 1.94 +} 1.95 + 1.96 + 1.97 +PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) 1.98 +{ 1.99 + if (isCurrent) { 1.100 + (void) setjmp(CONTEXT(t)); 1.101 + } 1.102 + *np = sizeof(CONTEXT(t)) / sizeof(PRWord); 1.103 + return (PRWord *) CONTEXT(t); 1.104 +} 1.105 + 1.106 +PR_IMPLEMENT(void) 1.107 +_MD_SetPriority(_MDThread *thread, PRThreadPriority newPri) 1.108 +{ 1.109 + /* 1.110 + * XXX - to be implemented 1.111 + */ 1.112 + return; 1.113 +} 1.114 + 1.115 +PR_IMPLEMENT(PRStatus) _MD_InitThread(struct PRThread *thread) 1.116 +{ 1.117 + struct sigaction sigact; 1.118 + 1.119 + if (thread->flags & _PR_GLOBAL_SCOPE) { 1.120 + thread->md.pthread = pthread_self(); 1.121 +#if 0 1.122 + /* 1.123 + * set up SIGUSR1 handler; this is used to save state 1.124 + * during PR_SuspendAll 1.125 + */ 1.126 + sigact.sa_handler = save_context_and_block; 1.127 + sigact.sa_flags = SA_RESTART; 1.128 + /* 1.129 + * Must mask clock interrupts 1.130 + */ 1.131 + sigact.sa_mask = timer_set; 1.132 + sigaction(SIGUSR1, &sigact, 0); 1.133 +#endif 1.134 + } 1.135 + 1.136 + return PR_SUCCESS; 1.137 +} 1.138 + 1.139 +PR_IMPLEMENT(void) _MD_ExitThread(struct PRThread *thread) 1.140 +{ 1.141 + if (thread->flags & _PR_GLOBAL_SCOPE) { 1.142 + _MD_CLEAN_THREAD(thread); 1.143 + _MD_SET_CURRENT_THREAD(NULL); 1.144 + } 1.145 +} 1.146 + 1.147 +PR_IMPLEMENT(void) _MD_CleanThread(struct PRThread *thread) 1.148 +{ 1.149 + if (thread->flags & _PR_GLOBAL_SCOPE) { 1.150 + pthread_mutex_destroy(&thread->md.pthread_mutex); 1.151 + pthread_cond_destroy(&thread->md.pthread_cond); 1.152 + } 1.153 +} 1.154 + 1.155 +PR_IMPLEMENT(void) _MD_SuspendThread(struct PRThread *thread) 1.156 +{ 1.157 + PRInt32 rv; 1.158 + 1.159 + PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) && 1.160 + _PR_IS_GCABLE_THREAD(thread)); 1.161 +#if 0 1.162 + thread->md.suspending_id = getpid(); 1.163 + rv = kill(thread->md.id, SIGUSR1); 1.164 + PR_ASSERT(rv == 0); 1.165 + /* 1.166 + * now, block the current thread/cpu until woken up by the suspended 1.167 + * thread from it's SIGUSR1 signal handler 1.168 + */ 1.169 + blockproc(getpid()); 1.170 +#endif 1.171 +} 1.172 + 1.173 +PR_IMPLEMENT(void) _MD_ResumeThread(struct PRThread *thread) 1.174 +{ 1.175 + PRInt32 rv; 1.176 + 1.177 + PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) && 1.178 + _PR_IS_GCABLE_THREAD(thread)); 1.179 +#if 0 1.180 + rv = unblockproc(thread->md.id); 1.181 +#endif 1.182 +} 1.183 + 1.184 +PR_IMPLEMENT(void) _MD_SuspendCPU(struct _PRCPU *thread) 1.185 +{ 1.186 + PRInt32 rv; 1.187 + 1.188 +#if 0 1.189 + cpu->md.suspending_id = getpid(); 1.190 + rv = kill(cpu->md.id, SIGUSR1); 1.191 + PR_ASSERT(rv == 0); 1.192 + /* 1.193 + * now, block the current thread/cpu until woken up by the suspended 1.194 + * thread from it's SIGUSR1 signal handler 1.195 + */ 1.196 + blockproc(getpid()); 1.197 +#endif 1.198 +} 1.199 + 1.200 +PR_IMPLEMENT(void) _MD_ResumeCPU(struct _PRCPU *thread) 1.201 +{ 1.202 +#if 0 1.203 + unblockproc(cpu->md.id); 1.204 +#endif 1.205 +} 1.206 + 1.207 + 1.208 +#define PT_NANOPERMICRO 1000UL 1.209 +#define PT_BILLION 1000000000UL 1.210 + 1.211 +PR_IMPLEMENT(PRStatus) 1.212 +_pt_wait(PRThread *thread, PRIntervalTime timeout) 1.213 +{ 1.214 +int rv; 1.215 +struct timeval now; 1.216 +struct timespec tmo; 1.217 +PRUint32 ticks = PR_TicksPerSecond(); 1.218 + 1.219 + 1.220 + if (timeout != PR_INTERVAL_NO_TIMEOUT) { 1.221 + tmo.tv_sec = timeout / ticks; 1.222 + tmo.tv_nsec = timeout - (tmo.tv_sec * ticks); 1.223 + tmo.tv_nsec = PR_IntervalToMicroseconds(PT_NANOPERMICRO * 1.224 + tmo.tv_nsec); 1.225 + 1.226 + /* pthreads wants this in absolute time, off we go ... */ 1.227 + (void)GETTIMEOFDAY(&now); 1.228 + /* that one's usecs, this one's nsecs - grrrr! */ 1.229 + tmo.tv_sec += now.tv_sec; 1.230 + tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec); 1.231 + tmo.tv_sec += tmo.tv_nsec / PT_BILLION; 1.232 + tmo.tv_nsec %= PT_BILLION; 1.233 + } 1.234 + 1.235 + pthread_mutex_lock(&thread->md.pthread_mutex); 1.236 + thread->md.wait--; 1.237 + if (thread->md.wait < 0) { 1.238 + if (timeout != PR_INTERVAL_NO_TIMEOUT) { 1.239 + rv = pthread_cond_timedwait(&thread->md.pthread_cond, 1.240 + &thread->md.pthread_mutex, &tmo); 1.241 + } 1.242 + else 1.243 + rv = pthread_cond_wait(&thread->md.pthread_cond, 1.244 + &thread->md.pthread_mutex); 1.245 + if (rv != 0) { 1.246 + thread->md.wait++; 1.247 + } 1.248 + } else 1.249 + rv = 0; 1.250 + pthread_mutex_unlock(&thread->md.pthread_mutex); 1.251 + 1.252 + return (rv == 0) ? PR_SUCCESS : PR_FAILURE; 1.253 +} 1.254 + 1.255 +PR_IMPLEMENT(PRStatus) 1.256 +_MD_wait(PRThread *thread, PRIntervalTime ticks) 1.257 +{ 1.258 + if ( thread->flags & _PR_GLOBAL_SCOPE ) { 1.259 + _MD_CHECK_FOR_EXIT(); 1.260 + if (_pt_wait(thread, ticks) == PR_FAILURE) { 1.261 + _MD_CHECK_FOR_EXIT(); 1.262 + /* 1.263 + * wait timed out 1.264 + */ 1.265 + _PR_THREAD_LOCK(thread); 1.266 + if (thread->wait.cvar) { 1.267 + /* 1.268 + * The thread will remove itself from the waitQ 1.269 + * of the cvar in _PR_WaitCondVar 1.270 + */ 1.271 + thread->wait.cvar = NULL; 1.272 + thread->state = _PR_RUNNING; 1.273 + _PR_THREAD_UNLOCK(thread); 1.274 + } else { 1.275 + _pt_wait(thread, PR_INTERVAL_NO_TIMEOUT); 1.276 + _PR_THREAD_UNLOCK(thread); 1.277 + } 1.278 + } 1.279 + } else { 1.280 + _PR_MD_SWITCH_CONTEXT(thread); 1.281 + } 1.282 + return PR_SUCCESS; 1.283 +} 1.284 + 1.285 +PR_IMPLEMENT(PRStatus) 1.286 +_MD_WakeupWaiter(PRThread *thread) 1.287 +{ 1.288 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.289 + PRInt32 pid, rv; 1.290 + PRIntn is; 1.291 + 1.292 + PR_ASSERT(_pr_md_idle_cpus >= 0); 1.293 + if (thread == NULL) { 1.294 + if (_pr_md_idle_cpus) 1.295 + _MD_Wakeup_CPUs(); 1.296 + } else if (!_PR_IS_NATIVE_THREAD(thread)) { 1.297 + /* 1.298 + * If the thread is on my cpu's runq there is no need to 1.299 + * wakeup any cpus 1.300 + */ 1.301 + if (!_PR_IS_NATIVE_THREAD(me)) { 1.302 + if (me->cpu != thread->cpu) { 1.303 + if (_pr_md_idle_cpus) 1.304 + _MD_Wakeup_CPUs(); 1.305 + } 1.306 + } else { 1.307 + if (_pr_md_idle_cpus) 1.308 + _MD_Wakeup_CPUs(); 1.309 + } 1.310 + } else { 1.311 + PR_ASSERT(_PR_IS_NATIVE_THREAD(thread)); 1.312 + if (!_PR_IS_NATIVE_THREAD(me)) 1.313 + _PR_INTSOFF(is); 1.314 + 1.315 + pthread_mutex_lock(&thread->md.pthread_mutex); 1.316 + thread->md.wait++; 1.317 + rv = pthread_cond_signal(&thread->md.pthread_cond); 1.318 + PR_ASSERT(rv == 0); 1.319 + pthread_mutex_unlock(&thread->md.pthread_mutex); 1.320 + 1.321 + if (!_PR_IS_NATIVE_THREAD(me)) 1.322 + _PR_FAST_INTSON(is); 1.323 + } 1.324 + return PR_SUCCESS; 1.325 +} 1.326 + 1.327 +/* These functions should not be called for AIX */ 1.328 +PR_IMPLEMENT(void) 1.329 +_MD_YIELD(void) 1.330 +{ 1.331 + PR_NOT_REACHED("_MD_YIELD should not be called for AIX."); 1.332 +} 1.333 + 1.334 +PR_IMPLEMENT(PRStatus) 1.335 +_MD_CreateThread( 1.336 + PRThread *thread, 1.337 + void (*start) (void *), 1.338 + PRThreadPriority priority, 1.339 + PRThreadScope scope, 1.340 + PRThreadState state, 1.341 + PRUint32 stackSize) 1.342 +{ 1.343 + PRIntn is; 1.344 + int rv; 1.345 + PRThread *me = _PR_MD_CURRENT_THREAD(); 1.346 + pthread_attr_t attr; 1.347 + 1.348 + if (!_PR_IS_NATIVE_THREAD(me)) 1.349 + _PR_INTSOFF(is); 1.350 + 1.351 + if (pthread_mutex_init(&thread->md.pthread_mutex, NULL) != 0) { 1.352 + if (!_PR_IS_NATIVE_THREAD(me)) 1.353 + _PR_FAST_INTSON(is); 1.354 + return PR_FAILURE; 1.355 + } 1.356 + 1.357 + if (pthread_cond_init(&thread->md.pthread_cond, NULL) != 0) { 1.358 + pthread_mutex_destroy(&thread->md.pthread_mutex); 1.359 + if (!_PR_IS_NATIVE_THREAD(me)) 1.360 + _PR_FAST_INTSON(is); 1.361 + return PR_FAILURE; 1.362 + } 1.363 + thread->flags |= _PR_GLOBAL_SCOPE; 1.364 + 1.365 + pthread_attr_init(&attr); /* initialize attr with default attributes */ 1.366 + if (pthread_attr_setstacksize(&attr, (size_t) stackSize) != 0) { 1.367 + pthread_mutex_destroy(&thread->md.pthread_mutex); 1.368 + pthread_cond_destroy(&thread->md.pthread_cond); 1.369 + pthread_attr_destroy(&attr); 1.370 + if (!_PR_IS_NATIVE_THREAD(me)) 1.371 + _PR_FAST_INTSON(is); 1.372 + return PR_FAILURE; 1.373 + } 1.374 + 1.375 + thread->md.wait = 0; 1.376 + rv = pthread_create(&thread->md.pthread, &attr, start, (void *)thread); 1.377 + if (0 == rv) { 1.378 + _MD_ATOMIC_INCREMENT(&_pr_md_pthreads_created); 1.379 + _MD_ATOMIC_INCREMENT(&_pr_md_pthreads); 1.380 + if (!_PR_IS_NATIVE_THREAD(me)) 1.381 + _PR_FAST_INTSON(is); 1.382 + return PR_SUCCESS; 1.383 + } else { 1.384 + pthread_mutex_destroy(&thread->md.pthread_mutex); 1.385 + pthread_cond_destroy(&thread->md.pthread_cond); 1.386 + pthread_attr_destroy(&attr); 1.387 + _MD_ATOMIC_INCREMENT(&_pr_md_pthreads_failed); 1.388 + if (!_PR_IS_NATIVE_THREAD(me)) 1.389 + _PR_FAST_INTSON(is); 1.390 + PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, rv); 1.391 + return PR_FAILURE; 1.392 + } 1.393 +} 1.394 + 1.395 +PR_IMPLEMENT(void) 1.396 +_MD_InitRunningCPU(struct _PRCPU *cpu) 1.397 +{ 1.398 + extern int _pr_md_pipefd[2]; 1.399 + 1.400 + _MD_unix_init_running_cpu(cpu); 1.401 + cpu->md.pthread = pthread_self(); 1.402 + if (_pr_md_pipefd[0] >= 0) { 1.403 + _PR_IOQ_MAX_OSFD(cpu) = _pr_md_pipefd[0]; 1.404 +#ifndef _PR_USE_POLL 1.405 + FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(cpu)); 1.406 +#endif 1.407 + } 1.408 +} 1.409 + 1.410 + 1.411 +void 1.412 +_MD_CleanupBeforeExit(void) 1.413 +{ 1.414 +#if 0 1.415 + extern PRInt32 _pr_cpus_exit; 1.416 + 1.417 + _pr_irix_exit_now = 1; 1.418 + if (_pr_numCPU > 1) { 1.419 + /* 1.420 + * Set a global flag, and wakeup all cpus which will notice the flag 1.421 + * and exit. 1.422 + */ 1.423 + _pr_cpus_exit = getpid(); 1.424 + _MD_Wakeup_CPUs(); 1.425 + while(_pr_numCPU > 1) { 1.426 + _PR_WAIT_SEM(_pr_irix_exit_sem); 1.427 + _pr_numCPU--; 1.428 + } 1.429 + } 1.430 + /* 1.431 + * cause global threads on the recycle list to exit 1.432 + */ 1.433 + _PR_DEADQ_LOCK; 1.434 + if (_PR_NUM_DEADNATIVE != 0) { 1.435 + PRThread *thread; 1.436 + PRCList *ptr; 1.437 + 1.438 + ptr = _PR_DEADNATIVEQ.next; 1.439 + while( ptr != &_PR_DEADNATIVEQ ) { 1.440 + thread = _PR_THREAD_PTR(ptr); 1.441 + _MD_CVAR_POST_SEM(thread); 1.442 + ptr = ptr->next; 1.443 + } 1.444 + } 1.445 + _PR_DEADQ_UNLOCK; 1.446 + while(_PR_NUM_DEADNATIVE > 1) { 1.447 + _PR_WAIT_SEM(_pr_irix_exit_sem); 1.448 + _PR_DEC_DEADNATIVE; 1.449 + } 1.450 +#endif 1.451 +}