home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /*
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
-
- #include "primpl.h"
- #include <sys/types.h>
- #include <unistd.h>
- #include <signal.h>
- #include <pthread.h>
-
-
- sigset_t ints_off;
- pthread_mutex_t _pr_heapLock;
- pthread_key_t current_thread_key;
- pthread_key_t current_cpu_key;
- pthread_key_t last_thread_key;
- pthread_key_t intsoff_key;
-
-
- PRInt32 _pr_md_pthreads_created, _pr_md_pthreads_failed;
- PRInt32 _pr_md_pthreads = 1;
-
- void _MD_EarlyInit(void)
- {
- extern PRInt32 _nspr_noclock;
-
- #ifdef HPUX
- _MD_hpux_install_sigfpe_handler();
- #endif
-
- if (pthread_key_create(¤t_thread_key, NULL) != 0) {
- perror("pthread_key_create failed");
- exit(1);
- }
- if (pthread_key_create(¤t_cpu_key, NULL) != 0) {
- perror("pthread_key_create failed");
- exit(1);
- }
- if (pthread_key_create(&last_thread_key, NULL) != 0) {
- perror("pthread_key_create failed");
- exit(1);
- }
- if (pthread_key_create(&intsoff_key, NULL) != 0) {
- perror("pthread_key_create failed");
- exit(1);
- }
-
- sigemptyset(&ints_off);
- sigaddset(&ints_off, SIGALRM);
- sigaddset(&ints_off, SIGIO);
- sigaddset(&ints_off, SIGCLD);
-
- /*
- * disable clock interrupts
- */
- _nspr_noclock = 1;
-
- }
-
- void _MD_InitLocks()
- {
- if (pthread_mutex_init(&_pr_heapLock, NULL) != 0) {
- perror("pthread_mutex_init failed");
- exit(1);
- }
- }
-
- PR_IMPLEMENT(void) _MD_FREE_LOCK(struct _MDLock *lockp)
- {
- PRIntn _is;
- PRThread *me = _PR_MD_CURRENT_THREAD();
-
- if (me && !_PR_IS_NATIVE_THREAD(me))
- _PR_INTSOFF(_is);
- pthread_mutex_destroy(&lockp->mutex);
- if (me && !_PR_IS_NATIVE_THREAD(me))
- _PR_FAST_INTSON(_is);
- }
-
-
-
- PR_IMPLEMENT(PRStatus) _MD_NEW_LOCK(struct _MDLock *lockp)
- {
- PRStatus rv;
- PRIntn is;
- PRThread *me = _PR_MD_CURRENT_THREAD();
-
- if (me && !_PR_IS_NATIVE_THREAD(me))
- _PR_INTSOFF(is);
- rv = pthread_mutex_init(&lockp->mutex, NULL);
- if (me && !_PR_IS_NATIVE_THREAD(me))
- _PR_FAST_INTSON(is);
- return (rv == 0) ? PR_SUCCESS : PR_FAILURE;
- }
-
-
- PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np)
- {
- if (isCurrent) {
- (void) setjmp(CONTEXT(t));
- }
- *np = sizeof(CONTEXT(t)) / sizeof(PRWord);
- return (PRWord *) CONTEXT(t);
- }
-
- PR_IMPLEMENT(void)
- _MD_SetPriority(_MDThread *thread, PRThreadPriority newPri)
- {
- /*
- * XXX - to be implemented
- */
- return;
- }
-
- PR_IMPLEMENT(PRStatus) _MD_InitThread(struct PRThread *thread)
- {
- struct sigaction sigact;
-
- if (thread->flags & _PR_GLOBAL_SCOPE) {
- thread->md.pthread = pthread_self();
- #if 0
- /*
- * set up SIGUSR1 handler; this is used to save state
- * during PR_SuspendAll
- */
- sigact.sa_handler = save_context_and_block;
- sigact.sa_flags = SA_RESTART;
- /*
- * Must mask clock interrupts
- */
- sigact.sa_mask = timer_set;
- sigaction(SIGUSR1, &sigact, 0);
- #endif
- }
-
- return PR_SUCCESS;
- }
-
- PR_IMPLEMENT(void) _MD_ExitThread(struct PRThread *thread)
- {
- if (thread->flags & _PR_GLOBAL_SCOPE) {
- _MD_CLEAN_THREAD(thread);
- _MD_SET_CURRENT_THREAD(NULL);
- }
- }
-
- PR_IMPLEMENT(void) _MD_CleanThread(struct PRThread *thread)
- {
- if (thread->flags & _PR_GLOBAL_SCOPE) {
- pthread_mutex_destroy(&thread->md.pthread_mutex);
- pthread_cond_destroy(&thread->md.pthread_cond);
- }
- }
-
- PR_IMPLEMENT(void) _MD_SuspendThread(struct PRThread *thread)
- {
- PRInt32 rv;
-
- PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) &&
- (thread->flags & _PR_GCABLE_THREAD));
- #if 0
- thread->md.suspending_id = getpid();
- rv = kill(thread->md.id, SIGUSR1);
- PR_ASSERT(rv == 0);
- /*
- * now, block the current thread/cpu until woken up by the suspended
- * thread from it's SIGUSR1 signal handler
- */
- blockproc(getpid());
- #endif
- }
-
- PR_IMPLEMENT(void) _MD_ResumeThread(struct PRThread *thread)
- {
- PRInt32 rv;
-
- PR_ASSERT((thread->flags & _PR_GLOBAL_SCOPE) &&
- (thread->flags & _PR_GCABLE_THREAD));
- #if 0
- rv = unblockproc(thread->md.id);
- #endif
- }
-
- PR_IMPLEMENT(void) _MD_SuspendCPU(struct _PRCPU *thread)
- {
- PRInt32 rv;
-
- #if 0
- cpu->md.suspending_id = getpid();
- rv = kill(cpu->md.id, SIGUSR1);
- PR_ASSERT(rv == 0);
- /*
- * now, block the current thread/cpu until woken up by the suspended
- * thread from it's SIGUSR1 signal handler
- */
- blockproc(getpid());
- #endif
- }
-
- PR_IMPLEMENT(void) _MD_ResumeCPU(struct _PRCPU *thread)
- {
- #if 0
- unblockproc(cpu->md.id);
- #endif
- }
-
-
- #define PT_NANOPERMICRO 1000UL
- #define PT_BILLION 1000000000UL
-
- PR_IMPLEMENT(PRStatus)
- _pt_wait(PRThread *thread, PRIntervalTime timeout)
- {
- int rv;
- struct timeval now;
- struct timespec tmo;
- PRUint32 ticks = PR_TicksPerSecond();
-
-
- if (timeout != PR_INTERVAL_NO_TIMEOUT) {
- tmo.tv_sec = timeout / ticks;
- tmo.tv_nsec = timeout - (tmo.tv_sec * ticks);
- tmo.tv_nsec = PR_IntervalToMicroseconds(PT_NANOPERMICRO *
- tmo.tv_nsec);
-
- /* pthreads wants this in absolute time, off we go ... */
- #if defined(SOLARIS) && defined(_SVID_GETTOD)
- (void)gettimeofday(&now);
- #else
- (void)gettimeofday(&now, NULL);
- #endif
- /* that one's usecs, this one's nsecs - grrrr! */
- tmo.tv_sec += now.tv_sec;
- tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec);
- tmo.tv_sec += tmo.tv_nsec / PT_BILLION;
- tmo.tv_nsec %= PT_BILLION;
- }
-
- pthread_mutex_lock(&thread->md.pthread_mutex);
- thread->md.wait--;
- if (thread->md.wait < 0) {
- if (timeout != PR_INTERVAL_NO_TIMEOUT) {
- rv = pthread_cond_timedwait(&thread->md.pthread_cond,
- &thread->md.pthread_mutex, &tmo);
- }
- else
- rv = pthread_cond_wait(&thread->md.pthread_cond,
- &thread->md.pthread_mutex);
- if (rv != 0) {
- thread->md.wait++;
- }
- } else
- rv = 0;
- pthread_mutex_unlock(&thread->md.pthread_mutex);
-
- return (rv == 0) ? PR_SUCCESS : PR_FAILURE;
- }
-
- PR_IMPLEMENT(PRStatus)
- _MD_wait(PRThread *thread, PRIntervalTime ticks)
- {
- if ( thread->flags & _PR_GLOBAL_SCOPE ) {
- _MD_CHECK_FOR_EXIT();
- if (_pt_wait(thread, ticks) == PR_FAILURE) {
- _MD_CHECK_FOR_EXIT();
- /*
- * wait timed out
- */
- _PR_THREAD_LOCK(thread);
- if (thread->wait.cvar) {
- /*
- * The thread will remove itself from the waitQ
- * of the cvar in _PR_WaitCondVar
- */
- thread->wait.cvar = NULL;
- thread->state = _PR_RUNNING;
- _PR_THREAD_UNLOCK(thread);
- } else {
- _pt_wait(thread, PR_INTERVAL_NO_TIMEOUT);
- _PR_THREAD_UNLOCK(thread);
- }
- }
- } else {
- _PR_MD_SWITCH_CONTEXT(thread);
- }
- return PR_SUCCESS;
- }
-
- PR_IMPLEMENT(PRStatus)
- _MD_WakeupWaiter(PRThread *thread)
- {
- PRThread *me = _PR_MD_CURRENT_THREAD();
- PRInt32 pid, rv;
- PRIntn is;
-
- PR_ASSERT(_pr_md_idle_cpus >= 0);
- if (thread == NULL) {
- if (_pr_md_idle_cpus)
- _MD_Wakeup_CPUs();
- } else if (!_PR_IS_NATIVE_THREAD(thread)) {
- /*
- * If the thread is on my cpu's runq there is no need to
- * wakeup any cpus
- */
- if (!_PR_IS_NATIVE_THREAD(me)) {
- if (me->cpu != thread->cpu) {
- if (_pr_md_idle_cpus)
- _MD_Wakeup_CPUs();
- }
- } else {
- if (_pr_md_idle_cpus)
- _MD_Wakeup_CPUs();
- }
- } else {
- PR_ASSERT(_PR_IS_NATIVE_THREAD(thread));
- if (!_PR_IS_NATIVE_THREAD(me))
- _PR_INTSOFF(is);
-
- pthread_mutex_lock(&thread->md.pthread_mutex);
- thread->md.wait++;
- rv = pthread_cond_signal(&thread->md.pthread_cond);
- PR_ASSERT(rv == 0);
- pthread_mutex_unlock(&thread->md.pthread_mutex);
-
- if (!_PR_IS_NATIVE_THREAD(me))
- _PR_FAST_INTSON(is);
- }
- return PR_SUCCESS;
- }
-
- /* These functions should not be called for AIX */
- PR_IMPLEMENT(void)
- _MD_YIELD(void)
- {
- PR_NOT_REACHED("_MD_YIELD should not be called for AIX.");
- }
-
- PR_IMPLEMENT(PRStatus)
- _MD_CreateThread(
- PRThread *thread,
- void (*start) (void *),
- PRThreadPriority priority,
- PRThreadScope scope,
- PRThreadState state,
- PRUint32 stackSize)
- {
- PRIntn is;
- PRThread *me = _PR_MD_CURRENT_THREAD();
- pthread_attr_t attr;
-
- if (!_PR_IS_NATIVE_THREAD(me))
- _PR_INTSOFF(is);
-
- if (pthread_mutex_init(&thread->md.pthread_mutex, NULL) != 0) {
- if (!_PR_IS_NATIVE_THREAD(me))
- _PR_FAST_INTSON(is);
- return PR_FAILURE;
- }
-
- if (pthread_cond_init(&thread->md.pthread_cond, NULL) != 0) {
- pthread_mutex_destroy(&thread->md.pthread_mutex);
- if (!_PR_IS_NATIVE_THREAD(me))
- _PR_FAST_INTSON(is);
- return PR_FAILURE;
- }
- thread->flags |= _PR_GLOBAL_SCOPE;
-
- pthread_attr_init(&attr); /* initialize attr with default attributes */
- if (pthread_attr_setstacksize(&attr, (size_t) stackSize) != 0) {
- pthread_mutex_destroy(&thread->md.pthread_mutex);
- pthread_cond_destroy(&thread->md.pthread_cond);
- pthread_attr_destroy(&attr);
- if (!_PR_IS_NATIVE_THREAD(me))
- _PR_FAST_INTSON(is);
- return PR_FAILURE;
- }
-
- thread->md.wait = 0;
- if (pthread_create(&thread->md.pthread, &attr, start, (void *)thread)
- == 0) {
- _MD_ATOMIC_INCREMENT(&_pr_md_pthreads_created);
- _MD_ATOMIC_INCREMENT(&_pr_md_pthreads);
- if (!_PR_IS_NATIVE_THREAD(me))
- _PR_FAST_INTSON(is);
- return PR_SUCCESS;
- } else {
- pthread_mutex_destroy(&thread->md.pthread_mutex);
- pthread_cond_destroy(&thread->md.pthread_cond);
- pthread_attr_destroy(&attr);
- _MD_ATOMIC_INCREMENT(&_pr_md_pthreads_failed);
- if (!_PR_IS_NATIVE_THREAD(me))
- _PR_FAST_INTSON(is);
- return PR_FAILURE;
- }
- }
-
- PR_IMPLEMENT(void)
- _MD_InitRunningCPU(struct _PRCPU *cpu)
- {
- extern int _pr_md_pipefd[2];
-
- _MD_unix_init_running_cpu(cpu);
- cpu->md.pthread = pthread_self();
- if (_pr_md_pipefd[0] >= 0) {
- _PR_IOQ_MAX_OSFD(cpu) = _pr_md_pipefd[0];
- FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(cpu));
- }
- }
-
-
- void
- _MD_CleanupBeforeExit(void)
- {
- #if 0
- extern PRInt32 _pr_cpus_exit;
-
- _pr_irix_exit_now = 1;
- if (_pr_numCPU > 1) {
- /*
- * Set a global flag, and wakeup all cpus which will notice the flag
- * and exit.
- */
- _pr_cpus_exit = getpid();
- _MD_Wakeup_CPUs();
- while(_pr_numCPU > 1) {
- _PR_WAIT_SEM(_pr_irix_exit_sem);
- _pr_numCPU--;
- }
- }
- /*
- * cause global threads on the recycle list to exit
- */
- _PR_DEADQ_LOCK;
- if (_PR_NUM_DEADNATIVE != 0) {
- PRThread *thread;
- PRCList *ptr;
-
- ptr = _PR_DEADNATIVEQ.next;
- while( ptr != &_PR_DEADNATIVEQ ) {
- thread = _PR_THREAD_PTR(ptr);
- _MD_CVAR_POST_SEM(thread);
- ptr = ptr->next;
- }
- }
- _PR_DEADQ_UNLOCK;
- while(_PR_NUM_DEADNATIVE > 1) {
- _PR_WAIT_SEM(_pr_irix_exit_sem);
- _PR_DEC_DEADNATIVE;
- }
- #endif
- }
-