Bug 1121269 - Use a LinkedList to store TLS keys for Nuwa, and allocate the first element in a static buffer. r=thinker

This commit is contained in:
Mike Hommey 2015-01-15 07:40:21 +09:00
parent c18398b98d
commit 49deb404a9

View File

@ -23,6 +23,7 @@
#include <sys/syscall.h>
#include <vector>
#include "mozilla/Alignment.h"
#include "mozilla/LinkedList.h"
#include "mozilla/TaggedAnonymousMemory.h"
#include "Nuwa.h"
@ -215,8 +216,41 @@ RunCustomRecreation() {
static std::vector<nuwa_construct_t> sConstructors;
static std::vector<nuwa_construct_t> sFinalConstructors;
typedef std::map<pthread_key_t, void (*)(void *)> TLSKeySet;
static TLSKeySet sTLSKeys;
class TLSKey
: public std::pair<pthread_key_t, void (*)(void*)>
, public LinkedListElement<TLSKey>
{
public:
TLSKey() {}
TLSKey(pthread_key_t aKey, void (*aDestructor)(void*))
: std::pair<pthread_key_t, void (*)(void*)>(aKey, aDestructor)
{}
static void* operator new(size_t size) {
if (sUsed)
return ::operator new(size);
sUsed = true;
return sFirstElement.addr();
}
static void operator delete(void* ptr) {
if (ptr == sFirstElement.addr()) {
sUsed = false;
return;
}
::operator delete(ptr);
}
private:
static bool sUsed;
static AlignedStorage2<TLSKey> sFirstElement;
};
bool TLSKey::sUsed = false;
AlignedStorage2<TLSKey> TLSKey::sFirstElement;
static AutoCleanLinkedList<TLSKey> sTLSKeys;
/**
* This mutex is used to block the running threads and freeze their contexts.
@ -232,13 +266,13 @@ static int sThreadFreezeCount = 0;
// Bug 1008254: LinkedList's destructor asserts that the list is empty.
// But here, on exit, when the global sAllThreads list
// is destroyed, it may or may be empty. Bug 1008254 comment 395 has a log
// is destroyed, it may or may not be empty. Bug 1008254 comment 395 has a log
// when there were 8 threads remaining on exit. So this assertion was
// intermittently (almost every second time) failing.
// As a work-around to avoid this intermittent failure, we clear the list on
// exit just before it gets destroyed. This is the only purpose of that
// AllThreadsListType subclass.
struct AllThreadsListType : public LinkedList<thread_info_t>
struct AllThreadsListType : public AutoCleanLinkedList<thread_info_t>
{
~AllThreadsListType()
{
@ -263,7 +297,6 @@ struct AllThreadsListType : public LinkedList<thread_info_t>
sThreadCount,
sThreadFreezeCount);
}
clear();
}
};
static AllThreadsListType sAllThreads;
@ -297,7 +330,7 @@ static bool sForkWaitCondChanged = false;
* This mutex protects the access to sTLSKeys, which keeps track of existing
* TLS Keys.
*/
static pthread_mutex_t sTLSKeyLock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t sTLSKeyLock = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
static int sThreadSkipCount = 0;
static thread_info_t *
@ -684,11 +717,9 @@ __wrap_pthread_create(pthread_t *thread,
*/
static void
SaveTLSInfo(thread_info_t *tinfo) {
REAL(pthread_mutex_lock)(&sTLSKeyLock);
MOZ_RELEASE_ASSERT(REAL(pthread_mutex_lock)(&sTLSKeyLock) == 0);
tinfo->tlsInfo.clear();
for (TLSKeySet::const_iterator it = sTLSKeys.begin();
it != sTLSKeys.end();
it++) {
for (TLSKey *it = sTLSKeys.getFirst(); it != nullptr; it = it->getNext()) {
void *value = pthread_getspecific(it->first);
if (value == nullptr) {
continue;
@ -697,7 +728,7 @@ SaveTLSInfo(thread_info_t *tinfo) {
pthread_key_t key = it->first;
tinfo->tlsInfo.push_back(TLSInfoList::value_type(key, value));
}
pthread_mutex_unlock(&sTLSKeyLock);
MOZ_RELEASE_ASSERT(pthread_mutex_unlock(&sTLSKeyLock) == 0);
}
/**
@ -726,9 +757,9 @@ __wrap_pthread_key_create(pthread_key_t *key, void (*destructor)(void*)) {
if (rv != 0) {
return rv;
}
REAL(pthread_mutex_lock)(&sTLSKeyLock);
sTLSKeys.insert(TLSKeySet::value_type(*key, destructor));
pthread_mutex_unlock(&sTLSKeyLock);
MOZ_RELEASE_ASSERT(REAL(pthread_mutex_lock)(&sTLSKeyLock) == 0);
sTLSKeys.insertBack(new TLSKey(*key, destructor));
MOZ_RELEASE_ASSERT(pthread_mutex_unlock(&sTLSKeyLock) == 0);
return 0;
}
@ -741,9 +772,14 @@ __wrap_pthread_key_delete(pthread_key_t key) {
if (rv != 0) {
return rv;
}
REAL(pthread_mutex_lock)(&sTLSKeyLock);
sTLSKeys.erase(key);
pthread_mutex_unlock(&sTLSKeyLock);
MOZ_RELEASE_ASSERT(REAL(pthread_mutex_lock)(&sTLSKeyLock) == 0);
for (TLSKey *it = sTLSKeys.getFirst(); it != nullptr; it = it->getNext()) {
if (key == it->first) {
delete it;
break;
}
}
MOZ_RELEASE_ASSERT(pthread_mutex_unlock(&sTLSKeyLock) == 0);
return 0;
}