Back to index

lightning-sunbird  0.9+nobinonly
Defines | Functions | Variables
macthr.c File Reference
#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"
#include <OpenTransport.h>

Go to the source code of this file.

Defines

#define kMacTimerInMiliSecs   8L
#define MAX_PAUSE_TIMEOUT_MS   500

Functions

 PR_IMPLEMENT (PRThread *)
PRStatus _MD_AllocSegment (PRSegment *seg, PRUint32 size, void *vaddr)
void _MD_FreeSegment (PRSegment *seg)
void _MD_InitStack (PRThreadStack *ts, int redZoneBytes)
void _MD_ClearStack (PRThreadStack *ts)
void _MD_IOInterrupt (void)
pascal void TimerCallback (TMTaskPtr tmTaskPtr)
void _MD_StartInterrupts (void)
void _MD_StopInterrupts (void)
void _MD_PauseCPU (PRIntervalTime timeout)
void _MD_InitRunningCPU (_PRCPU *cpu)
PRStatus _MD_InitThread (PRThread *thread)
PRStatus _MD_wait (PRThread *thread, PRIntervalTime timeout)
void WaitOnThisThread (PRThread *thread, PRIntervalTime timeout)
void DoneWaitingOnThisThread (PRThread *thread)
 PR_IMPLEMENT (void)
void AsyncNotify (PRThread *thread)
PRProcess_MD_CreateProcess (const char *path, char *const *argv, char *const *envp, const PRProcessAttr *attr)
PRStatus _MD_DetachProcess (PRProcess *process)
PRStatus _MD_WaitProcess (PRProcess *process, PRInt32 *exitCode)
PRStatus _MD_KillProcess (PRProcess *process)
static PRBool RunningOnOSX ()
void InitIdleSemaphore ()
void TermIdleSemaphore ()
void WaitOnIdleSemaphore (PRIntervalTime timeout)
void SignalIdleSemaphore ()

Variables

TimerUPP gTimerCallbackUPP = NULL
PRThreadgPrimaryThread = NULL
ProcessSerialNumber gApplicationProcess
static Boolean gTimeManagerTaskDoesWUP
static TMTask gTimeManagerTaskElem
_PRInterruptTable _pr_interruptTable []

Define Documentation

Definition at line 190 of file macthr.c.

Definition at line 261 of file macthr.c.


Function Documentation

PRStatus _MD_AllocSegment ( PRSegment seg,
PRUint32  size,
void vaddr 
)

Definition at line 78 of file macthr.c.

{
       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;
}

Here is the call graph for this function:

Definition at line 146 of file macthr.c.

       {
#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
       }

Here is the call graph for this function:

PRProcess* _MD_CreateProcess ( const char *  path,
char *const argv,
char *const envp,
const PRProcessAttr attr 
) [read]

Definition at line 446 of file macthr.c.

{
#pragma unused (path, argv, envp, attr)

       PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr);
       return NULL;
}

Definition at line 458 of file macthr.c.

{
#pragma unused (process)

       PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr);
       return PR_FAILURE;
}

Definition at line 112 of file macthr.c.

{
       PR_ASSERT((seg->flags & _PR_SEG_VM) == 0);

       if (seg->vaddr != NULL)
              free(seg->vaddr);
}

Definition at line 280 of file macthr.c.

{
    cpu->md.trackScheduling = RunningOnOSX();
    if (cpu->md.trackScheduling) {
        AbsoluteTime    zeroTime = {0, 0};
        cpu->md.lastThreadSwitch = UpTime();
        cpu->md.lastWakeUpProcess = zeroTime;
    }
}

Here is the call graph for this function:

void _MD_InitStack ( PRThreadStack ts,
int  redZoneBytes 
)

Definition at line 128 of file macthr.c.

       {
#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 
       }

Here is the call graph for this function:

Definition at line 298 of file macthr.c.

{
       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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 183 of file macio.c.

{
    PRCList *qp;
    PRThread *thread, *me = _PR_MD_CURRENT_THREAD();

    PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);

    _PR_SLEEPQ_LOCK(me->cpu);
    qp = _PR_PAUSEQ(me->cpu).next;
    while (qp != &_PR_PAUSEQ(me->cpu)) {

              thread = _PR_THREAD_PTR(qp);
              PR_ASSERT(thread->flags & _PR_ON_PAUSEQ);

              qp = qp->next;
              
              if (thread->md.missedIONotify) {
                     thread->md.missedIONotify = PR_FALSE;
                     DoneWaitingOnThisThread(thread);
              }

              if (thread->md.missedAsyncNotify) {
                     thread->md.missedAsyncNotify = PR_FALSE;
                     AsyncNotify(thread);
              }
    }
    qp = _PR_SLEEPQ(me->cpu).next;
    while (qp != &_PR_SLEEPQ(me->cpu)) {

              thread = _PR_THREAD_PTR(qp);
              PR_ASSERT(thread->flags & _PR_ON_SLEEPQ);

              qp = qp->next;
              
              if (thread->md.missedIONotify) {
                     thread->md.missedIONotify = PR_FALSE;
                     DoneWaitingOnThisThread(thread);
              }

              if (thread->md.missedAsyncNotify) {
                     thread->md.missedAsyncNotify = PR_FALSE;
                     AsyncNotify(thread);
              }
    }
       _PR_SLEEPQ_UNLOCK(thread->cpu);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 474 of file macthr.c.

{
#pragma unused (process)

       PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr);
       return PR_FAILURE;
}

Definition at line 263 of file macthr.c.

{
    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();
    }
}

Here is the call graph for this function:

Definition at line 230 of file macthr.c.

{
       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);
}

Here is the call graph for this function:

Definition at line 252 of file macthr.c.

{
       if (gTimeManagerTaskElem.tmAddr != NULL) {
              RmvTime((QElemPtr)&gTimeManagerTaskElem);
              gTimeManagerTaskElem.tmAddr = NULL;
       }
}
PRStatus _MD_wait ( PRThread thread,
PRIntervalTime  timeout 
)

Definition at line 311 of file macthr.c.

{
#pragma unused (timeout)

       _MD_SWITCH_CONTEXT(thread);
       return PR_SUCCESS;
}
PRStatus _MD_WaitProcess ( PRProcess process,
PRInt32 exitCode 
)

Definition at line 466 of file macthr.c.

{
#pragma unused (process, exitCode)

       PR_SetError(PR_NOT_IMPLEMENTED_ERROR, unimpErr);
       return PR_FAILURE;
}
void AsyncNotify ( PRThread thread)

Definition at line 411 of file macthr.c.

{
    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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 353 of file macthr.c.

{
    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
       // 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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 656 of file macthr.c.

{
    // 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
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 57 of file macthr.c.

{
       return gPrimaryThread;
}

Definition at line 382 of file macthr.c.

{
    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);
}

Here is the call graph for this function:

static PRBool RunningOnOSX ( ) [static]

Definition at line 577 of file macthr.c.

{
    long    systemVersion;
    OSErr   err = Gestalt(gestaltSystemVersion, &systemVersion);
    return (err == noErr) && (systemVersion >= 0x00001000);
}

Here is the caller graph for this function:

Definition at line 706 of file macthr.c.

{
#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);
       }
}

Here is the caller graph for this function:

Definition at line 669 of file macthr.c.

{
#if TARGET_CARBON
       if (gUseIdleSemaphore)
       {
              OSStatus  err = MPDeleteSemaphore(gIdleSemaphore);
              PR_ASSERT(err == noErr);
              gUseIdleSemaphore = NULL;
       }
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

pascal void TimerCallback ( TMTaskPtr  tmTaskPtr)

Definition at line 192 of file macthr.c.

{
    _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);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 682 of file macthr.c.

{
#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);
       }
}

Here is the call graph for this function:

void WaitOnThisThread ( PRThread thread,
PRIntervalTime  timeout 
)

Definition at line 320 of file macthr.c.

{
    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);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Initial value:
 {
    { "clock", _PR_MISSED_CLOCK, _PR_ClockInterrupt, },
    { "i/o", _PR_MISSED_IO, _MD_IOInterrupt, },
    { 0 }
}

Definition at line 184 of file macthr.c.

ProcessSerialNumber gApplicationProcess

Definition at line 55 of file macthr.c.

Definition at line 53 of file macthr.c.

Definition at line 179 of file macthr.c.

TMTask gTimeManagerTaskElem [static]

Definition at line 181 of file macthr.c.

TimerUPP gTimerCallbackUPP = NULL

Definition at line 52 of file macthr.c.