Bug 1323100 - Add nsThreadManager::NewNamedThread API. r?froydnj
The point of this exercise is to make the thread name available in the thread
func of the thread, so that we can register the thread with the profiler from
the very start of its lifetime, and so that registration and unregistration
can be inside the same function.
MozReview-Commit-ID: DiiMKUQVr55
--- a/xpcom/threads/nsIThreadManager.idl
+++ b/xpcom/threads/nsIThreadManager.idl
@@ -31,16 +31,30 @@ interface nsIThreadManager : nsISupports
* Number of bytes to reserve for the thread's stack.
*
* @returns
* The newly created nsIThread object.
*/
nsIThread newThread(in unsigned long creationFlags, [optional] in unsigned long stackSize);
/**
+ * Create a new thread (a global, user PRThread) with the specified name.
+ *
+ * @param name
+ * The name of the thread. Passing an empty name is equivalent to
+ * calling newThread(0, stackSize), i.e. the thread will not be named.
+ * @param stackSize
+ * Number of bytes to reserve for the thread's stack.
+ *
+ * @returns
+ * The newly created nsIThread object.
+ */
+ [noscript] nsIThread newNamedThread(in ACString name, [optional] in unsigned long stackSize);
+
+ /**
* Get the nsIThread object (if any) corresponding to the given PRThread.
* This method returns null if there is no corresponding nsIThread.
*
* @param prthread
* The PRThread of the nsIThread being requested.
*
* @returns
* The nsIThread object corresponding to the given PRThread or null if no
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -427,39 +427,57 @@ SetupCurrentThreadForChaosMode()
#endif
// Force half the threads to CPU 0 so they compete for CPU
if (ChaosMode::randomUint32LessThan(2)) {
SetThreadAffinity(0);
}
}
+namespace {
+
+struct ThreadInitData {
+ nsThread* thread;
+ const nsACString& name;
+};
+
+}
+
/*static*/ void
nsThread::ThreadFunc(void* aArg)
{
using mozilla::ipc::BackgroundChild;
- nsThread* self = static_cast<nsThread*>(aArg); // strong reference
+ ThreadInitData* initData = static_cast<ThreadInitData*>(aArg);
+ nsThread* self = initData->thread; // strong reference
+
self->mThread = PR_GetCurrentThread();
SetupCurrentThreadForChaosMode();
+ if (initData->name.Length() > 0) {
+ PR_SetCurrentThreadName(initData->name.BeginReading());
+ }
+
// Inform the ThreadManager
nsThreadManager::get().RegisterCurrentThread(*self);
mozilla::IOInterposer::RegisterCurrentThread();
// Wait for and process startup event
nsCOMPtr<nsIRunnable> event;
{
MutexAutoLock lock(self->mLock);
if (!self->mEvents->GetEvent(true, getter_AddRefs(event), lock)) {
NS_WARNING("failed waiting for thread startup event");
return;
}
}
+
+ initData = nullptr; // clear before unblocking nsThread::Init
+
event->Run(); // unblocks nsThread::Init
event = nullptr;
{
// Scope for MessageLoop.
nsAutoPtr<MessageLoop> loop(
new MessageLoop(MessageLoop::TYPE_MOZILLA_NONMAINTHREAD, self));
@@ -623,29 +641,31 @@ nsThread::~nsThread()
// the leak.
for (size_t i = 0; i < mRequestedShutdownContexts.Length(); ++i) {
Unused << mRequestedShutdownContexts[i].forget();
}
#endif
}
nsresult
-nsThread::Init()
+nsThread::Init(const nsACString& aName)
{
// spawn thread and wait until it is fully setup
RefPtr<nsThreadStartupEvent> startup = new nsThreadStartupEvent();
NS_ADDREF_THIS();
mIdlePeriod = new IdlePeriod();
mShutdownRequired = true;
+ ThreadInitData initData = { this, aName };
+
// ThreadFunc is responsible for setting mThread
- if (!PR_CreateThread(PR_USER_THREAD, ThreadFunc, this,
+ if (!PR_CreateThread(PR_USER_THREAD, ThreadFunc, &initData,
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD, mStackSize)) {
NS_RELEASE_THIS();
return NS_ERROR_OUT_OF_MEMORY;
}
// 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
--- a/xpcom/threads/nsThread.h
+++ b/xpcom/threads/nsThread.h
@@ -43,18 +43,18 @@ public:
enum MainThreadFlag
{
MAIN_THREAD,
NOT_MAIN_THREAD
};
nsThread(MainThreadFlag aMainThread, uint32_t aStackSize);
- // Initialize this as a wrapper for a new PRThread.
- nsresult Init();
+ // Initialize this as a wrapper for a new PRThread, and optionally give it a name.
+ nsresult Init(const nsACString& aName = NS_LITERAL_CSTRING(""));
// Initialize this as a wrapper for the current PRThread.
nsresult InitCurrentThread();
// The PRThread corresponding to this thread.
PRThread* GetPRThread()
{
return mThread;
--- a/xpcom/threads/nsThreadManager.cpp
+++ b/xpcom/threads/nsThreadManager.cpp
@@ -244,25 +244,33 @@ nsThreadManager::GetCurrentThread()
return thread.get(); // reference held in TLS
}
NS_IMETHODIMP
nsThreadManager::NewThread(uint32_t aCreationFlags,
uint32_t aStackSize,
nsIThread** aResult)
{
+ return NewNamedThread(NS_LITERAL_CSTRING(""), aStackSize, aResult);
+}
+
+NS_IMETHODIMP
+nsThreadManager::NewNamedThread(const nsACString& aName,
+ uint32_t aStackSize,
+ nsIThread** aResult)
+{
// Note: can be called from arbitrary threads
// No new threads during Shutdown
if (NS_WARN_IF(!mInitialized)) {
return NS_ERROR_NOT_INITIALIZED;
}
RefPtr<nsThread> thr = new nsThread(nsThread::NOT_MAIN_THREAD, aStackSize);
- nsresult rv = thr->Init(); // Note: blocks until the new thread has been set up
+ nsresult rv = thr->Init(aName); // Note: blocks until the new thread has been set up
if (NS_FAILED(rv)) {
return rv;
}
// At this point, we expect that the thread has been registered in mThreadByPRThread;
// however, it is possible that it could have also been replaced by now, so
// we cannot really assert that it was added. Instead, kill it if we entered
// Shutdown() during/before Init()