⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 macthr.c

📁 Netscape NSPR库源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* -*- 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 + -