📄 macthr.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 <string.h>#include <MacTypes.h>#include <Timer.h>#include <OSUtils.h>#include <Math64.h>#include <LowMem.h>#include <Multiprocessing.h>#include <Gestalt.h>#include "mdcriticalregion.h"TimerUPP gTimerCallbackUPP = NULL;PRThread * gPrimaryThread = NULL;ProcessSerialNumber gApplicationProcess;PR_IMPLEMENT(PRThread *) PR_GetPrimaryThread(){ return gPrimaryThread;}//##############################################################################//###############################################################################pragma mark -#pragma mark CREATING MACINTOSH THREAD STACKS#if defined(GC_LEAK_DETECTOR)extern void* GC_malloc_atomic(PRUint32 size);#endif/*** Allocate a new memory segment. We allocate it from our figment heap. Currently,** it is being used for per thread stack space.** ** Return the segment's access rights and size. vaddr is used on Unix platforms to** map an existing address for the segment.*/PRStatus _MD_AllocSegment(PRSegment *seg, PRUint32 size, void *vaddr){ PR_ASSERT(seg != 0); PR_ASSERT(size != 0); PR_ASSERT(vaddr == 0); /* ** Take the actual memory for the segment out of our Figment heap. */#if defined(GC_LEAK_DETECTOR) seg->vaddr = (char *)GC_malloc_atomic(size);#else seg->vaddr = (char *)malloc(size);#endif if (seg->vaddr == NULL) {#if DEBUG DebugStr("\p_MD_AllocSegment failed.");#endif return PR_FAILURE; } seg->size = size; return PR_SUCCESS;}/*** Free previously allocated memory segment.*/void _MD_FreeSegment(PRSegment *seg){ PR_ASSERT((seg->flags & _PR_SEG_VM) == 0); if (seg->vaddr != NULL) free(seg->vaddr);}/*** The thread's stack has been allocated and its fields are already properly filled** in by PR. Perform any debugging related initialization here.**** Put a recognizable pattern so that we can find it from Macsbug.** Put a cookie at the top of the stack so that we can find it from Macsbug.*/void _MD_InitStack(PRThreadStack *ts, int redZoneBytes) {#pragma unused (redZoneBytes)#if DEVELOPER_DEBUG // Put a cookie at the top of the stack so that we can find // it from Macsbug. memset(ts->allocBase, 0xDC, ts->stackSize); ((UInt32 *)ts->stackTop)[-1] = 0xBEEFCAFE; ((UInt32 *)ts->stackTop)[-2] = (UInt32)gPrimaryThread; ((UInt32 *)ts->stackTop)[-3] = (UInt32)(ts); ((UInt32 *)ts->stackBottom)[0] = 0xCAFEBEEF;#else#pragma unused (ts)#endif }extern void _MD_ClearStack(PRThreadStack *ts) {#if DEVELOPER_DEBUG // Clear out our cookies. memset(ts->allocBase, 0xEF, ts->allocSize); ((UInt32 *)ts->stackTop)[-1] = 0; ((UInt32 *)ts->stackTop)[-2] = 0; ((UInt32 *)ts->stackTop)[-3] = 0; ((UInt32 *)ts->stackBottom)[0] = 0;#else#pragma unused (ts)#endif }//##############################################################################//###############################################################################pragma mark -#pragma mark TIME MANAGER-BASED CLOCK// On Mac OS X, it's possible for the application to spend lots of time// in WaitNextEvent, yielding to other applications. Since NSPR threads are// cooperative here, this means that NSPR threads will also get very little// time to run. To kick ourselves out of a WaitNextEvent call when we have// determined that it's time to schedule another thread, the Timer Task// (which fires every 8ms, even when other apps have the CPU) calls WakeUpProcess.// We only want to do this on Mac OS X; the gTimeManagerTaskDoesWUP variable// indicates when we're running on that OS.//// Note that the TimerCallback makes use of gApplicationProcess. We need to// have set this up before the first possible run of the timer task; we do// so in _MD_EarlyInit().static Boolean gTimeManagerTaskDoesWUP;static TMTask gTimeManagerTaskElem;extern void _MD_IOInterrupt(void);_PRInterruptTable _pr_interruptTable[] = { { "clock", _PR_MISSED_CLOCK, _PR_ClockInterrupt, }, { "i/o", _PR_MISSED_IO, _MD_IOInterrupt, }, { 0 }};#define kMacTimerInMiliSecs 8Lpascal void TimerCallback(TMTaskPtr tmTaskPtr){ _PRCPU *cpu = _PR_MD_CURRENT_CPU(); PRIntn is; if (_PR_MD_GET_INTSOFF()) { cpu->u.missed[cpu->where] |= _PR_MISSED_CLOCK; PrimeTime((QElemPtr)tmTaskPtr, kMacTimerInMiliSecs); return; } _PR_INTSOFF(is); // And tell nspr that a clock interrupt occured. _PR_ClockInterrupt(); if ((_PR_RUNQREADYMASK(cpu)) >> ((_PR_MD_CURRENT_THREAD()->priority))) { if (gTimeManagerTaskDoesWUP) { // We only want to call WakeUpProcess if we know that NSPR has managed to switch threads // since the last call, otherwise we end up spewing out WakeUpProcess() calls while the // application is blocking somewhere. This can interfere with events loops other than // our own (see bug 158927). if (UnsignedWideToUInt64(cpu->md.lastThreadSwitch) > UnsignedWideToUInt64(cpu->md.lastWakeUpProcess)) { WakeUpProcess(&gApplicationProcess); cpu->md.lastWakeUpProcess = UpTime(); } } _PR_SET_RESCHED_FLAG(); } _PR_FAST_INTSON(is); // Reset the clock timer so that we fire again. PrimeTime((QElemPtr)tmTaskPtr, kMacTimerInMiliSecs);}void _MD_StartInterrupts(void){ gPrimaryThread = _PR_MD_CURRENT_THREAD(); gTimeManagerTaskDoesWUP = RunningOnOSX(); if ( !gTimerCallbackUPP ) gTimerCallbackUPP = NewTimerUPP(TimerCallback); // Fill in the Time Manager queue element gTimeManagerTaskElem.tmAddr = (TimerUPP)gTimerCallbackUPP; gTimeManagerTaskElem.tmCount = 0; gTimeManagerTaskElem.tmWakeUp = 0; gTimeManagerTaskElem.tmReserved = 0; // Make sure that our time manager task is ready to go. InsTime((QElemPtr)&gTimeManagerTaskElem); PrimeTime((QElemPtr)&gTimeManagerTaskElem, kMacTimerInMiliSecs);}void _MD_StopInterrupts(void){ if (gTimeManagerTaskElem.tmAddr != NULL) { RmvTime((QElemPtr)&gTimeManagerTaskElem); gTimeManagerTaskElem.tmAddr = NULL; }}#define MAX_PAUSE_TIMEOUT_MS 500void _MD_PauseCPU(PRIntervalTime timeout){ if (timeout != PR_INTERVAL_NO_WAIT) { // There is a race condition entering the critical section // in AsyncIOCompletion (and probably elsewhere) that can // causes deadlock for the duration of this timeout. To // work around this, use a max 500ms timeout for now. // See bug 99561 for details. if (PR_IntervalToMilliseconds(timeout) > MAX_PAUSE_TIMEOUT_MS) timeout = PR_MillisecondsToInterval(MAX_PAUSE_TIMEOUT_MS); WaitOnIdleSemaphore(timeout); (void) _MD_IOInterrupt(); }}void _MD_InitRunningCPU(_PRCPU* cpu){ cpu->md.trackScheduling = RunningOnOSX(); if (cpu->md.trackScheduling) { AbsoluteTime zeroTime = {0, 0}; cpu->md.lastThreadSwitch = UpTime(); cpu->md.lastWakeUpProcess = zeroTime; }}//##############################################################################//###############################################################################pragma mark -#pragma mark THREAD SUPPORT FUNCTIONS#include <OpenTransport.h> /* for error codes */PRStatus _MD_InitThread(PRThread *thread){ thread->md.asyncIOLock = PR_NewLock(); PR_ASSERT(thread->md.asyncIOLock != NULL); thread->md.asyncIOCVar = PR_NewCondVar(thread->md.asyncIOLock); PR_ASSERT(thread->md.asyncIOCVar != NULL); if (thread->md.asyncIOLock == NULL || thread->md.asyncIOCVar == NULL) return PR_FAILURE; else return PR_SUCCESS;}PRStatus _MD_wait(PRThread *thread, PRIntervalTime timeout){#pragma unused (timeout) _MD_SWITCH_CONTEXT(thread); return PR_SUCCESS;}void WaitOnThisThread(PRThread *thread, PRIntervalTime timeout){ intn is; PRIntervalTime timein = PR_IntervalNow(); PRStatus status = PR_SUCCESS; // Turn interrupts off to avoid a race over lock ownership with the callback // (which can fire at any time). Interrupts may stay off until we leave // this function, or another NSPR thread turns them back on. They certainly // stay off until PR_WaitCondVar() relinquishes the asyncIOLock lock, which // is what we care about. _PR_INTSOFF(is); PR_Lock(thread->md.asyncIOLock); if (timeout == PR_INTERVAL_NO_TIMEOUT) { while ((thread->io_pending) && (status == PR_SUCCESS)) status = PR_WaitCondVar(thread->md.asyncIOCVar, PR_INTERVAL_NO_TIMEOUT); } else { while ((thread->io_pending) && ((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->io_pending) { thread->md.osErrCode = kETIMEDOUTErr; PR_SetError(PR_IO_TIMEOUT_ERROR, kETIMEDOUTErr); } thread->io_pending = PR_FALSE; PR_Unlock(thread->md.asyncIOLock); _PR_FAST_INTSON(is);}void DoneWaitingOnThisThread(PRThread *thread){ intn is; PR_ASSERT(thread->md.asyncIOLock->owner == NULL); // DoneWaitingOnThisThread() is called from OT notifiers and async file I/O // callbacks that can run at "interrupt" time (Classic Mac OS) or on pthreads // that may run concurrently with the main threads (Mac OS X). They can thus // be called when any NSPR thread is running, or even while NSPR is in a // thread context switch. It is therefore vital that we can guarantee to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -