Back to index

lightning-sunbird  0.9+nobinonly
Functions | Variables
prucpu.c File Reference
#include "primpl.h"

Go to the source code of this file.

Functions

static void PR_CALLBACK _PR_CPU_Idle (void *)
static _PRCPU_PR_CreateCPU (void)
static PRStatus _PR_StartCPU (_PRCPU *cpu, PRThread *thread)
static void _PR_RunCPU (void *arg)
void _PR_InitCPUs ()
static _PRCPUQueue_PR_CreateCPUQueue (void)
 PR_IMPLEMENT (void)
 PR_IMPLEMENT (_PRCPU *)

Variables

_PRCPU_pr_primordialCPU = NULL
PRInt32 _pr_md_idle_cpus
static _MDLock _pr_md_idle_cpus_lock
PRUintn _pr_numCPU
PRInt32 _pr_cpus_exit
PRInt32 _pr_cpu_affinity_mask = 0
static PRUintn _pr_cpuID

Function Documentation

static void PR_CALLBACK _PR_CPU_Idle ( void _cpu) [static]

Definition at line 315 of file prucpu.c.

{
    _PRCPU *cpu = (_PRCPU *)_cpu;
    PRThread *me = _PR_MD_CURRENT_THREAD();

    PR_ASSERT(NULL != me);

    me->cpu = cpu;
    cpu->idle_thread = me;
    if (_MD_LAST_THREAD())
        _MD_LAST_THREAD()->no_sched = 0;
    if (!_PR_IS_NATIVE_THREAD(me)) _PR_MD_SET_INTSOFF(0);
    while(1) {
        PRInt32 is;
        PRIntervalTime timeout;
        if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);

        _PR_RUNQ_LOCK(cpu);
#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY)
#ifdef _PR_HAVE_ATOMIC_OPS
        _PR_MD_ATOMIC_INCREMENT(&_pr_md_idle_cpus);
#else
        _PR_MD_LOCK(&_pr_md_idle_cpus_lock);
        _pr_md_idle_cpus++;
        _PR_MD_UNLOCK(&_pr_md_idle_cpus_lock);
#endif /* _PR_HAVE_ATOMIC_OPS */
#endif
        /* If someone on runq; do a nonblocking PAUSECPU */
        if (_PR_RUNQREADYMASK(me->cpu) != 0) {
            _PR_RUNQ_UNLOCK(cpu);
            timeout = PR_INTERVAL_NO_WAIT;
        } else {
            _PR_RUNQ_UNLOCK(cpu);

            _PR_SLEEPQ_LOCK(cpu);
            if (PR_CLIST_IS_EMPTY(&_PR_SLEEPQ(me->cpu))) {
                timeout = PR_INTERVAL_NO_TIMEOUT;
            } else {
                PRThread *wakeThread;
                wakeThread = _PR_THREAD_PTR(_PR_SLEEPQ(me->cpu).next);
                timeout = wakeThread->sleep;
            }
            _PR_SLEEPQ_UNLOCK(cpu);
        }

        /* Wait for an IO to complete */
        (void)_PR_MD_PAUSE_CPU(timeout);

#ifdef WINNT
        if (_pr_cpus_exit) {
            /* _PR_CleanupCPUs tells us to exit */
            _PR_MD_END_THREAD();
        }
#endif

#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY)
#ifdef _PR_HAVE_ATOMIC_OPS
        _PR_MD_ATOMIC_DECREMENT(&_pr_md_idle_cpus);
#else
        _PR_MD_LOCK(&_pr_md_idle_cpus_lock);
        _pr_md_idle_cpus--;
        _PR_MD_UNLOCK(&_pr_md_idle_cpus_lock);
#endif /* _PR_HAVE_ATOMIC_OPS */
#endif

              _PR_ClockInterrupt();

              /* Now schedule any thread that is on the runq
               * INTS must be OFF when calling PR_Schedule()
               */
              me->state = _PR_RUNNABLE;
              _PR_MD_SWITCH_CONTEXT(me);
              if (!_PR_IS_NATIVE_THREAD(me)) _PR_FAST_INTSON(is);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static _PRCPU * _PR_CreateCPU ( void  ) [static]

Definition at line 190 of file prucpu.c.

{
    _PRCPU *cpu;

    cpu = PR_NEWZAP(_PRCPU);
    if (cpu) {
        cpu->queue = _PR_CreateCPUQueue();
        if (!cpu->queue) {
            PR_DELETE(cpu);
            return NULL;
        }
    }
    return cpu;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static _PRCPUQueue* _PR_CreateCPUQueue ( void  ) [static]

Definition at line 149 of file prucpu.c.

{
    PRInt32 index;
    _PRCPUQueue *cpuQueue;
    cpuQueue = PR_NEWZAP(_PRCPUQueue);
 
    _MD_NEW_LOCK( &cpuQueue->runQLock );
    _MD_NEW_LOCK( &cpuQueue->sleepQLock );
    _MD_NEW_LOCK( &cpuQueue->miscQLock );

    for (index = 0; index < PR_PRIORITY_LAST + 1; index++)
        PR_INIT_CLIST( &(cpuQueue->runQ[index]) );
    PR_INIT_CLIST( &(cpuQueue->sleepQ) );
    PR_INIT_CLIST( &(cpuQueue->pauseQ) );
    PR_INIT_CLIST( &(cpuQueue->suspendQ) );
    PR_INIT_CLIST( &(cpuQueue->waitingToJoinQ) );

    cpuQueue->numCPUs = 1;

    return cpuQueue;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 72 of file prucpu.c.

{
    PRThread *me = _PR_MD_CURRENT_THREAD();

    if (_native_threads_only)
        return;

    _pr_cpuID = 0;
    _MD_NEW_LOCK( &_pr_cpuLock);
#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY)
#ifndef _PR_HAVE_ATOMIC_OPS
    _MD_NEW_LOCK(&_pr_md_idle_cpus_lock);
#endif
#endif

#ifdef _PR_LOCAL_THREADS_ONLY

#ifdef HAVE_CUSTOM_USER_THREADS
    _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(me);
#endif

    /* Now start the first CPU. */
    _pr_primordialCPU = _PR_CreateCPU();
    _pr_numCPU = 1;
    _PR_StartCPU(_pr_primordialCPU, me);

    _PR_MD_SET_CURRENT_CPU(_pr_primordialCPU);

    /* Initialize cpu for current thread (could be different from me) */
    _PR_MD_CURRENT_THREAD()->cpu = _pr_primordialCPU;

    _PR_MD_SET_LAST_THREAD(me);

#else /* Combined MxN model */

    _pr_primordialCPU = _PR_CreateCPU();
    _pr_numCPU = 1;
    _PR_CreateThread(PR_SYSTEM_THREAD,
                     _PR_RunCPU,
                     _pr_primordialCPU,
                     PR_PRIORITY_NORMAL,
                     PR_GLOBAL_THREAD,
                     PR_UNJOINABLE_THREAD,
                     0,
                     _PR_IDLE_THREAD);

#endif /* _PR_LOCAL_THREADS_ONLY */

    _PR_MD_INIT_CPUS();
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void _PR_RunCPU ( void arg) [static]

Definition at line 268 of file prucpu.c.

{
    _PRCPU *cpu = (_PRCPU *)arg;
    PRThread *me = _PR_MD_CURRENT_THREAD();

    PR_ASSERT(NULL != me);

    /*
     * _PR_StartCPU calls _PR_CreateThread to create the
     * idle thread.  Because _PR_CreateThread calls PR_Lock,
     * the current thread has to remain a global thread
     * during the _PR_StartCPU call so that it can wait for
     * the lock if the lock is held by another thread.  If
     * we clear the _PR_GLOBAL_SCOPE flag in
     * _PR_MD_CREATE_PRIMORDIAL_THREAD, the current thread
     * will be treated as a local thread and have trouble
     * waiting for the lock because the CPU is not fully
     * constructed yet.
     *
     * After the CPU is started, it is safe to mark the
     * current thread as a local thread.
     */

#ifdef HAVE_CUSTOM_USER_THREADS
    _PR_MD_CREATE_PRIMORDIAL_USER_THREAD(me);
#endif

    me->no_sched = 1;
    _PR_StartCPU(cpu, me);

#ifdef HAVE_CUSTOM_USER_THREADS
    me->flags &= (~_PR_GLOBAL_SCOPE);
#endif

    _PR_MD_SET_CURRENT_CPU(cpu);
    _PR_MD_SET_CURRENT_THREAD(cpu->thread);
    me->cpu = cpu;

    while(1) {
        PRInt32 is;
        if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
           _PR_MD_START_INTERRUPTS();
        _PR_MD_SWITCH_CONTEXT(me);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRStatus _PR_StartCPU ( _PRCPU cpu,
PRThread thread 
) [static]

Definition at line 213 of file prucpu.c.

{
    /*
    ** Start a new cpu. The assumption this code makes is that the
    ** underlying operating system creates a stack to go with the new
    ** native thread. That stack will be used by the cpu when pausing.
    */

    PR_ASSERT(!_native_threads_only);

    cpu->last_clock = PR_IntervalNow();

    /* Before we create any threads on this CPU we have to
     * set the current CPU 
     */
    _PR_MD_SET_CURRENT_CPU(cpu);
    _PR_MD_INIT_RUNNING_CPU(cpu);
    thread->cpu = cpu;

    cpu->idle_thread = _PR_CreateThread(PR_SYSTEM_THREAD,
                                        _PR_CPU_Idle,
                                        (void *)cpu,
                                        PR_PRIORITY_NORMAL,
                                        PR_LOCAL_THREAD,
                                        PR_UNJOINABLE_THREAD,
                                        0,
                                        _PR_IDLE_THREAD);

    if (!cpu->idle_thread) {
        /* didn't clean up CPU queue XXXMB */
        PR_DELETE(cpu);
        return PR_FAILURE;
    } 
    PR_ASSERT(cpu->idle_thread->cpu == cpu);

    cpu->idle_thread->no_sched = 0;

    cpu->thread = thread;

    if (_pr_cpu_affinity_mask)
        PR_SetThreadAffinityMask(thread, _pr_cpu_affinity_mask);

    /* Created and started a new CPU */
    _PR_CPU_LIST_LOCK();
    cpu->id = _pr_cpuID++;
    PR_APPEND_LINK(&cpu->links, &_PR_CPUQ());
    _PR_CPU_LIST_UNLOCK();

    return PR_SUCCESS;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 392 of file prucpu.c.

{
#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_LOCAL_THREADS_ONLY)
#ifdef XP_MAC 
#pragma unused(numCPUs) 
#endif

    /* do nothing */

#else /* combined, MxN thread model */

    PRUintn newCPU;
    _PRCPU *cpu;
    PRThread *thr;


    if (!_pr_initialized) _PR_ImplicitInitialization();

       if (_native_threads_only)
              return;
    
    _PR_CPU_LIST_LOCK();
    if (_pr_numCPU < numCPUs) {
        newCPU = numCPUs - _pr_numCPU;
        _pr_numCPU = numCPUs;
    } else newCPU = 0;
    _PR_CPU_LIST_UNLOCK();

    for (; newCPU; newCPU--) {
        cpu = _PR_CreateCPU();
        thr = _PR_CreateThread(PR_SYSTEM_THREAD,
                              _PR_RunCPU,
                              cpu,
                              PR_PRIORITY_NORMAL,
                              PR_GLOBAL_THREAD,
                              PR_UNJOINABLE_THREAD,
                              0,
                              _PR_IDLE_THREAD);
    }
#endif
}

Here is the call graph for this function:

Definition at line 434 of file prucpu.c.

{
    if (_pr_primordialCPU)
        return _pr_primordialCPU;
    else
        return _PR_MD_CURRENT_CPU();
}

Variable Documentation

Definition at line 57 of file prucpu.c.

PRUintn _pr_cpuID [static]

Definition at line 61 of file prucpu.c.

Definition at line 56 of file prucpu.c.

Definition at line 42 of file prucpu.c.

Definition at line 52 of file prucpu.c.

PRUintn _pr_numCPU

Definition at line 55 of file prucpu.c.

Definition at line 40 of file prucpu.c.