prucpu.c revision 677833bc953b6cb418c701facbdcf4aa18d6c44e
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* 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
*
* 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 the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "primpl.h"
/*
* If _PR_HAVE_ATOMIC_OPS is not defined, they can't use the atomic
* because PR_Lock asserts that the calling thread is not an idle thread.
* So we use a _MDLock to protect _pr_md_idle_cpus.
*/
#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY)
#ifndef _PR_HAVE_ATOMIC_OPS
static _MDLock _pr_md_idle_cpus_lock;
#endif
#endif
#if !defined (_PR_GLOBAL_THREADS_ONLY)
static void PR_CALLBACK _PR_CPU_Idle(void *);
static _PRCPU *_PR_CreateCPU(void);
#if !defined(_PR_LOCAL_THREADS_ONLY)
static void _PR_RunCPU(void *arg);
#endif
void _PR_InitCPUs()
{
if (_native_threads_only)
return;
_pr_cpuID = 0;
#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY)
#ifndef _PR_HAVE_ATOMIC_OPS
#endif
#endif
#ifdef _PR_LOCAL_THREADS_ONLY
#ifdef HAVE_CUSTOM_USER_THREADS
#endif
/* Now start the first CPU. */
_pr_numCPU = 1;
/* Initialize cpu for current thread (could be different from me) */
#else /* Combined MxN model */
_pr_numCPU = 1;
0,
#endif /* _PR_LOCAL_THREADS_ONLY */
}
#ifdef WINNT
/*
* Right now this function merely stops the CPUs and does
* not do any other cleanup.
*
* It is only implemented for WINNT because bug 161998 only
* affects the WINNT version of NSPR, but it would be nice
* to implement this function for other platforms too.
*/
void _PR_CleanupCPUs(void)
{
PRUintn i;
_pr_cpus_exit = 1;
for (i = 0; i < _pr_numCPU; i++) {
}
}
}
#endif
static _PRCPUQueue *_PR_CreateCPUQueue(void)
{
return cpuQueue;
}
/*
* Create a new CPU.
*
* This function initializes enough of the _PRCPU structure so
* that it can be accessed safely by a global thread or another
* CPU. This function does not create the native thread that
* will run the CPU nor does it initialize the parts of _PRCPU
* that must be initialized by that native thread.
*
* The reason we cannot simply have the native thread create
* and fully initialize a new CPU is that we need to be able to
* create a usable _pr_primordialCPU in _PR_InitCPUs without
* assuming that the primordial CPU thread we created can run
* during NSPR initialization. For example, on Windows while
* new threads can be created by DllMain, they won't be able
* to run during DLL initialization. If NSPR is initialized
* by DllMain, the primordial CPU thread won't run until DLL
* initialization is finished.
*/
static _PRCPU *_PR_CreateCPU(void)
{
if (cpu) {
return NULL;
}
}
return cpu;
}
/*
* Start a new CPU.
*
* 'cpu' is a _PRCPU structure created by _PR_CreateCPU().
* 'thread' is the native thread that will run the CPU.
*
* If this function fails, 'cpu' is destroyed.
*/
{
/*
** 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.
*/
/* Before we create any threads on this CPU we have to
* set the current CPU
*/
(void *)cpu,
0,
if (!cpu->idle_thread) {
/* didn't clean up CPU queue XXXMB */
return PR_FAILURE;
}
/* Created and started a new CPU */
return PR_SUCCESS;
}
#if !defined(_PR_GLOBAL_THREADS_ONLY) && !defined(_PR_LOCAL_THREADS_ONLY)
/*
** This code is used during a cpu's initial creation.
*/
static void _PR_RunCPU(void *arg)
{
/*
* _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
#endif
#ifdef HAVE_CUSTOM_USER_THREADS
#endif
while(1) {
}
}
#endif
{
if (_MD_LAST_THREAD())
_MD_LAST_THREAD()->no_sched = 0;
while(1) {
#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY)
#ifdef _PR_HAVE_ATOMIC_OPS
#else
#endif /* _PR_HAVE_ATOMIC_OPS */
#endif
/* If someone on runq; do a nonblocking PAUSECPU */
} else {
} else {
}
}
/* Wait for an IO to complete */
(void)_PR_MD_PAUSE_CPU(timeout);
#ifdef WINNT
if (_pr_cpus_exit) {
/* _PR_CleanupCPUs tells us to exit */
}
#endif
#if !defined(_PR_LOCAL_THREADS_ONLY) && !defined(_PR_GLOBAL_THREADS_ONLY)
#ifdef _PR_HAVE_ATOMIC_OPS
#else
#endif /* _PR_HAVE_ATOMIC_OPS */
#endif
/* Now schedule any thread that is on the runq
* INTS must be OFF when calling PR_Schedule()
*/
}
}
#endif /* _PR_GLOBAL_THREADS_ONLY */
{
#if defined(_PR_GLOBAL_THREADS_ONLY) || defined(_PR_LOCAL_THREADS_ONLY)
#ifdef XP_MAC
#endif
/* do nothing */
#else /* combined, MxN thread model */
if (_native_threads_only)
return;
if (_pr_numCPU < numCPUs) {
} else newCPU = 0;
cpu = _PR_CreateCPU();
cpu,
0,
}
#endif
}
{
if (_pr_primordialCPU)
return _pr_primordialCPU;
else
return _PR_MD_CURRENT_CPU();
}