diff options
Diffstat (limited to 'xpcom/base/RLBoxSandboxPool.cpp')
-rw-r--r-- | xpcom/base/RLBoxSandboxPool.cpp | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/xpcom/base/RLBoxSandboxPool.cpp b/xpcom/base/RLBoxSandboxPool.cpp new file mode 100644 index 0000000000..5cee3406ea --- /dev/null +++ b/xpcom/base/RLBoxSandboxPool.cpp @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "nsThreadUtils.h" +#include "mozilla/ClearOnShutdown.h" +#include "mozilla/DebugOnly.h" +#include "mozilla/RLBoxSandboxPool.h" +#ifdef MOZ_USING_WASM_SANDBOXING +# include "mozilla/rlbox/rlbox_config.h" +# include "mozilla/rlbox/rlbox_wasm2c_sandbox.hpp" +#endif + +using namespace mozilla; + +NS_IMPL_ISUPPORTS(RLBoxSandboxPool, nsITimerCallback, nsINamed) + +void RLBoxSandboxPool::StartTimer() { + mMutex.AssertCurrentThreadOwns(); + MOZ_ASSERT(!mTimer, "timer already initialized"); + if (NS_IsMainThread() && + PastShutdownPhase(ShutdownPhase::AppShutdownConfirmed)) { + // If we're shutting down, setting the time might fail, and we don't need it + // (since all the memory will be cleaned up soon anyway). Note that + // PastShutdownPhase() can only be called on the main thread, but that's + // fine, because other threads will have joined already by the point timers + // start failing to register. + mPool.Clear(); + return; + } + DebugOnly<nsresult> rv = NS_NewTimerWithCallback( + getter_AddRefs(mTimer), this, mDelaySeconds * 1000, + nsITimer::TYPE_ONE_SHOT, GetMainThreadEventTarget()); + MOZ_ASSERT(NS_SUCCEEDED(rv), "failed to create timer"); +} + +void RLBoxSandboxPool::CancelTimer() { + mMutex.AssertCurrentThreadOwns(); + if (mTimer) { + mTimer->Cancel(); + mTimer = nullptr; + } +} + +NS_IMETHODIMP RLBoxSandboxPool::Notify(nsITimer* aTimer) { + MutexAutoLock lock(mMutex); + + mPool.Clear(); + mTimer = nullptr; + + return NS_OK; +} + +NS_IMETHODIMP RLBoxSandboxPool::GetName(nsACString& aName) { + aName.AssignLiteral("RLBoxSandboxPool"); + return NS_OK; +} + +void RLBoxSandboxPool::Push(UniquePtr<RLBoxSandboxDataBase> sbxData) { + MutexAutoLock lock(mMutex); + + mPool.AppendElement(std::move(sbxData)); + if (!mTimer) { + StartTimer(); + } +} + +UniquePtr<RLBoxSandboxPoolData> RLBoxSandboxPool::PopOrCreate( + uint64_t aMinSize) { + MutexAutoLock lock(mMutex); + + UniquePtr<RLBoxSandboxDataBase> sbxData; + + if (!mPool.IsEmpty()) { + const int64_t lastIndex = ReleaseAssertedCast<int64_t>(mPool.Length()) - 1; + for (int64_t i = lastIndex; i >= 0; i--) { + if (mPool[i]->mSize >= aMinSize) { + sbxData = std::move(mPool[i]); + mPool.RemoveElementAt(i); + + // If we reuse a sandbox from the pool, reset the timer to clear the + // pool + CancelTimer(); + if (!mPool.IsEmpty()) { + StartTimer(); + } + break; + } + } + } + + if (!sbxData) { +#ifdef MOZ_USING_WASM_SANDBOXING + // RLBox's wasm sandboxes have a limited platform dependent capacity. We + // track this capacity in this pool. Note the noop sandboxes have no + // capacity limit but this design assumes that all sandboxes use the wasm + // sandbox limit. + const uint64_t defaultCapacityForSandbox = + wasm_rt_get_default_max_linear_memory_size(); + const uint64_t minSandboxCapacity = + std::max(aMinSize, defaultCapacityForSandbox); + const uint64_t chosenAdjustedCapacity = + rlbox::rlbox_wasm2c_sandbox::rlbox_wasm2c_get_adjusted_heap_size( + minSandboxCapacity); +#else + // If sandboxing is disabled altogether we just set a limit of 4gb. + // This is not actually enforced by the noop sandbox. + const uint64_t chosenAdjustedCapacity = static_cast<uint64_t>(1) << 32; +#endif + sbxData = CreateSandboxData(chosenAdjustedCapacity); + NS_ENSURE_TRUE(sbxData, nullptr); + } + + return MakeUnique<RLBoxSandboxPoolData>(std::move(sbxData), this); +} |