nsNSSShutDown.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #include "nsNSSShutDown.h"
  5. #include "mozilla/Casting.h"
  6. #include "nsCOMPtr.h"
  7. using namespace mozilla;
  8. extern LazyLogModule gPIPNSSLog;
  9. struct ObjectHashEntry : PLDHashEntryHdr {
  10. nsNSSShutDownObject *obj;
  11. };
  12. static bool
  13. ObjectSetMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
  14. {
  15. const ObjectHashEntry *entry = static_cast<const ObjectHashEntry*>(hdr);
  16. return entry->obj == static_cast<const nsNSSShutDownObject*>(key);
  17. }
  18. static void
  19. ObjectSetInitEntry(PLDHashEntryHdr *hdr, const void *key)
  20. {
  21. ObjectHashEntry *entry = static_cast<ObjectHashEntry*>(hdr);
  22. entry->obj = const_cast<nsNSSShutDownObject*>(static_cast<const nsNSSShutDownObject*>(key));
  23. }
  24. static const PLDHashTableOps gSetOps = {
  25. PLDHashTable::HashVoidPtrKeyStub,
  26. ObjectSetMatchEntry,
  27. PLDHashTable::MoveEntryStub,
  28. PLDHashTable::ClearEntryStub,
  29. ObjectSetInitEntry
  30. };
  31. StaticMutex sListLock;
  32. Atomic<bool> sInShutdown(false);
  33. nsNSSShutDownList *singleton = nullptr;
  34. nsNSSShutDownList::nsNSSShutDownList()
  35. : mObjects(&gSetOps, sizeof(ObjectHashEntry))
  36. , mPK11LogoutCancelObjects(&gSetOps, sizeof(ObjectHashEntry))
  37. {
  38. }
  39. nsNSSShutDownList::~nsNSSShutDownList()
  40. {
  41. PR_ASSERT(this == singleton);
  42. singleton = nullptr;
  43. }
  44. void nsNSSShutDownList::remember(nsNSSShutDownObject *o)
  45. {
  46. StaticMutexAutoLock lock(sListLock);
  47. if (!nsNSSShutDownList::construct(lock)) {
  48. return;
  49. }
  50. PR_ASSERT(o);
  51. singleton->mObjects.Add(o, fallible);
  52. }
  53. void nsNSSShutDownList::forget(nsNSSShutDownObject *o)
  54. {
  55. StaticMutexAutoLock lock(sListLock);
  56. if (!singleton) {
  57. return;
  58. }
  59. PR_ASSERT(o);
  60. singleton->mObjects.Remove(o);
  61. }
  62. void nsNSSShutDownList::remember(nsOnPK11LogoutCancelObject *o)
  63. {
  64. StaticMutexAutoLock lock(sListLock);
  65. if (!nsNSSShutDownList::construct(lock)) {
  66. return;
  67. }
  68. PR_ASSERT(o);
  69. singleton->mPK11LogoutCancelObjects.Add(o, fallible);
  70. }
  71. void nsNSSShutDownList::forget(nsOnPK11LogoutCancelObject *o)
  72. {
  73. StaticMutexAutoLock lock(sListLock);
  74. if (!singleton) {
  75. return;
  76. }
  77. PR_ASSERT(o);
  78. singleton->mPK11LogoutCancelObjects.Remove(o);
  79. }
  80. nsresult nsNSSShutDownList::doPK11Logout()
  81. {
  82. StaticMutexAutoLock lock(sListLock);
  83. if (!singleton) {
  84. return NS_OK;
  85. }
  86. MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
  87. ("canceling all open SSL sockets to disallow future IO\n"));
  88. // During our iteration we will set a bunch of PRBools to true.
  89. // Nobody else ever modifies that bool, only we do.
  90. // We only must ensure that our objects do not go away.
  91. // This is guaranteed by holding the list lock.
  92. for (auto iter = singleton->mPK11LogoutCancelObjects.Iter();
  93. !iter.Done();
  94. iter.Next()) {
  95. auto entry = static_cast<ObjectHashEntry*>(iter.Get());
  96. nsOnPK11LogoutCancelObject* pklco =
  97. BitwiseCast<nsOnPK11LogoutCancelObject*, nsNSSShutDownObject*>(entry->obj);
  98. if (pklco) {
  99. pklco->logout();
  100. }
  101. }
  102. return NS_OK;
  103. }
  104. nsresult nsNSSShutDownList::evaporateAllNSSResources()
  105. {
  106. MOZ_RELEASE_ASSERT(NS_IsMainThread());
  107. if (!NS_IsMainThread()) {
  108. return NS_ERROR_NOT_SAME_THREAD;
  109. }
  110. StaticMutexAutoLock lock(sListLock);
  111. // Other threads can acquire an nsNSSShutDownPreventionLock and cause this
  112. // thread to block when it calls restructActivityToCurrentThread, below. If
  113. // those other threads then attempt to create an object that must be
  114. // remembered by the shut down list, they will call
  115. // nsNSSShutDownList::remember, which attempts to acquire sListLock.
  116. // Consequently, holding sListLock while we're in
  117. // restrictActivityToCurrentThread would result in deadlock. sListLock
  118. // protects the singleton, so if we enforce that the singleton only be created
  119. // and destroyed on the main thread, and if we similarly enforce that this
  120. // function is only called on the main thread, what we can do is check that
  121. // the singleton hasn't already gone away and then we don't actually have to
  122. // hold sListLock while calling restrictActivityToCurrentThread.
  123. if (!singleton) {
  124. return NS_OK;
  125. }
  126. {
  127. StaticMutexAutoUnlock unlock(sListLock);
  128. PRStatus rv = singleton->mActivityState.restrictActivityToCurrentThread();
  129. if (rv != PR_SUCCESS) {
  130. MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
  131. ("failed to restrict activity to current thread"));
  132. return NS_ERROR_FAILURE;
  133. }
  134. }
  135. MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("now evaporating NSS resources"));
  136. // Never free more than one entry, because other threads might be calling
  137. // us and remove themselves while we are iterating over the list,
  138. // and the behaviour of changing the list while iterating is undefined.
  139. while (singleton) {
  140. auto iter = singleton->mObjects.Iter();
  141. if (iter.Done()) {
  142. break;
  143. }
  144. auto entry = static_cast<ObjectHashEntry*>(iter.Get());
  145. {
  146. StaticMutexAutoUnlock unlock(sListLock);
  147. entry->obj->shutdown(nsNSSShutDownObject::ShutdownCalledFrom::List);
  148. }
  149. iter.Remove();
  150. }
  151. if (!singleton) {
  152. return NS_ERROR_FAILURE;
  153. }
  154. singleton->mActivityState.releaseCurrentThreadActivityRestriction();
  155. return NS_OK;
  156. }
  157. void nsNSSShutDownList::enterActivityState()
  158. {
  159. StaticMutexAutoLock lock(sListLock);
  160. if (nsNSSShutDownList::construct(lock)) {
  161. singleton->mActivityState.enter();
  162. }
  163. }
  164. void nsNSSShutDownList::leaveActivityState()
  165. {
  166. StaticMutexAutoLock lock(sListLock);
  167. if (singleton) {
  168. singleton->mActivityState.leave();
  169. }
  170. }
  171. bool nsNSSShutDownList::construct(const StaticMutexAutoLock& /*proofOfLock*/)
  172. {
  173. if (!singleton && !sInShutdown && XRE_IsParentProcess()) {
  174. singleton = new nsNSSShutDownList();
  175. }
  176. return !!singleton;
  177. }
  178. void nsNSSShutDownList::shutdown()
  179. {
  180. MOZ_RELEASE_ASSERT(NS_IsMainThread());
  181. StaticMutexAutoLock lock(sListLock);
  182. sInShutdown = true;
  183. if (singleton) {
  184. delete singleton;
  185. }
  186. }
  187. nsNSSActivityState::nsNSSActivityState()
  188. :mNSSActivityStateLock("nsNSSActivityState.mNSSActivityStateLock"),
  189. mNSSActivityChanged(mNSSActivityStateLock,
  190. "nsNSSActivityState.mNSSActivityStateLock"),
  191. mNSSActivityCounter(0),
  192. mNSSRestrictedThread(nullptr)
  193. {
  194. }
  195. nsNSSActivityState::~nsNSSActivityState()
  196. {
  197. }
  198. void nsNSSActivityState::enter()
  199. {
  200. MutexAutoLock lock(mNSSActivityStateLock);
  201. while (mNSSRestrictedThread && mNSSRestrictedThread != PR_GetCurrentThread()) {
  202. mNSSActivityChanged.Wait();
  203. }
  204. ++mNSSActivityCounter;
  205. }
  206. void nsNSSActivityState::leave()
  207. {
  208. MutexAutoLock lock(mNSSActivityStateLock);
  209. --mNSSActivityCounter;
  210. mNSSActivityChanged.NotifyAll();
  211. }
  212. PRStatus nsNSSActivityState::restrictActivityToCurrentThread()
  213. {
  214. MutexAutoLock lock(mNSSActivityStateLock);
  215. while (mNSSActivityCounter > 0) {
  216. mNSSActivityChanged.Wait(PR_TicksPerSecond());
  217. }
  218. mNSSRestrictedThread = PR_GetCurrentThread();
  219. return PR_SUCCESS;
  220. }
  221. void nsNSSActivityState::releaseCurrentThreadActivityRestriction()
  222. {
  223. MutexAutoLock lock(mNSSActivityStateLock);
  224. mNSSRestrictedThread = nullptr;
  225. mNSSActivityChanged.NotifyAll();
  226. }
  227. nsNSSShutDownPreventionLock::nsNSSShutDownPreventionLock()
  228. {
  229. nsNSSShutDownList::enterActivityState();
  230. }
  231. nsNSSShutDownPreventionLock::~nsNSSShutDownPreventionLock()
  232. {
  233. nsNSSShutDownList::leaveActivityState();
  234. }