Backed out 10 changesets (bug 1803810) for xpcshell failures on test_import_global...
[gecko.git] / netwerk / ipc / ProxyAutoConfigChild.cpp
blob1ab78c65e35f47bf02466963c76f03e350f7e3e4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "ProxyAutoConfigChild.h"
8 #include "mozilla/ipc/Endpoint.h"
9 #include "mozilla/net/SocketProcessChild.h"
10 #include "mozilla/SpinEventLoopUntil.h"
11 #include "nsIObserver.h"
12 #include "nsIObserverService.h"
13 #include "nsThreadUtils.h"
14 #include "ProxyAutoConfig.h"
16 namespace mozilla::net {
18 static bool sThreadLocalSetup = false;
19 static uint32_t sThreadLocalIndex = 0xdeadbeef;
20 StaticRefPtr<nsIThread> ProxyAutoConfigChild::sPACThread;
21 bool ProxyAutoConfigChild::sShutdownObserverRegistered = false;
22 static StaticRefPtr<ProxyAutoConfigChild> sActor;
24 namespace {
26 class ShutdownObserver final : public nsIObserver {
27 public:
28 ShutdownObserver() = default;
30 NS_DECL_ISUPPORTS
31 NS_DECL_NSIOBSERVER
33 private:
34 ~ShutdownObserver() = default;
37 NS_IMPL_ISUPPORTS(ShutdownObserver, nsIObserver)
39 NS_IMETHODIMP
40 ShutdownObserver::Observe(nsISupports* aSubject, const char* aTopic,
41 const char16_t* aData) {
42 ProxyAutoConfigChild::ShutdownPACThread();
43 return NS_OK;
46 } // namespace
48 // static
49 void ProxyAutoConfigChild::BindProxyAutoConfigChild(
50 RefPtr<ProxyAutoConfigChild>&& aActor,
51 Endpoint<PProxyAutoConfigChild>&& aEndpoint) {
52 // We only allow one ProxyAutoConfigChild at a time, so we need to
53 // wait until the old one to be destroyed.
54 if (sActor) {
55 NS_DispatchToCurrentThread(NS_NewRunnableFunction(
56 "BindProxyAutoConfigChild",
57 [actor = std::move(aActor), endpoint = std::move(aEndpoint)]() mutable {
58 ProxyAutoConfigChild::BindProxyAutoConfigChild(std::move(actor),
59 std::move(endpoint));
60 }));
61 return;
64 if (aEndpoint.Bind(aActor)) {
65 sActor = aActor;
69 // static
70 bool ProxyAutoConfigChild::Create(Endpoint<PProxyAutoConfigChild>&& aEndpoint) {
71 if (!sPACThread && !CreatePACThread()) {
72 NS_WARNING("Failed to create pac thread!");
73 return false;
76 if (!sShutdownObserverRegistered) {
77 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
78 if (NS_WARN_IF(!obs)) {
79 return false;
81 nsCOMPtr<nsIObserver> observer = new ShutdownObserver();
82 nsresult rv = obs->AddObserver(observer, "xpcom-shutdown-threads", false);
83 if (NS_WARN_IF(NS_FAILED(rv))) {
84 return false;
86 sShutdownObserverRegistered = true;
89 RefPtr<ProxyAutoConfigChild> actor = new ProxyAutoConfigChild();
90 if (NS_FAILED(sPACThread->Dispatch(NS_NewRunnableFunction(
91 "ProxyAutoConfigChild::ProxyAutoConfigChild",
92 [actor = std::move(actor),
93 endpoint = std::move(aEndpoint)]() mutable {
94 MOZ_ASSERT(endpoint.IsValid());
95 ProxyAutoConfigChild::BindProxyAutoConfigChild(std::move(actor),
96 std::move(endpoint));
97 })))) {
98 NS_WARNING("Failed to dispatch runnable!");
99 return false;
102 return true;
105 // static
106 bool ProxyAutoConfigChild::CreatePACThread() {
107 MOZ_ASSERT(NS_IsMainThread());
109 if (SocketProcessChild::GetSingleton()->IsShuttingDown()) {
110 NS_WARNING("Trying to create pac thread after shutdown has already begun!");
111 return false;
114 nsCOMPtr<nsIThread> thread;
115 if (NS_FAILED(NS_NewNamedThread("ProxyResolution", getter_AddRefs(thread)))) {
116 NS_WARNING("NS_NewNamedThread failed!");
117 return false;
120 sPACThread = thread.forget();
121 return true;
124 // static
125 void ProxyAutoConfigChild::ShutdownPACThread() {
126 MOZ_ASSERT(NS_IsMainThread());
128 if (sPACThread) {
129 // Wait until all actos are released.
130 SpinEventLoopUntil("ProxyAutoConfigChild::ShutdownPACThread"_ns,
131 [&]() { return !sActor; });
133 nsCOMPtr<nsIThread> thread = sPACThread.get();
134 sPACThread = nullptr;
135 MOZ_ALWAYS_SUCCEEDS(thread->Shutdown());
139 ProxyAutoConfigChild::ProxyAutoConfigChild()
140 : mPAC(MakeUnique<ProxyAutoConfig>()) {
141 if (!sThreadLocalSetup) {
142 sThreadLocalSetup = true;
143 PR_NewThreadPrivateIndex(&sThreadLocalIndex, nullptr);
146 mPAC->SetThreadLocalIndex(sThreadLocalIndex);
149 ProxyAutoConfigChild::~ProxyAutoConfigChild() = default;
151 mozilla::ipc::IPCResult ProxyAutoConfigChild::RecvConfigurePAC(
152 const nsACString& aPACURI, const nsACString& aPACScriptData,
153 const bool& aIncludePath, const uint32_t& aExtraHeapSize) {
154 mPAC->ConfigurePAC(aPACURI, aPACScriptData, aIncludePath, aExtraHeapSize,
155 GetMainThreadSerialEventTarget());
156 mPACLoaded = true;
157 NS_DispatchToCurrentThread(
158 NewRunnableMethod("ProxyAutoConfigChild::ProcessPendingQ", this,
159 &ProxyAutoConfigChild::ProcessPendingQ));
160 return IPC_OK();
163 void ProxyAutoConfigChild::PendingQuery::Resolve(nsresult aStatus,
164 const nsACString& aResult) {
165 mResolver(std::tuple<const nsresult&, const nsACString&>(aStatus, aResult));
168 mozilla::ipc::IPCResult ProxyAutoConfigChild::RecvGetProxyForURI(
169 const nsACString& aTestURI, const nsACString& aTestHost,
170 GetProxyForURIResolver&& aResolver) {
171 mPendingQ.insertBack(
172 new PendingQuery(aTestURI, aTestHost, std::move(aResolver)));
173 ProcessPendingQ();
174 return IPC_OK();
177 void ProxyAutoConfigChild::ProcessPendingQ() {
178 while (ProcessPending()) {
182 if (mShutdown) {
183 mPAC->Shutdown();
184 } else {
185 // do GC while the thread has nothing pending
186 mPAC->GC();
190 bool ProxyAutoConfigChild::ProcessPending() {
191 if (mPendingQ.isEmpty()) {
192 return false;
195 if (mInProgress || !mPACLoaded) {
196 return false;
199 if (mShutdown) {
200 return true;
203 mInProgress = true;
204 RefPtr<PendingQuery> query = mPendingQ.popFirst();
205 nsCString result;
206 nsresult rv = mPAC->GetProxyForURI(query->URI(), query->Host(), result);
207 query->Resolve(rv, result);
208 mInProgress = false;
209 return true;
212 void ProxyAutoConfigChild::ActorDestroy(ActorDestroyReason aWhy) {
213 mPendingQ.clear();
214 mShutdown = true;
215 mPAC->Shutdown();
217 // To avoid racing with the main thread, we need to dispatch
218 // ProxyAutoConfigChild::Destroy again.
219 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(NewNonOwningRunnableMethod(
220 "ProxyAutoConfigChild::Destroy", this, &ProxyAutoConfigChild::Destroy)));
223 void ProxyAutoConfigChild::Destroy() { sActor = nullptr; }
225 } // namespace mozilla::net