📄 pthreads_user.c
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape Portable Runtime (NSPR). * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */#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; 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) && _PR_IS_GCABLE_THREAD(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) && _PR_IS_GCABLE_THREAD(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 1000000000ULPR_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 ... */ (void)GETTIMEOFDAY(&now); /* 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; int rv; 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; rv = pthread_create(&thread->md.pthread, &attr, start, (void *)thread); if (0 == rv) { _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); PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, rv); 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];#ifndef _PR_USE_POLL FD_SET(_pr_md_pipefd[0], &_PR_FD_READ_SET(cpu));#endif }}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}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -