mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
a13d595ddb
There are multiple defects in NetworkWorker and the related parts since the C++ rewrite. 1) NetworkService holds a reference to NetworkWorker and never releases it. It has to wait until the cycle collector comes up to resolve their ownership loop and free NetworkWorker manually. However 2) nsINetworkWorker::shutdown is never called, and that leaves everything living till the end, inclusive of that gNetdConsumer in Netd.cpp. 3) when GC comes to free NetworkWorker, it calls its parent destructor ~NetConsumer(), which in turn calls ~RefCounted<NetdConsumer>(). Having a valid gNetdConsumer in Netd.cpp follows its refCnt is not zero and this triggers an assertion in ~RefCounted<NetdConsumer>(). So, some obvious treatments here. A) NetworkService should call nsINetworkWorker::shutdown upon receiving a shutdown observer event and release the reference to NetworkWorker. B) NetworkWorker should never be double ref-counted. Move NetdConsumer implementation into a separated class.
288 lines
6.3 KiB
C++
288 lines
6.3 KiB
C++
/* 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 "NetworkWorker.h"
|
|
#include "NetworkUtils.h"
|
|
#include <nsThreadUtils.h>
|
|
#include "mozilla/ModuleUtils.h"
|
|
#include "mozilla/ClearOnShutdown.h"
|
|
#include "nsXULAppAPI.h"
|
|
#include "nsCxPusher.h"
|
|
|
|
#define NS_NETWORKWORKER_CID \
|
|
{ 0x6df093e1, 0x8127, 0x4fa7, {0x90, 0x13, 0xa3, 0xaa, 0xa7, 0x79, 0xbb, 0xdd} }
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::dom;
|
|
using namespace mozilla::ipc;
|
|
|
|
namespace mozilla {
|
|
|
|
nsCOMPtr<nsIThread> gWorkerThread;
|
|
|
|
// The singleton network worker, to be used on the main thread.
|
|
StaticRefPtr<NetworkWorker> gNetworkWorker;
|
|
|
|
// The singleton networkutils class, that can be used on any thread.
|
|
static nsAutoPtr<NetworkUtils> gNetworkUtils;
|
|
|
|
// Runnable used dispatch command result on the main thread.
|
|
class NetworkResultDispatcher : public nsRunnable
|
|
{
|
|
public:
|
|
NetworkResultDispatcher(const NetworkResultOptions& aResult)
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
#define COPY_FIELD(prop) mResult.prop = aResult.prop;
|
|
COPY_FIELD(mId)
|
|
COPY_FIELD(mRet)
|
|
COPY_FIELD(mBroadcast)
|
|
COPY_FIELD(mTopic)
|
|
COPY_FIELD(mReason)
|
|
COPY_FIELD(mResultCode)
|
|
COPY_FIELD(mResultReason)
|
|
COPY_FIELD(mError)
|
|
COPY_FIELD(mRxBytes)
|
|
COPY_FIELD(mTxBytes)
|
|
COPY_FIELD(mDate)
|
|
COPY_FIELD(mEnable)
|
|
COPY_FIELD(mResult)
|
|
COPY_FIELD(mSuccess)
|
|
COPY_FIELD(mCurExternalIfname)
|
|
COPY_FIELD(mCurInternalIfname)
|
|
#undef COPY_FIELD
|
|
}
|
|
|
|
NS_IMETHOD Run()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (gNetworkWorker) {
|
|
gNetworkWorker->DispatchNetworkResult(mResult);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
private:
|
|
NetworkResultOptions mResult;
|
|
};
|
|
|
|
// Runnable used dispatch netd command on the worker thread.
|
|
class NetworkCommandDispatcher : public nsRunnable
|
|
{
|
|
public:
|
|
NetworkCommandDispatcher(const NetworkParams& aParams)
|
|
: mParams(aParams)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
}
|
|
|
|
NS_IMETHOD Run()
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
if (gNetworkUtils) {
|
|
gNetworkUtils->ExecuteCommand(mParams);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
private:
|
|
NetworkParams mParams;
|
|
};
|
|
|
|
// Runnable used dispatch netd result on the worker thread.
|
|
class NetdEventRunnable : public nsRunnable
|
|
{
|
|
public:
|
|
NetdEventRunnable(NetdCommand* aCommand)
|
|
: mCommand(aCommand)
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
}
|
|
|
|
NS_IMETHOD Run()
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
if (gNetworkUtils) {
|
|
gNetworkUtils->onNetdMessage(mCommand);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
nsAutoPtr<NetdCommand> mCommand;
|
|
};
|
|
|
|
class NetdMessageConsumer : public NetdConsumer
|
|
{
|
|
public:
|
|
NetdMessageConsumer()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
}
|
|
|
|
void MessageReceived(NetdCommand* aCommand)
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
nsCOMPtr<nsIRunnable> runnable = new NetdEventRunnable(aCommand);
|
|
if (gWorkerThread) {
|
|
gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
|
|
}
|
|
}
|
|
};
|
|
|
|
NS_IMPL_ISUPPORTS1(NetworkWorker, nsINetworkWorker)
|
|
|
|
NetworkWorker::NetworkWorker()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(!gNetworkWorker);
|
|
}
|
|
|
|
NetworkWorker::~NetworkWorker()
|
|
{
|
|
MOZ_ASSERT(!gNetworkWorker);
|
|
MOZ_ASSERT(!mListener);
|
|
}
|
|
|
|
already_AddRefed<NetworkWorker>
|
|
NetworkWorker::FactoryCreate()
|
|
{
|
|
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
|
return nullptr;
|
|
}
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (!gNetworkWorker) {
|
|
gNetworkWorker = new NetworkWorker();
|
|
ClearOnShutdown(&gNetworkWorker);
|
|
|
|
gNetworkUtils = new NetworkUtils(NetworkWorker::NotifyResult);
|
|
ClearOnShutdown(&gNetworkUtils);
|
|
}
|
|
|
|
nsRefPtr<NetworkWorker> worker = gNetworkWorker.get();
|
|
return worker.forget();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
NetworkWorker::Start(nsINetworkEventListener* aListener)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(aListener);
|
|
|
|
if (mListener) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult rv;
|
|
|
|
rv = NS_NewNamedThread("NetworkWorker", getter_AddRefs(gWorkerThread));
|
|
if (NS_FAILED(rv)) {
|
|
NS_WARNING("Can't create network control thread");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
StartNetd(new NetdMessageConsumer());
|
|
mListener = aListener;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
NetworkWorker::Shutdown()
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (!mListener) {
|
|
return NS_OK;
|
|
}
|
|
|
|
StopNetd();
|
|
|
|
gWorkerThread->Shutdown();
|
|
gWorkerThread = nullptr;
|
|
|
|
mListener = nullptr;
|
|
return NS_OK;
|
|
}
|
|
|
|
// Receive command from main thread (NetworkService.js).
|
|
NS_IMETHODIMP
|
|
NetworkWorker::PostMessage(JS::Handle<JS::Value> aOptions, JSContext* aCx)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
NetworkCommandOptions options;
|
|
if (!options.Init(aCx, aOptions)) {
|
|
NS_WARNING("Bad dictionary passed to NetworkWorker::SendCommand");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
// Dispatch the command to the control thread.
|
|
NetworkParams NetworkParams(options);
|
|
nsCOMPtr<nsIRunnable> runnable = new NetworkCommandDispatcher(NetworkParams);
|
|
if (gWorkerThread) {
|
|
gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
NetworkWorker::DispatchNetworkResult(const NetworkResultOptions& aOptions)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
mozilla::AutoSafeJSContext cx;
|
|
JS::RootedValue val(cx);
|
|
|
|
if (!aOptions.ToObject(cx, &val)) {
|
|
return;
|
|
}
|
|
|
|
// Call the listener with a JS value.
|
|
if (mListener) {
|
|
mListener->OnEvent(val);
|
|
}
|
|
}
|
|
|
|
// Callback function from network worker thread to update result on main thread.
|
|
void
|
|
NetworkWorker::NotifyResult(NetworkResultOptions& aResult)
|
|
{
|
|
MOZ_ASSERT(!NS_IsMainThread());
|
|
|
|
nsCOMPtr<nsIRunnable> runnable = new NetworkResultDispatcher(aResult);
|
|
NS_DispatchToMainThread(runnable);
|
|
}
|
|
|
|
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(NetworkWorker,
|
|
NetworkWorker::FactoryCreate)
|
|
|
|
NS_DEFINE_NAMED_CID(NS_NETWORKWORKER_CID);
|
|
|
|
static const mozilla::Module::CIDEntry kNetworkWorkerCIDs[] = {
|
|
{ &kNS_NETWORKWORKER_CID, false, nullptr, NetworkWorkerConstructor },
|
|
{ nullptr }
|
|
};
|
|
|
|
static const mozilla::Module::ContractIDEntry kNetworkWorkerContracts[] = {
|
|
{ "@mozilla.org/network/worker;1", &kNS_NETWORKWORKER_CID },
|
|
{ nullptr }
|
|
};
|
|
|
|
static const mozilla::Module kNetworkWorkerModule = {
|
|
mozilla::Module::kVersion,
|
|
kNetworkWorkerCIDs,
|
|
kNetworkWorkerContracts,
|
|
nullptr
|
|
};
|
|
|
|
} // namespace mozilla
|
|
|
|
NSMODULE_DEFN(NetworkWorkerModule) = &kNetworkWorkerModule;
|