forked from mirrors/gecko-dev
Using ipc::Shmem causes unbounded shmem use growth until e.g. a Worker yields to the event loop. If a Worker never yields, Shmems sent to WebGLParent are never released. Specifically the manager (PCanvasManager) for WebGLParent calls DestroySharedMemory, which sends/enqueues for WebGLChild's manager a matching call to ShmemDestroyed. However, while WebGLChild refuses to spin its event loop (such as a no-return WASM Worker), the ShmemDestroyed events will just pile up. Closing e.g. the tab frees the shmems, but they accumulate unbounded until the Worker yields to the event loop. This is true for other users of ipc::Shmem (or RaiiShmem) as well, but entrypoints other than DispatchCommands are rarer and can be handled later similarly. Differential Revision: https://phabricator.services.mozilla.com/D162946
109 lines
3.5 KiB
C++
109 lines
3.5 KiB
C++
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* 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 "WebGLChild.h"
|
|
|
|
#include "ClientWebGLContext.h"
|
|
#include "mozilla/StaticPrefs_webgl.h"
|
|
#include "WebGLMethodDispatcher.h"
|
|
|
|
namespace mozilla::dom {
|
|
|
|
WebGLChild::WebGLChild(ClientWebGLContext& context)
|
|
: mContext(&context),
|
|
mDefaultCmdsShmemSize(StaticPrefs::webgl_out_of_process_shmem_size()) {}
|
|
|
|
WebGLChild::~WebGLChild() { (void)Send__delete__(this); }
|
|
|
|
void WebGLChild::ActorDestroy(ActorDestroyReason why) {
|
|
mPendingCmdsShmem = {};
|
|
}
|
|
|
|
// -
|
|
|
|
Maybe<Range<uint8_t>> WebGLChild::AllocPendingCmdBytes(
|
|
const size_t size, const size_t fyiAlignmentOverhead) {
|
|
if (!mPendingCmdsShmem.Size()) {
|
|
size_t capacity = mDefaultCmdsShmemSize;
|
|
if (capacity < size) {
|
|
capacity = size;
|
|
}
|
|
|
|
mPendingCmdsShmem = mozilla::ipc::BigBuffer::TryAlloc(capacity);
|
|
if (!mPendingCmdsShmem.Size()) {
|
|
NS_WARNING("Failed to alloc shmem for AllocPendingCmdBytes.");
|
|
return {};
|
|
}
|
|
mPendingCmdsPos = 0;
|
|
mPendingCmdsAlignmentOverhead = 0;
|
|
|
|
if (kIsDebug) {
|
|
const auto ptr = mPendingCmdsShmem.Data();
|
|
const auto initialOffset = AlignmentOffset(kUniversalAlignment, ptr);
|
|
MOZ_ALWAYS_TRUE(!initialOffset);
|
|
}
|
|
}
|
|
|
|
const auto range = Range<uint8_t>{mPendingCmdsShmem.AsSpan()};
|
|
|
|
auto itr = range.begin() + mPendingCmdsPos;
|
|
const auto offset = AlignmentOffset(kUniversalAlignment, itr.get());
|
|
mPendingCmdsPos += offset;
|
|
mPendingCmdsAlignmentOverhead += offset;
|
|
const auto required = mPendingCmdsPos + size;
|
|
if (required > range.length()) {
|
|
FlushPendingCmds();
|
|
return AllocPendingCmdBytes(size, fyiAlignmentOverhead);
|
|
}
|
|
itr = range.begin() + mPendingCmdsPos;
|
|
const auto remaining = Range<uint8_t>{itr, range.end()};
|
|
mPendingCmdsPos += size;
|
|
mPendingCmdsAlignmentOverhead += fyiAlignmentOverhead;
|
|
return Some(Range<uint8_t>{remaining.begin(), remaining.begin() + size});
|
|
}
|
|
|
|
void WebGLChild::FlushPendingCmds() {
|
|
if (!mPendingCmdsShmem.Size()) return;
|
|
|
|
const auto byteSize = mPendingCmdsPos;
|
|
SendDispatchCommands(std::move(mPendingCmdsShmem), byteSize);
|
|
mPendingCmdsShmem = {};
|
|
|
|
mFlushedCmdInfo.flushes += 1;
|
|
mFlushedCmdInfo.flushedCmdBytes += byteSize;
|
|
mFlushedCmdInfo.overhead += mPendingCmdsAlignmentOverhead;
|
|
|
|
if (gl::GLContext::ShouldSpew()) {
|
|
const auto overheadRatio = float(mPendingCmdsAlignmentOverhead) /
|
|
(byteSize - mPendingCmdsAlignmentOverhead);
|
|
const auto totalOverheadRatio =
|
|
float(mFlushedCmdInfo.overhead) /
|
|
(mFlushedCmdInfo.flushedCmdBytes - mFlushedCmdInfo.overhead);
|
|
printf_stderr(
|
|
"[WebGLChild] Flushed %zu (%zu=%.2f%% overhead) bytes."
|
|
" (%zu (%.2f%% overhead) over %zu flushes)\n",
|
|
byteSize, mPendingCmdsAlignmentOverhead, 100 * overheadRatio,
|
|
mFlushedCmdInfo.flushedCmdBytes, 100 * totalOverheadRatio,
|
|
mFlushedCmdInfo.flushes);
|
|
}
|
|
}
|
|
|
|
// -
|
|
|
|
mozilla::ipc::IPCResult WebGLChild::RecvJsWarning(
|
|
const std::string& text) const {
|
|
if (!mContext) return IPC_OK();
|
|
mContext->JsWarning(text);
|
|
return IPC_OK();
|
|
}
|
|
|
|
mozilla::ipc::IPCResult WebGLChild::RecvOnContextLoss(
|
|
const webgl::ContextLossReason reason) const {
|
|
if (!mContext) return IPC_OK();
|
|
mContext->OnContextLoss(reason);
|
|
return IPC_OK();
|
|
}
|
|
|
|
} // namespace mozilla::dom
|