Bug 1091533, Part 2: Implement NuwaAddThreadConstructor() to allow a thread to perform a custom action after being recreated in the content process. r=khuey,tlee

This commit is contained in:
Cervantes Yu 2014-11-06 19:34:03 +08:00
parent 4199f3e652
commit 66f8cbe724
2 changed files with 75 additions and 21 deletions

View File

@ -117,6 +117,22 @@ static size_t getPageSize(void) {
#define NATIVE_THREAD_NAME_LENGTH 16
typedef struct nuwa_construct {
typedef void(*construct_t)(void*);
construct_t construct;
void *arg;
nuwa_construct(construct_t aConstruct, void *aArg)
: construct(aConstruct)
, arg(aArg)
{ }
nuwa_construct(const nuwa_construct&) = default;
nuwa_construct& operator=(const nuwa_construct&) = default;
} nuwa_construct_t;
struct thread_info : public mozilla::LinkedListElement<thread_info> {
pthread_t origThreadID;
pthread_t recreatedThreadID;
@ -131,8 +147,15 @@ struct thread_info : public mozilla::LinkedListElement<thread_info> {
// The thread specific function to recreate the new thread. It's executed
// after the thread is recreated.
void (*recrFunc)(void *arg);
void *recrArg;
std::vector<nuwa_construct_t> *recrFunctions;
void addThreadConstructor(const nuwa_construct_t *construct) {
if (!recrFunctions) {
recrFunctions = new std::vector<nuwa_construct_t>();
}
recrFunctions->push_back(*construct);
}
TLSInfoList tlsInfo;
@ -169,8 +192,12 @@ static thread_info_t *sCurrentRecreatingThread = nullptr;
static void
RunCustomRecreation() {
thread_info_t *tinfo = sCurrentRecreatingThread;
if (tinfo->recrFunc != nullptr) {
tinfo->recrFunc(tinfo->recrArg);
if (tinfo->recrFunctions) {
for (auto iter = tinfo->recrFunctions->begin();
iter != tinfo->recrFunctions->end();
iter++) {
iter->construct(iter->arg);
}
}
}
@ -189,11 +216,6 @@ RunCustomRecreation() {
#define TINFO_FLAG_NUWA_SKIP 0x2
#define TINFO_FLAG_NUWA_EXPLICIT_CHECKPOINT 0x4
typedef struct nuwa_construct {
void (*construct)(void *);
void *arg;
} nuwa_construct_t;
static std::vector<nuwa_construct_t> sConstructors;
static std::vector<nuwa_construct_t> sFinalConstructors;
@ -507,8 +529,7 @@ thread_info_new(void) {
/* link tinfo to sAllThreads */
thread_info_t *tinfo = new thread_info_t();
tinfo->flags = 0;
tinfo->recrFunc = nullptr;
tinfo->recrArg = nullptr;
tinfo->recrFunctions = nullptr;
tinfo->recreatedThreadID = 0;
tinfo->recreatedNativeThreadID = 0;
tinfo->condMutex = nullptr;
@ -556,6 +577,10 @@ thread_info_cleanup(void *arg) {
tinfo->remove();
pthread_mutex_unlock(&sThreadCountLock);
if (tinfo->recrFunctions) {
delete tinfo->recrFunctions;
}
// while sThreadCountLock is held, since delete calls wrapped functions
// which try to lock sThreadCountLock. This results in deadlock. And we
// need to delete |tinfo| before decreasing sThreadCount, so Nuwa won't
@ -1765,8 +1790,10 @@ NuwaMarkCurrentThread(void (*recreate)(void *), void *arg) {
}
tinfo->flags |= TINFO_FLAG_NUWA_SUPPORT;
tinfo->recrFunc = recreate;
tinfo->recrArg = arg;
if (recreate) {
nuwa_construct_t construct(recreate, arg);
tinfo->addThreadConstructor(&construct);
}
// XXX Thread name might be set later than this call. If this is the case, we
// might need to delay getting the thread name.
@ -1873,9 +1900,7 @@ NuwaCheckpointCurrentThread2(int setjmpCond) {
*/
MFBT_API void
NuwaAddConstructor(void (*construct)(void *), void *arg) {
nuwa_construct_t ctr;
ctr.construct = construct;
ctr.arg = arg;
nuwa_construct_t ctr(construct, arg);
sConstructors.push_back(ctr);
}
@ -1885,12 +1910,21 @@ NuwaAddConstructor(void (*construct)(void *), void *arg) {
*/
MFBT_API void
NuwaAddFinalConstructor(void (*construct)(void *), void *arg) {
nuwa_construct_t ctr;
ctr.construct = construct;
ctr.arg = arg;
nuwa_construct_t ctr(construct, arg);
sFinalConstructors.push_back(ctr);
}
MFBT_API void
NuwaAddThreadConstructor(void (*aConstruct)(void *), void *aArg) {
thread_info *tinfo = CUR_THREAD_INFO;
if (!tinfo || !aConstruct) {
return;
}
nuwa_construct_t construct(aConstruct, aArg);
tinfo->addThreadConstructor(&construct);
}
/**
* @return if the current process is the nuwa process.
*/

View File

@ -88,6 +88,10 @@ MFBT_API pid_t NuwaSpawn();
* @param recreate The custom function that will be called in the spawned
* process, after the thread is recreated. Can be nullptr if no
* custom function to be called after the thread is recreated.
* Note that this function is called duing thread recreation
* while other threads are frozen. It must not perform any
* action (e.g. acquiring a mutex) that might depend on another
* thread that is still blocked.
* @param arg The argument passed to the custom function. Can be nullptr.
*/
MFBT_API void NuwaMarkCurrentThread(void (*recreate)(void *), void *arg);
@ -137,22 +141,38 @@ MFBT_API void MakeNuwaProcess();
/**
* Register a method to be invoked after a new process is spawned. The method
* will be invoked on the main thread.
* will be invoked on the main thread *before* recreating the other threads.
* The registered method must not perform any action (e.g. acquiring a mutex)
* that might depend on another thread that has not yet been recreated.
*
* @param construct The method to be invoked.
* @param arg The argument passed to the method.
*/
MFBT_API void NuwaAddConstructor(void (*construct)(void *), void *arg);
/**
* Register a method to be invoked after a new process is spawned and threads
* are recreated. The method will be invoked on the main thread.
* are recreated. The method will be invoked on the main thread *after*
* the other threads are recreated and fully functional.
*
* @param construct The method to be invoked.
* @param arg The argument passed to the method.
*/
MFBT_API void NuwaAddFinalConstructor(void (*construct)(void *), void *arg);
/**
* Register a method to be invoked after the current thread is recreated in the
* spawned process. Note that this function is called while other threads are
* frozen. It must not perform any action (e.g. acquiring a mutex) that might
* depend on another thread that is still blocked.
*
* @param construct The method to be invoked.
* @param arg The argument passed to the method.
*/
MFBT_API void NuwaAddThreadConstructor(void (*construct)(void *), void *arg);
/**
* The methods to query the Nuwa-related states.
*/