📄 macthr.c
字号:
// be able to get the asyncIOLock without blocking (thus avoiding code // that makes assumptions about the current NSPR thread etc). To achieve // this, we use NSPR interrrupts as a semaphore on the lock; all code // that grabs the lock also disables interrupts for the time the lock // is held. Callers of DoneWaitingOnThisThread() thus have to check whether // interrupts are already off, and, if so, simply set the missed_IO flag on // the CPU rather than calling this function. _PR_INTSOFF(is); PR_Lock(thread->md.asyncIOLock); thread->io_pending = PR_FALSE; /* let the waiting thread know that async IO completed */ PR_NotifyCondVar(thread->md.asyncIOCVar); PR_Unlock(thread->md.asyncIOLock); _PR_FAST_INTSON(is);}PR_IMPLEMENT(void) PR_Mac_WaitForAsyncNotify(PRIntervalTime timeout){ intn is; PRIntervalTime timein = PR_IntervalNow(); PRStatus status = PR_SUCCESS; PRThread *thread = _PR_MD_CURRENT_THREAD(); // See commments in WaitOnThisThread() _PR_INTSOFF(is); PR_Lock(thread->md.asyncIOLock); if (timeout == PR_INTERVAL_NO_TIMEOUT) { while ((!thread->md.asyncNotifyPending) && (status == PR_SUCCESS)) status = PR_WaitCondVar(thread->md.asyncIOCVar, PR_INTERVAL_NO_TIMEOUT); } else { while ((!thread->md.asyncNotifyPending) && ((PRIntervalTime)(PR_IntervalNow() - timein) < timeout) && (status == PR_SUCCESS)) status = PR_WaitCondVar(thread->md.asyncIOCVar, timeout); } if ((status == PR_FAILURE) && (PR_GetError() == PR_PENDING_INTERRUPT_ERROR)) { thread->md.osErrCode = kEINTRErr; } else if (!thread->md.asyncNotifyPending) { thread->md.osErrCode = kETIMEDOUTErr; PR_SetError(PR_IO_TIMEOUT_ERROR, kETIMEDOUTErr); } thread->md.asyncNotifyPending = PR_FALSE; PR_Unlock(thread->md.asyncIOLock); _PR_FAST_INTSON(is);}void AsyncNotify(PRThread *thread){ intn is; PR_ASSERT(thread->md.asyncIOLock->owner == NULL); // See commments in DoneWaitingOnThisThread() _PR_INTSOFF(is); PR_Lock(thread->md.asyncIOLock); thread->md.asyncNotifyPending = PR_TRUE; /* let the waiting thread know that async IO completed */ PR_NotifyCondVar(thread->md.asyncIOCVar); PR_Unlock(thread->md.asyncIOLock); _PR_FAST_INTSON(is);}PR_IMPLEMENT(void) PR_Mac_PostAsyncNotify(PRThread *thread){ _PRCPU * cpu = _PR_MD_CURRENT_CPU(); if (_PR_MD_GET_INTSOFF()) { thread->md.missedAsyncNotify = PR_TRUE; cpu->u.missed[cpu->where] |= _PR_MISSED_IO; } else { AsyncNotify(thread); }}//##############################################################################//###############################################################################pragma mark -#pragma mark PROCESS SUPPORT FUNCTIONSPRProcess * _MD_CreateProcess( const char *path, char *const *argv, char *const *envp, const PRProcessAttr *attr){#pragma unused (path, argv, envp, attr) PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr); return NULL;}PRStatus _MD_DetachProcess(PRProcess *process){#pragma unused (process) PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr); return PR_FAILURE;}PRStatus _MD_WaitProcess(PRProcess *process, PRInt32 *exitCode){#pragma unused (process, exitCode) PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr); return PR_FAILURE;}PRStatus _MD_KillProcess(PRProcess *process){#pragma unused (process) PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr); return PR_FAILURE;}//##############################################################################//###############################################################################pragma mark -#pragma mark ATOMIC OPERATIONS#ifdef _PR_HAVE_ATOMIC_OPSPRInt32_MD_AtomicSet(PRInt32 *val, PRInt32 newval){ PRInt32 rv; do { rv = *val; } while (!OTCompareAndSwap32(rv, newval, (UInt32*)val)); return rv;}#endif // _PR_HAVE_ATOMIC_OPS//##############################################################################//###############################################################################pragma mark -#pragma mark INTERRUPT SUPPORT#if TARGET_CARBON/* This critical region support is required for Mac NSPR to work correctly on dual CPU machines on Mac OS X. This note explains why. NSPR uses a timer task, and has callbacks for async file I/O and Open Transport whose runtime behaviour differs depending on environment. On "Classic" Mac OS these run at "interrupt" time (OS-level interrupts, that is, not NSPR interrupts), and can thus preempt other code, but they always run to completion. On Mac OS X, these are all emulated using MP tasks, which sit atop pthreads. Thus, they can be preempted at any time (and not necessarily run to completion), and can also run *concurrently* with eachother, and with application code, on multiple CPU machines. Note that all NSPR threads are emulated, and all run on the main application MP task. We thus have to use MP critical sections to protect data that is shared between the various callbacks and the main MP thread. It so happens that NSPR has this concept of software interrupts, and making interrupt-off times be critical sections works.*//* Whether to use critical regions. True if running on Mac OS X and later*/PRBool gUseCriticalRegions;/* Count of the number of times we've entered the critical region. We need this because ENTER_CRITICAL_REGION() will *not* block when called from different NSPR threads (which all run on one MP thread), and we need to ensure that when code turns interrupts back on (by settings _pr_intsOff to 0) we exit the critical section enough times to leave it.*/PRInt32 gCriticalRegionEntryCount;void _MD_SetIntsOff(PRInt32 ints){ ENTER_CRITICAL_REGION(); gCriticalRegionEntryCount ++; _pr_intsOff = ints; if (!ints) { PRInt32 i = gCriticalRegionEntryCount; gCriticalRegionEntryCount = 0; for ( ;i > 0; i --) { LEAVE_CRITICAL_REGION(); } }}#endif /* TARGET_CARBON *///##############################################################################//###############################################################################pragma mark -#pragma mark CRITICAL REGION SUPPORTstatic PRBool RunningOnOSX(){ long systemVersion; OSErr err = Gestalt(gestaltSystemVersion, &systemVersion); return (err == noErr) && (systemVersion >= 0x00001000);}#if MAC_CRITICAL_REGIONSMDCriticalRegionID gCriticalRegion;void InitCriticalRegion(){ OSStatus err; // we only need to do critical region stuff on Mac OS X gUseCriticalRegions = RunningOnOSX(); if (!gUseCriticalRegions) return; err = MD_CriticalRegionCreate(&gCriticalRegion); PR_ASSERT(err == noErr);}void TermCriticalRegion(){ OSStatus err; if (!gUseCriticalRegions) return; err = MD_CriticalRegionDelete(gCriticalRegion); PR_ASSERT(err == noErr);}void EnterCritialRegion(){ OSStatus err; if (!gUseCriticalRegions) return; PR_ASSERT(gCriticalRegion != kInvalidID); /* Change to a non-infinite timeout for debugging purposes */ err = MD_CriticalRegionEnter(gCriticalRegion, kDurationForever /* 10000 * kDurationMillisecond */ ); PR_ASSERT(err == noErr);}void LeaveCritialRegion(){ OSStatus err; if (!gUseCriticalRegions) return; PR_ASSERT(gCriticalRegion != kInvalidID); err = MD_CriticalRegionExit(gCriticalRegion); PR_ASSERT(err == noErr);}#endif // MAC_CRITICAL_REGIONS//##############################################################################//###############################################################################pragma mark -#pragma mark IDLE SEMAPHORE SUPPORT/* Since the WaitNextEvent() in _MD_PauseCPU() is causing all sorts of headache under Mac OS X we're going to switch to MPWaitOnSemaphore() which should do what we want*/#if TARGET_CARBONPRBool gUseIdleSemaphore = PR_FALSE;MPSemaphoreID gIdleSemaphore = NULL;#endifvoid InitIdleSemaphore(){ // we only need to do idle semaphore stuff on Mac OS X#if TARGET_CARBON gUseIdleSemaphore = RunningOnOSX(); if (gUseIdleSemaphore) { OSStatus err = MPCreateSemaphore(1 /* max value */, 0 /* initial value */, &gIdleSemaphore); PR_ASSERT(err == noErr); }#endif}void TermIdleSemaphore(){#if TARGET_CARBON if (gUseIdleSemaphore) { OSStatus err = MPDeleteSemaphore(gIdleSemaphore); PR_ASSERT(err == noErr); gUseIdleSemaphore = NULL; }#endif}void WaitOnIdleSemaphore(PRIntervalTime timeout){#if TARGET_CARBON if (gUseIdleSemaphore) { OSStatus err = MPWaitOnSemaphore(gIdleSemaphore, kDurationMillisecond * PR_IntervalToMilliseconds(timeout)); PR_ASSERT(err == noErr); } else#endif { EventRecord theEvent; /* ** Calling WaitNextEvent() here is suboptimal. This routine should ** pause the process until IO or the timeout occur, yielding time to ** other processes on operating systems that require this (Mac OS classic). ** WaitNextEvent() may incur too much latency, and has other problems, ** such as the potential to drop suspend/resume events. */ (void)WaitNextEvent(nullEvent, &theEvent, 1, NULL); }}void SignalIdleSemaphore(){#if TARGET_CARBON if (gUseIdleSemaphore) { // often we won't be waiting on the semaphore here, so ignore any errors (void)MPSignalSemaphore(gIdleSemaphore); } else#endif { WakeUpProcess(&gApplicationProcess); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -