Backed out 9 changesets (bug 1476405) for causing leaks

Backed out changeset 4113d6fb3c1c (bug 1476405)
Backed out changeset cb7f7cc32687 (bug 1476405)
Backed out changeset 6d18a8bd5ee3 (bug 1476405)
Backed out changeset b2a99f50e642 (bug 1476405)
Backed out changeset b5b9d295545d (bug 1476405)
Backed out changeset f092a32a3639 (bug 1476405)
Backed out changeset 6c154f4d9dd9 (bug 1476405)
Backed out changeset d0ebb3aa8e0f (bug 1476405)
Backed out changeset 06b8093ddc6a (bug 1476405)
This commit is contained in:
Coroiu Cristina 2018-07-27 08:56:36 +03:00
Родитель a410b62f8d
Коммит 6d037d0cba
13 изменённых файлов: 147 добавлений и 259 удалений

Просмотреть файл

@ -59,7 +59,6 @@ struct AudioIpcInitParams {
int mServerConnection;
size_t mPoolSize;
size_t mStackSize;
void (*mThreadCreateCallback)(const char*);
};
// These functions are provided by audioipc-server crate
@ -431,9 +430,6 @@ cubeb* GetCubebContextUnlocked()
initParams.mPoolSize = sAudioIPCPoolSize;
initParams.mStackSize = sAudioIPCStackSize;
initParams.mServerConnection = sIPCConnection->ClonePlatformHandle().release();
initParams.mThreadCreateCallback = [](const char* aName) {
PROFILER_REGISTER_THREAD(aName);
};
MOZ_LOG(gCubebLog, LogLevel::Debug, ("%s: %d", PREF_AUDIOIPC_POOL_SIZE, (int) initParams.mPoolSize));
MOZ_LOG(gCubebLog, LogLevel::Debug, ("%s: %d", PREF_AUDIOIPC_STACK_SIZE, (int) initParams.mStackSize));

Просмотреть файл

@ -26,8 +26,6 @@
#include <pthread_np.h>
#endif
#include "nsThreadUtils.h"
#if defined(OS_MACOSX)
namespace base {
void InitThreading();
@ -35,10 +33,6 @@ void InitThreading();
#endif
static void* ThreadFunc(void* closure) {
// Create a nsThread wrapper for the current platform thread, and register it
// with the thread manager.
(void) NS_GetCurrentThread();
PlatformThread::Delegate* delegate =
static_cast<PlatformThread::Delegate*>(closure);
delegate->ThreadMain();
@ -98,10 +92,21 @@ void PlatformThread::SetName(const char* name) {
if (PlatformThread::CurrentId() == getpid())
return;
// Using NS_SetCurrentThreadName, as opposed to using platform APIs directly,
// also sets the thread name on the PRThread wrapper, and allows us to
// retrieve it using PR_GetThreadName.
NS_SetCurrentThreadName(name);
// http://0pointer.de/blog/projects/name-your-threads.html
// Set the name for the LWP (which gets truncated to 15 characters).
// Note that glibc also has a 'pthread_setname_np' api, but it may not be
// available everywhere and it's only benefit over using prctl directly is
// that it can set the name of threads other than the current thread.
#if defined(OS_LINUX)
prctl(PR_SET_NAME, reinterpret_cast<uintptr_t>(name), 0, 0, 0);
#elif defined(OS_NETBSD)
pthread_setname_np(pthread_self(), "%s", (void *)name);
#elif defined(OS_BSD) && !defined(__GLIBC__)
pthread_set_name_np(pthread_self(), name);
#elif defined(OS_SOLARIS)
pthread_setname_np(pthread_self(), name);
#else
#endif
}
#endif // !OS_MACOSX
@ -124,9 +129,8 @@ bool CreateThread(size_t stack_size, bool joinable,
pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
}
if (stack_size == 0)
stack_size = nsIThreadManager::DEFAULT_STACK_SIZE;
pthread_attr_setstacksize(&attributes, stack_size);
if (stack_size > 0)
pthread_attr_setstacksize(&attributes, stack_size);
success = !pthread_create(thread_handle, &attributes, ThreadFunc, delegate);

Просмотреть файл

@ -9,8 +9,6 @@
#include "base/logging.h"
#include "base/win_util.h"
#include "nsThreadUtils.h"
namespace {
// The information on how to set the thread name comes from
@ -25,10 +23,6 @@ typedef struct tagTHREADNAME_INFO {
} THREADNAME_INFO;
DWORD __stdcall ThreadFunc(void* closure) {
// Create a nsThread wrapper for the current platform thread, and register it
// with the thread manager.
(void) NS_GetCurrentThread();
PlatformThread::Delegate* delegate =
static_cast<PlatformThread::Delegate*>(closure);
delegate->ThreadMain();
@ -54,10 +48,24 @@ void PlatformThread::Sleep(int duration_ms) {
// static
void PlatformThread::SetName(const char* name) {
// Using NS_SetCurrentThreadName, as opposed to using platform APIs directly,
// also sets the thread name on the PRThread wrapper, and allows us to
// retrieve it using PR_GetThreadName.
NS_SetCurrentThreadName(name);
#ifdef HAVE_SEH_EXCEPTIONS
// The debugger needs to be around to catch the name in the exception. If
// there isn't a debugger, we are just needlessly throwing an exception.
if (!::IsDebuggerPresent())
return;
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = name;
info.dwThreadID = CurrentId();
info.dwFlags = 0;
MOZ_SEH_TRY {
RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
reinterpret_cast<DWORD_PTR*>(&info));
} MOZ_SEH_EXCEPT(EXCEPTION_CONTINUE_EXECUTION) {
}
#endif
}
// static

Просмотреть файл

@ -943,12 +943,7 @@ js::CurrentThreadIsParseThread()
}
#endif
// We want our default stack size limit to be approximately 2MB, to be safe, but
// expect most threads to use much less. On Linux, however, requesting a stack
// of 2MB or larger risks the kernel allocating an entire 2MB huge page for it
// on first access, which we do not want. To avoid this possibility, we subtract
// 2 standard VM page sizes from our default.
static const uint32_t kDefaultHelperStackSize = 2048 * 1024 - 2 * 4096;
static const uint32_t kDefaultHelperStackSize = 2048 * 1024;
static const uint32_t kDefaultHelperStackQuota = 1800 * 1024;
// TSan enforces a minimum stack size that's just slightly larger than our

Просмотреть файл

@ -79,10 +79,6 @@ using namespace xpc;
using namespace JS;
using mozilla::dom::AutoEntryScript;
// The watchdog thread loop is pretty trivial, and should not require much stack
// space to do its job. So only give it 32KiB.
static constexpr size_t kWatchdogStackSize = 32 * 1024;
static void WatchdogMain(void* arg);
class Watchdog;
class WatchdogManager;
@ -147,7 +143,7 @@ class Watchdog
// join it on shutdown.
mThread = PR_CreateThread(PR_USER_THREAD, WatchdogMain, this,
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD, kWatchdogStackSize);
PR_JOINABLE_THREAD, 0);
if (!mThread)
MOZ_CRASH("PR_CreateThread failed!");
@ -476,8 +472,6 @@ static void
WatchdogMain(void* arg)
{
AUTO_PROFILER_REGISTER_THREAD("JS Watchdog");
// Create an nsThread wrapper for the thread and register it with the thread manager.
Unused << NS_GetCurrentThread();
NS_SetCurrentThreadName("JS Watchdog");
Watchdog* self = static_cast<Watchdog*>(arg);

Просмотреть файл

@ -20,7 +20,6 @@ use std::os::raw::c_void;
use std::os::unix::io::FromRawFd;
use std::os::unix::net;
use std::sync::mpsc;
use std::thread;
use stream;
use tokio_core::reactor::{Handle, Remote};
use tokio_uds::UnixStream;
@ -100,25 +99,9 @@ impl ContextOps for ClientContext {
let (tx_rpc, rx_rpc) = mpsc::channel();
let params = CPUPOOL_INIT_PARAMS.with(|p| {
p.replace(None).unwrap()
});
let thread_create_callback = params.thread_create_callback;
let register_thread = move || {
if let Some(func) = thread_create_callback {
let thr = thread::current();
let name = CString::new(thr.name().unwrap()).unwrap();
func(name.as_ptr());
}
};
let core = t!(core::spawn_thread("AudioIPC Client RPC", move || {
let handle = core::handle();
register_thread();
open_server_stream()
.ok()
.and_then(|stream| UnixStream::from_stream(stream, &handle).ok())
@ -133,12 +116,14 @@ impl ContextOps for ClientContext {
let rpc = t!(rx_rpc.recv());
let cpupool = futures_cpupool::Builder::new()
let cpupool = CPUPOOL_INIT_PARAMS.with(|p| {
let params = p.replace(None).unwrap();
futures_cpupool::Builder::new()
.name_prefix("AudioIPC")
.after_start(register_thread)
.pool_size(params.pool_size)
.stack_size(params.stack_size)
.create();
.create()
});
let ctx = Box::new(ClientContext {
_ops: &CLIENT_OPS as *const _,

Просмотреть файл

@ -37,14 +37,12 @@ pub struct AudioIpcInitParams {
pub server_connection: c_int,
pub pool_size: usize,
pub stack_size: usize,
pub thread_create_callback: Option<extern "C" fn(*const ::std::os::raw::c_char)>,
}
#[derive(Clone, Copy, Debug)]
struct CpuPoolInitParams {
pub pool_size: usize,
pub stack_size: usize,
pub thread_create_callback: Option<extern "C" fn(*const ::std::os::raw::c_char)>,
}
impl CpuPoolInitParams {
@ -52,7 +50,6 @@ impl CpuPoolInitParams {
CpuPoolInitParams {
pool_size: params.pool_size,
stack_size: params.stack_size,
thread_create_callback: params.thread_create_callback,
}
}
}

Просмотреть файл

@ -268,8 +268,7 @@ BackgroundHangManager::BackgroundHangManager()
mHangMonitorThread = PR_CreateThread(
PR_USER_THREAD, MonitorThread, this,
PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD,
nsIThreadManager::DEFAULT_STACK_SIZE);
PR_PRIORITY_LOW, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
MOZ_ASSERT(mHangMonitorThread, "Failed to create BHR monitor thread");

Просмотреть файл

@ -3298,11 +3298,6 @@ profiler_register_thread(const char* aName, void* aGuessStackTop)
MOZ_ASSERT_IF(NS_IsMainThread(), Scheduler::IsCooperativeThread());
MOZ_RELEASE_ASSERT(CorePS::Exists());
// Make sure we have a nsThread wrapper for the current thread, and that NSPR
// knows its name.
(void) NS_GetCurrentThread();
NS_SetCurrentThreadName(aName);
PSAutoLock lock(gPSMutex);
void* stackTop = GetStackTop(aGuessStackTop);

Просмотреть файл

@ -405,13 +405,6 @@ nsThread::ThreadList()
return sList;
}
/* static */ void
nsThread::ClearThreadList()
{
OffTheBooksMutexAutoLock mal(ThreadListMutex());
while (ThreadList().popFirst()) {}
}
/* static */ nsThreadEnumerator
nsThread::Enumerate()
{
@ -427,6 +420,7 @@ nsThread::ThreadFunc(void* aArg)
nsThread* self = initData->thread; // strong reference
self->mThread = PR_GetCurrentThread();
self->mThreadId = uint32_t(PlatformThread::CurrentId());
self->mVirtualThread = GetCurrentVirtualThread();
self->mEventTarget->SetCurrentThread();
SetupCurrentThreadForChaosMode();
@ -435,7 +429,71 @@ nsThread::ThreadFunc(void* aArg)
NS_SetCurrentThreadName(initData->name.BeginReading());
}
self->InitCommon();
{
#if defined(XP_LINUX)
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_getattr_np(pthread_self(), &attr);
size_t stackSize;
pthread_attr_getstack(&attr, &self->mStackBase, &stackSize);
// Glibc prior to 2.27 reports the stack size and base including the guard
// region, so we need to compensate for it to get accurate accounting.
// Also, this behavior difference isn't guarded by a versioned symbol, so we
// actually need to check the runtime glibc version, not the version we were
// compiled against.
static bool sAdjustForGuardSize = ({
#ifdef __GLIBC__
unsigned major, minor;
sscanf(gnu_get_libc_version(), "%u.%u", &major, &minor) < 2 ||
major < 2 || (major == 2 && minor < 27);
#else
false;
#endif
});
if (sAdjustForGuardSize) {
size_t guardSize;
pthread_attr_getguardsize(&attr, &guardSize);
// Note: This assumes that the stack grows down, as is the case on all of
// our tier 1 platforms. On platforms where the stack grows up, the
// mStackBase adjustment is unnecessary, but doesn't cause any harm other
// than under-counting stack memory usage by one page.
self->mStackBase = reinterpret_cast<char*>(self->mStackBase) + guardSize;
stackSize -= guardSize;
}
self->mStackSize = stackSize;
// This is a bit of a hack.
//
// We really do want the NOHUGEPAGE flag on our thread stacks, since we
// don't expect any of them to need anywhere near 2MB of space. But setting
// it here is too late to have an effect, since the first stack page has
// already been faulted in existence, and NSPR doesn't give us a way to set
// it beforehand.
//
// What this does get us, however, is a different set of VM flags on our
// thread stacks compared to normal heap memory. Which makes the Linux
// kernel report them as separate regions, even when they are adjacent to
// heap memory. This allows us to accurately track the actual memory
// consumption of our allocated stacks.
madvise(self->mStackBase, stackSize, MADV_NOHUGEPAGE);
pthread_attr_destroy(&attr);
#elif defined(XP_WIN)
static const DynamicallyLinkedFunctionPtr<GetCurrentThreadStackLimitsFn>
sGetStackLimits(L"kernel32.dll", "GetCurrentThreadStackLimits");
if (sGetStackLimits) {
ULONG_PTR stackBottom, stackTop;
sGetStackLimits(&stackBottom, &stackTop);
self->mStackBase = reinterpret_cast<void*>(stackBottom);
self->mStackSize = stackTop - stackBottom;
}
#endif
}
// Inform the ThreadManager
nsThreadManager::get().RegisterCurrentThread(*self);
@ -516,81 +574,6 @@ nsThread::ThreadFunc(void* aArg)
NS_RELEASE(self);
}
void
nsThread::InitCommon()
{
mThreadId = uint32_t(PlatformThread::CurrentId());
{
#if defined(XP_LINUX)
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_getattr_np(pthread_self(), &attr);
size_t stackSize;
pthread_attr_getstack(&attr, &mStackBase, &stackSize);
// Glibc prior to 2.27 reports the stack size and base including the guard
// region, so we need to compensate for it to get accurate accounting.
// Also, this behavior difference isn't guarded by a versioned symbol, so we
// actually need to check the runtime glibc version, not the version we were
// compiled against.
static bool sAdjustForGuardSize = ({
#ifdef __GLIBC__
unsigned major, minor;
sscanf(gnu_get_libc_version(), "%u.%u", &major, &minor) < 2 ||
major < 2 || (major == 2 && minor < 27);
#else
false;
#endif
});
if (sAdjustForGuardSize) {
size_t guardSize;
pthread_attr_getguardsize(&attr, &guardSize);
// Note: This assumes that the stack grows down, as is the case on all of
// our tier 1 platforms. On platforms where the stack grows up, the
// mStackBase adjustment is unnecessary, but doesn't cause any harm other
// than under-counting stack memory usage by one page.
mStackBase = reinterpret_cast<char*>(mStackBase) + guardSize;
stackSize -= guardSize;
}
mStackSize = stackSize;
// This is a bit of a hack.
//
// We really do want the NOHUGEPAGE flag on our thread stacks, since we
// don't expect any of them to need anywhere near 2MB of space. But setting
// it here is too late to have an effect, since the first stack page has
// already been faulted in existence, and NSPR doesn't give us a way to set
// it beforehand.
//
// What this does get us, however, is a different set of VM flags on our
// thread stacks compared to normal heap memory. Which makes the Linux
// kernel report them as separate regions, even when they are adjacent to
// heap memory. This allows us to accurately track the actual memory
// consumption of our allocated stacks.
madvise(mStackBase, stackSize, MADV_NOHUGEPAGE);
pthread_attr_destroy(&attr);
#elif defined(XP_WIN)
static const DynamicallyLinkedFunctionPtr<GetCurrentThreadStackLimitsFn>
sGetStackLimits(L"kernel32.dll", "GetCurrentThreadStackLimits");
if (sGetStackLimits) {
ULONG_PTR stackBottom, stackTop;
sGetStackLimits(&stackBottom, &stackTop);
mStackBase = reinterpret_cast<void*>(stackBottom);
mStackSize = stackTop - stackBottom;
}
#endif
}
OffTheBooksMutexAutoLock mal(ThreadListMutex());
ThreadList().insertBack(this);
}
//-----------------------------------------------------------------------------
// Tell the crash reporter to save a memory report if our heuristics determine
@ -687,17 +670,7 @@ nsThread::~nsThread()
{
NS_ASSERTION(mRequestedShutdownContexts.IsEmpty(),
"shouldn't be waiting on other threads to shutdown");
// We shouldn't need to lock before checking isInList at this point. We're
// destroying the last reference to this object, so there's no way for anyone
// else to remove it in the middle of our check. And the not-in-list state is
// determined the element's next and previous members pointing to itself, so a
// non-atomic update to an adjacent member won't affect the outcome either.
if (isInList()) {
OffTheBooksMutexAutoLock mal(ThreadListMutex());
removeFrom(ThreadList());
}
MOZ_ASSERT(!isInList());
#ifdef DEBUG
// We deliberately leak these so they can be tracked by the leak checker.
// If you're having nsThreadShutdownContext leaks, you can set:
@ -731,6 +704,11 @@ nsThread::Init(const nsACString& aName)
return NS_ERROR_OUT_OF_MEMORY;
}
{
OffTheBooksMutexAutoLock mal(ThreadListMutex());
ThreadList().insertBack(this);
}
// ThreadFunc will wait for this event to be run before it tries to access
// mThread. By delaying insertion of this event into the queue, we ensure
// that mThread is set properly.
@ -750,7 +728,6 @@ nsThread::InitCurrentThread()
mThread = PR_GetCurrentThread();
mVirtualThread = GetCurrentVirtualThread();
SetupCurrentThreadForChaosMode();
InitCommon();
nsThreadManager::get().RegisterCurrentThread(*this);
return NS_OK;
@ -879,13 +856,6 @@ nsThread::ShutdownComplete(NotNull<nsThreadShutdownContext*> aContext)
MOZ_ASSERT(mThread);
MOZ_ASSERT(aContext->mTerminatingThread == this);
{
OffTheBooksMutexAutoLock mal(ThreadListMutex());
if (isInList()) {
removeFrom(ThreadList());
}
}
if (aContext->mAwaitingShutdownAck) {
// We're in a synchronous shutdown, so tell whatever is up the stack that
// we're done and unwind the stack so it can call us again.

Просмотреть файл

@ -66,12 +66,6 @@ public:
// Initialize this as a wrapper for the current PRThread.
nsresult InitCurrentThread();
private:
// Initializes the mThreadId and stack base/size members, and adds the thread
// to the ThreadList().
void InitCommon();
public:
// The PRThread corresponding to this thread.
PRThread* GetPRThread()
{
@ -176,11 +170,8 @@ protected:
struct nsThreadShutdownContext* ShutdownInternal(bool aSync);
friend class nsThreadManager;
static mozilla::OffTheBooksMutex& ThreadListMutex();
static mozilla::LinkedList<nsThread>& ThreadList();
static void ClearThreadList();
RefPtr<mozilla::SynchronizedEventQueue> mEvents;
RefPtr<mozilla::ThreadEventTarget> mEventTarget;
@ -214,8 +205,6 @@ protected:
// Set to true if this thread creates a JSRuntime.
bool mCanInvokeJS;
bool mHasTLSEntry = false;
// Used to track which event is being executed by ProcessNextEvent
nsCOMPtr<nsIRunnable> mCurrentEvent;

Просмотреть файл

@ -94,27 +94,12 @@ AssertIsOnMainThread()
typedef nsTArray<NotNull<RefPtr<nsThread>>> nsThreadArray;
static bool sShutdownComplete;
//-----------------------------------------------------------------------------
/* static */ void
nsThreadManager::ReleaseThread(void* aData)
static void
ReleaseObject(void* aData)
{
if (sShutdownComplete) {
// We've already completed shutdown and released the references to all or
// our TLS wrappers. Don't try to release them again.
return;
}
auto* thread = static_cast<nsThread*>(aData);
get().UnregisterCurrentThread(*thread, true);
if (thread->mHasTLSEntry) {
thread->mHasTLSEntry = false;
thread->Release();
}
static_cast<nsISupports*>(aData)->Release();
}
// statically allocated instance
@ -251,7 +236,7 @@ nsThreadManager::Init()
Scheduler::EventLoopActivation::Init();
if (PR_NewThreadPrivateIndex(&mCurThreadIndex, ReleaseThread) == PR_FAILURE) {
if (PR_NewThreadPrivateIndex(&mCurThreadIndex, ReleaseObject) == PR_FAILURE) {
return NS_ERROR_FAILURE;
}
@ -319,34 +304,32 @@ nsThreadManager::Shutdown()
// Empty the main thread event queue before we begin shutting down threads.
NS_ProcessPendingEvents(mMainThread);
// We gather the threads from the hashtable into a list, so that we avoid
// holding the hashtable lock while calling nsIThread::Shutdown.
nsThreadArray threads;
{
// We gather the threads from the hashtable into a list, so that we avoid
// holding the hashtable lock while calling nsIThread::Shutdown.
nsThreadArray threads;
{
OffTheBooksMutexAutoLock lock(mLock);
for (auto iter = mThreadsByPRThread.Iter(); !iter.Done(); iter.Next()) {
RefPtr<nsThread>& thread = iter.Data();
threads.AppendElement(WrapNotNull(thread));
iter.Remove();
}
OffTheBooksMutexAutoLock lock(mLock);
for (auto iter = mThreadsByPRThread.Iter(); !iter.Done(); iter.Next()) {
RefPtr<nsThread>& thread = iter.Data();
threads.AppendElement(WrapNotNull(thread));
iter.Remove();
}
}
// It's tempting to walk the list of threads here and tell them each to stop
// accepting new events, but that could lead to badness if one of those
// threads is stuck waiting for a response from another thread. To do it
// right, we'd need some way to interrupt the threads.
//
// Instead, we process events on the current thread while waiting for threads
// to shutdown. This means that we have to preserve a mostly functioning
// world until such time as the threads exit.
// It's tempting to walk the list of threads here and tell them each to stop
// accepting new events, but that could lead to badness if one of those
// threads is stuck waiting for a response from another thread. To do it
// right, we'd need some way to interrupt the threads.
//
// Instead, we process events on the current thread while waiting for threads
// to shutdown. This means that we have to preserve a mostly functioning
// world until such time as the threads exit.
// Shutdown all threads that require it (join with threads that we created).
for (uint32_t i = 0; i < threads.Length(); ++i) {
NotNull<nsThread*> thread = threads[i];
if (thread->ShutdownRequired()) {
thread->Shutdown();
}
// Shutdown all threads that require it (join with threads that we created).
for (uint32_t i = 0; i < threads.Length(); ++i) {
NotNull<nsThread*> thread = threads[i];
if (thread->ShutdownRequired()) {
thread->Shutdown();
}
}
@ -377,24 +360,6 @@ nsThreadManager::Shutdown()
// Remove the TLS entry for the main thread.
PR_SetThreadPrivate(mCurThreadIndex, nullptr);
{
// Cleanup the last references to any threads which haven't shut down yet.
nsTArray<RefPtr<nsThread>> threads;
for (auto* thread : nsThread::Enumerate()) {
if (thread->mHasTLSEntry) {
threads.AppendElement(dont_AddRef(thread));
thread->mHasTLSEntry = false;
}
}
}
// xpcshell tests sometimes leak the main thread. They don't enable leak
// checking, so that doesn't cause the test to fail, but leaving the entry in
// the thread list triggers an assertion, which does.
nsThread::ClearThreadList();
sShutdownComplete = true;
}
void
@ -412,28 +377,21 @@ nsThreadManager::RegisterCurrentThread(nsThread& aThread)
mThreadsByPRThread.Put(aThread.GetPRThread(), &aThread); // XXX check OOM?
aThread.AddRef(); // for TLS entry
aThread.mHasTLSEntry = true;
PR_SetThreadPrivate(mCurThreadIndex, &aThread);
}
void
nsThreadManager::UnregisterCurrentThread(nsThread& aThread, bool aIfExists)
nsThreadManager::UnregisterCurrentThread(nsThread& aThread)
{
MOZ_ASSERT(aThread.GetPRThread() == PR_GetCurrentThread(), "bad aThread");
{
OffTheBooksMutexAutoLock lock(mLock);
OffTheBooksMutexAutoLock lock(mLock);
if (aIfExists && !mThreadsByPRThread.GetWeak(aThread.GetPRThread())) {
return;
}
--mCurrentNumberOfThreads;
mThreadsByPRThread.Remove(aThread.GetPRThread());
}
--mCurrentNumberOfThreads;
mThreadsByPRThread.Remove(aThread.GetPRThread());
PR_SetThreadPrivate(mCurThreadIndex, nullptr);
// Ref-count balanced via ReleaseThread
// Ref-count balanced via ReleaseObject
}
nsThread*

Просмотреть файл

@ -36,7 +36,7 @@ public:
// Called by nsThread to inform the ThreadManager it is going away. This
// method must be called when the given thread is the current thread.
void UnregisterCurrentThread(nsThread& aThread, bool aIfExists = false);
void UnregisterCurrentThread(nsThread& aThread);
// Returns the current thread. Returns null if OOM or if ThreadManager isn't
// initialized. Creates the nsThread if one does not exist yet.
@ -85,8 +85,6 @@ private:
SpinEventLoopUntilInternal(nsINestedEventLoopCondition* aCondition,
bool aCheckingShutdown);
static void ReleaseThread(void* aData);
nsRefPtrHashtable<nsPtrHashKey<PRThread>, nsThread> mThreadsByPRThread;
unsigned mCurThreadIndex; // thread-local-storage index
RefPtr<nsThread> mMainThread;