123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "nsNSSShutDown.h"
- #include "mozilla/Casting.h"
- #include "nsCOMPtr.h"
- using namespace mozilla;
- extern LazyLogModule gPIPNSSLog;
- struct ObjectHashEntry : PLDHashEntryHdr {
- nsNSSShutDownObject *obj;
- };
- static bool
- ObjectSetMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
- {
- const ObjectHashEntry *entry = static_cast<const ObjectHashEntry*>(hdr);
- return entry->obj == static_cast<const nsNSSShutDownObject*>(key);
- }
- static void
- ObjectSetInitEntry(PLDHashEntryHdr *hdr, const void *key)
- {
- ObjectHashEntry *entry = static_cast<ObjectHashEntry*>(hdr);
- entry->obj = const_cast<nsNSSShutDownObject*>(static_cast<const nsNSSShutDownObject*>(key));
- }
- static const PLDHashTableOps gSetOps = {
- PLDHashTable::HashVoidPtrKeyStub,
- ObjectSetMatchEntry,
- PLDHashTable::MoveEntryStub,
- PLDHashTable::ClearEntryStub,
- ObjectSetInitEntry
- };
- StaticMutex sListLock;
- Atomic<bool> sInShutdown(false);
- nsNSSShutDownList *singleton = nullptr;
- nsNSSShutDownList::nsNSSShutDownList()
- : mObjects(&gSetOps, sizeof(ObjectHashEntry))
- , mPK11LogoutCancelObjects(&gSetOps, sizeof(ObjectHashEntry))
- {
- }
- nsNSSShutDownList::~nsNSSShutDownList()
- {
- PR_ASSERT(this == singleton);
- singleton = nullptr;
- }
- void nsNSSShutDownList::remember(nsNSSShutDownObject *o)
- {
- StaticMutexAutoLock lock(sListLock);
- if (!nsNSSShutDownList::construct(lock)) {
- return;
- }
- PR_ASSERT(o);
- singleton->mObjects.Add(o, fallible);
- }
- void nsNSSShutDownList::forget(nsNSSShutDownObject *o)
- {
- StaticMutexAutoLock lock(sListLock);
- if (!singleton) {
- return;
- }
- PR_ASSERT(o);
- singleton->mObjects.Remove(o);
- }
- void nsNSSShutDownList::remember(nsOnPK11LogoutCancelObject *o)
- {
- StaticMutexAutoLock lock(sListLock);
- if (!nsNSSShutDownList::construct(lock)) {
- return;
- }
- PR_ASSERT(o);
- singleton->mPK11LogoutCancelObjects.Add(o, fallible);
- }
- void nsNSSShutDownList::forget(nsOnPK11LogoutCancelObject *o)
- {
- StaticMutexAutoLock lock(sListLock);
- if (!singleton) {
- return;
- }
- PR_ASSERT(o);
- singleton->mPK11LogoutCancelObjects.Remove(o);
- }
- nsresult nsNSSShutDownList::doPK11Logout()
- {
- StaticMutexAutoLock lock(sListLock);
- if (!singleton) {
- return NS_OK;
- }
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
- ("canceling all open SSL sockets to disallow future IO\n"));
- // During our iteration we will set a bunch of PRBools to true.
- // Nobody else ever modifies that bool, only we do.
- // We only must ensure that our objects do not go away.
- // This is guaranteed by holding the list lock.
- for (auto iter = singleton->mPK11LogoutCancelObjects.Iter();
- !iter.Done();
- iter.Next()) {
- auto entry = static_cast<ObjectHashEntry*>(iter.Get());
- nsOnPK11LogoutCancelObject* pklco =
- BitwiseCast<nsOnPK11LogoutCancelObject*, nsNSSShutDownObject*>(entry->obj);
- if (pklco) {
- pklco->logout();
- }
- }
- return NS_OK;
- }
- nsresult nsNSSShutDownList::evaporateAllNSSResources()
- {
- MOZ_RELEASE_ASSERT(NS_IsMainThread());
- if (!NS_IsMainThread()) {
- return NS_ERROR_NOT_SAME_THREAD;
- }
- StaticMutexAutoLock lock(sListLock);
- // Other threads can acquire an nsNSSShutDownPreventionLock and cause this
- // thread to block when it calls restructActivityToCurrentThread, below. If
- // those other threads then attempt to create an object that must be
- // remembered by the shut down list, they will call
- // nsNSSShutDownList::remember, which attempts to acquire sListLock.
- // Consequently, holding sListLock while we're in
- // restrictActivityToCurrentThread would result in deadlock. sListLock
- // protects the singleton, so if we enforce that the singleton only be created
- // and destroyed on the main thread, and if we similarly enforce that this
- // function is only called on the main thread, what we can do is check that
- // the singleton hasn't already gone away and then we don't actually have to
- // hold sListLock while calling restrictActivityToCurrentThread.
- if (!singleton) {
- return NS_OK;
- }
- {
- StaticMutexAutoUnlock unlock(sListLock);
- PRStatus rv = singleton->mActivityState.restrictActivityToCurrentThread();
- if (rv != PR_SUCCESS) {
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
- ("failed to restrict activity to current thread"));
- return NS_ERROR_FAILURE;
- }
- }
- MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("now evaporating NSS resources"));
- // Never free more than one entry, because other threads might be calling
- // us and remove themselves while we are iterating over the list,
- // and the behaviour of changing the list while iterating is undefined.
- while (singleton) {
- auto iter = singleton->mObjects.Iter();
- if (iter.Done()) {
- break;
- }
- auto entry = static_cast<ObjectHashEntry*>(iter.Get());
- {
- StaticMutexAutoUnlock unlock(sListLock);
- entry->obj->shutdown(nsNSSShutDownObject::ShutdownCalledFrom::List);
- }
- iter.Remove();
- }
- if (!singleton) {
- return NS_ERROR_FAILURE;
- }
- singleton->mActivityState.releaseCurrentThreadActivityRestriction();
- return NS_OK;
- }
- void nsNSSShutDownList::enterActivityState()
- {
- StaticMutexAutoLock lock(sListLock);
- if (nsNSSShutDownList::construct(lock)) {
- singleton->mActivityState.enter();
- }
- }
- void nsNSSShutDownList::leaveActivityState()
- {
- StaticMutexAutoLock lock(sListLock);
- if (singleton) {
- singleton->mActivityState.leave();
- }
- }
- bool nsNSSShutDownList::construct(const StaticMutexAutoLock& /*proofOfLock*/)
- {
- if (!singleton && !sInShutdown && XRE_IsParentProcess()) {
- singleton = new nsNSSShutDownList();
- }
- return !!singleton;
- }
- void nsNSSShutDownList::shutdown()
- {
- MOZ_RELEASE_ASSERT(NS_IsMainThread());
- StaticMutexAutoLock lock(sListLock);
- sInShutdown = true;
- if (singleton) {
- delete singleton;
- }
- }
- nsNSSActivityState::nsNSSActivityState()
- :mNSSActivityStateLock("nsNSSActivityState.mNSSActivityStateLock"),
- mNSSActivityChanged(mNSSActivityStateLock,
- "nsNSSActivityState.mNSSActivityStateLock"),
- mNSSActivityCounter(0),
- mNSSRestrictedThread(nullptr)
- {
- }
- nsNSSActivityState::~nsNSSActivityState()
- {
- }
- void nsNSSActivityState::enter()
- {
- MutexAutoLock lock(mNSSActivityStateLock);
- while (mNSSRestrictedThread && mNSSRestrictedThread != PR_GetCurrentThread()) {
- mNSSActivityChanged.Wait();
- }
- ++mNSSActivityCounter;
- }
- void nsNSSActivityState::leave()
- {
- MutexAutoLock lock(mNSSActivityStateLock);
- --mNSSActivityCounter;
- mNSSActivityChanged.NotifyAll();
- }
- PRStatus nsNSSActivityState::restrictActivityToCurrentThread()
- {
- MutexAutoLock lock(mNSSActivityStateLock);
- while (mNSSActivityCounter > 0) {
- mNSSActivityChanged.Wait(PR_TicksPerSecond());
- }
- mNSSRestrictedThread = PR_GetCurrentThread();
- return PR_SUCCESS;
- }
- void nsNSSActivityState::releaseCurrentThreadActivityRestriction()
- {
- MutexAutoLock lock(mNSSActivityStateLock);
- mNSSRestrictedThread = nullptr;
- mNSSActivityChanged.NotifyAll();
- }
- nsNSSShutDownPreventionLock::nsNSSShutDownPreventionLock()
- {
- nsNSSShutDownList::enterActivityState();
- }
- nsNSSShutDownPreventionLock::~nsNSSShutDownPreventionLock()
- {
- nsNSSShutDownList::leaveActivityState();
- }
|