Change reclaimer function signature (#27649)

* Fix fuzzer found leak in memory_quota

* Make reclamation functions know about cancellation

* fixes

* fix race

* Automated change: Fix sanity tests

* fixes

* Automated change: Fix sanity tests

Co-authored-by: ctiller <ctiller@users.noreply.github.com>
pull/27659/head
Craig Tiller 3 years ago committed by GitHub
parent 6f2021c48f
commit 016ef6cede
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      build_autogenerated.yaml
  2. 29
      src/core/lib/resource_quota/memory_quota.cc
  3. 10
      src/core/lib/resource_quota/memory_quota.h
  4. 12
      test/core/resource_quota/BUILD
  5. 52
      test/core/resource_quota/call_checker.h
  6. 32
      test/core/resource_quota/memory_quota_fuzzer.cc
  7. 859
      test/core/resource_quota/memory_quota_fuzzer_corpus/testcase-4574576847224832
  8. 9
      test/core/resource_quota/memory_quota_fuzzer_corpus/testcase-4574576847224832-after-creduce
  9. 5
      test/core/resource_quota/memory_quota_stress_test.cc
  10. 53
      test/core/resource_quota/memory_quota_test.cc

@ -6516,6 +6516,7 @@ targets:
- src/core/lib/slice/slice_string_helpers.h
- src/core/lib/slice/slice_utils.h
- src/core/lib/slice/static_slice.h
- test/core/resource_quota/call_checker.h
src:
- src/core/lib/debug/trace.cc
- src/core/lib/event_engine/memory_allocator.cc

@ -50,9 +50,11 @@ const ReclaimerQueue::Index ReclaimerQueue::kInvalidIndex;
void ReclaimerQueue::Insert(
std::shared_ptr<EventEngineMemoryAllocatorImpl> allocator,
ReclamationFunction reclaimer, Index* index) {
MutexLock lock(&mu_);
ReleasableMutexLock lock(&mu_);
if (*index < entries_.size() && entries_[*index].allocator == allocator) {
entries_[*index].reclaimer.swap(reclaimer);
lock.Release();
reclaimer({});
return;
}
if (free_entries_.empty()) {
@ -115,11 +117,21 @@ GrpcMemoryAllocatorImpl::~GrpcMemoryAllocatorImpl() {
}
void GrpcMemoryAllocatorImpl::Shutdown() {
ReclamationFunction old_reclaimers[kNumReclamationPasses];
MutexLock lock(&memory_quota_mu_);
std::shared_ptr<BasicMemoryQuota> memory_quota;
ReclaimerQueue::Index reclamation_indices[kNumReclamationPasses];
{
MutexLock lock(&memory_quota_mu_);
GPR_ASSERT(!shutdown_);
shutdown_ = true;
memory_quota = memory_quota_;
for (size_t i = 0; i < kNumReclamationPasses; i++) {
reclamation_indices[i] = absl::exchange(reclamation_indices_[i],
ReclaimerQueue::kInvalidIndex);
}
}
for (size_t i = 0; i < kNumReclamationPasses; i++) {
old_reclaimers[i] =
memory_quota_->CancelReclaimer(i, reclamation_indices_[i], this);
auto fn = memory_quota->CancelReclaimer(i, reclamation_indices[i], this);
if (fn != nullptr) fn({});
}
}
@ -180,6 +192,7 @@ absl::optional<size_t> GrpcMemoryAllocatorImpl::TryReserve(
void GrpcMemoryAllocatorImpl::Replenish() {
MutexLock lock(&memory_quota_mu_);
GPR_ASSERT(!shutdown_);
// Attempt a fairly low rate exponential growth request size, bounded between
// some reasonable limits declared at top of file.
auto amount = Clamp(taken_bytes_ / 3, kMinReplenishBytes, kMaxReplenishBytes);
@ -201,11 +214,13 @@ void GrpcMemoryAllocatorImpl::MaybeRegisterReclaimer() {
void GrpcMemoryAllocatorImpl::MaybeRegisterReclaimerLocked() {
// If the reclaimer is already registered, then there's nothing to do.
if (reclamation_indices_[0] != ReclaimerQueue::kInvalidIndex) return;
if (shutdown_) return;
// Grab references to the things we'll need
auto self = shared_from_this();
memory_quota_->InsertReclaimer(
0, self,
[self](ReclamationSweep) {
[self](absl::optional<ReclamationSweep> sweep) {
if (!sweep.has_value()) return;
auto* p = static_cast<GrpcMemoryAllocatorImpl*>(self.get());
MutexLock lock(&p->memory_quota_mu_);
// Figure out how many bytes we can return to the quota.
@ -223,6 +238,7 @@ void GrpcMemoryAllocatorImpl::MaybeRegisterReclaimerLocked() {
void GrpcMemoryAllocatorImpl::Rebind(
std::shared_ptr<BasicMemoryQuota> memory_quota) {
MutexLock lock(&memory_quota_mu_);
GPR_ASSERT(!shutdown_);
if (memory_quota_ == memory_quota) return;
// Return memory to the original memory quota.
memory_quota_->Return(taken_bytes_);
@ -252,6 +268,7 @@ void GrpcMemoryAllocatorImpl::Rebind(
void GrpcMemoryAllocatorImpl::PostReclaimer(ReclamationPass pass,
ReclamationFunction fn) {
MutexLock lock(&memory_quota_mu_);
GPR_ASSERT(!shutdown_);
auto pass_num = static_cast<size_t>(pass);
memory_quota_->InsertReclaimer(pass_num, shared_from_this(), std::move(fn),
&reclamation_indices_[pass_num]);

@ -99,7 +99,8 @@ class ReclamationSweep {
uint64_t sweep_token_;
};
using ReclamationFunction = std::function<void(ReclamationSweep)>;
using ReclamationFunction =
std::function<void(absl::optional<ReclamationSweep>)>;
class ReclaimerQueue {
public:
@ -257,8 +258,7 @@ class GrpcMemoryAllocatorImpl final : public EventEngineMemoryAllocatorImpl {
}
// Post a reclamation function.
void PostReclaimer(ReclamationPass pass,
std::function<void(ReclamationSweep)>);
void PostReclaimer(ReclamationPass pass, ReclamationFunction fn);
// Shutdown the allocator.
void Shutdown() override;
@ -288,6 +288,7 @@ class GrpcMemoryAllocatorImpl final : public EventEngineMemoryAllocatorImpl {
// Amount of memory taken from the quota by this allocator.
size_t taken_bytes_ ABSL_GUARDED_BY(memory_quota_mu_) =
sizeof(GrpcMemoryAllocatorImpl);
bool shutdown_ ABSL_GUARDED_BY(memory_quota_mu_) = false;
// Indices into the various reclaimer queues, used so that we can cancel
// reclamation should we shutdown or get rebound.
ReclaimerQueue::Index
@ -307,8 +308,7 @@ class MemoryOwner {
MemoryAllocator* allocator() { return &allocator_; }
// Post a reclaimer for some reclamation pass.
void PostReclaimer(ReclamationPass pass,
std::function<void(ReclamationSweep)> fn) {
void PostReclaimer(ReclamationPass pass, ReclamationFunction fn) {
static_cast<GrpcMemoryAllocatorImpl*>(allocator_.get_internal_impl_ptr())
->PostReclaimer(pass, std::move(fn));
}

@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_package")
load("//bazel:grpc_build_system.bzl", "grpc_cc_library", "grpc_cc_test", "grpc_package")
licenses(["notice"])
@ -20,6 +20,14 @@ grpc_package(name = "test/core/resource_quota")
load("//test/core/util:grpc_fuzzer.bzl", "grpc_proto_fuzzer")
grpc_cc_library(
name = "call_checker",
testonly = True,
hdrs = ["call_checker.h"],
language = "c++",
deps = ["//:gpr"],
)
grpc_cc_test(
name = "memory_quota_test",
srcs = ["memory_quota_test.cc"],
@ -29,6 +37,7 @@ grpc_cc_test(
language = "c++",
uses_polling = False,
deps = [
"call_checker",
"//:memory_quota",
"//test/core/util:grpc_suppressions",
],
@ -88,6 +97,7 @@ grpc_proto_fuzzer(
tags = ["no_windows"],
uses_polling = False,
deps = [
"call_checker",
"//:memory_quota",
"//test/core/util:grpc_test_util",
],

@ -0,0 +1,52 @@
// Copyright 2021 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef LOCAL_GOOGLE_HOME_CTILLER_GRPC_TEST_CORE_RESOURCE_QUOTA_CALL_CHECKER_H_
#define LOCAL_GOOGLE_HOME_CTILLER_GRPC_TEST_CORE_RESOURCE_QUOTA_CALL_CHECKER_H_
#include <memory>
#include <grpc/support/log.h>
namespace grpc_core {
namespace testing {
// Utility to help check a function is called.
// Usage:
// auto checker = CallChecker::Make();
// auto f = [checker]() {
// checker.Called();
// };
// Will crash if: f never called, or f called more than once.
class CallChecker {
public:
~CallChecker() { GPR_ASSERT(called_); }
void Called() {
GPR_ASSERT(!called_);
called_ = true;
}
static std::shared_ptr<CallChecker> Make() {
return std::make_shared<CallChecker>();
}
private:
bool called_ = false;
};
} // namespace testing
} // namespace grpc_core
#endif // LOCAL_GOOGLE_HOME_CTILLER_GRPC_TEST_CORE_RESOURCE_QUOTA_CALL_CHECKER_H_

@ -18,13 +18,14 @@
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/resource_quota/memory_quota.h"
#include "src/libfuzzer/libfuzzer_macro.h"
#include "test/core/resource_quota/call_checker.h"
#include "test/core/resource_quota/memory_quota_fuzzer.pb.h"
bool squelch = true;
bool leak_check = true;
namespace grpc_core {
namespace testing {
namespace {
ReclamationPass MapReclamationPass(memory_quota_fuzzer::Reclaimer::Pass pass) {
switch (pass) {
@ -100,14 +101,16 @@ class Fuzzer {
allocations_.erase(action.allocation());
break;
case memory_quota_fuzzer::Action::kPostReclaimer: {
std::function<void(ReclamationSweep)> reclaimer;
std::function<void(absl::optional<ReclamationSweep>)> reclaimer;
auto cfg = action.post_reclaimer();
if (cfg.synchronous()) {
reclaimer = [this, cfg](ReclamationSweep) { RunMsg(cfg.msg()); };
reclaimer = [this, cfg](absl::optional<ReclamationSweep>) {
RunMsg(cfg.msg());
};
} else {
reclaimer = [cfg, this](ReclamationSweep sweep) {
reclaimer = [cfg, this](absl::optional<ReclamationSweep> sweep) {
struct Args {
ReclamationSweep sweep;
absl::optional<ReclamationSweep> sweep;
memory_quota_fuzzer::Msg msg;
Fuzzer* fuzzer;
};
@ -122,10 +125,17 @@ class Fuzzer {
ExecCtx::Get()->Run(DEBUG_LOCATION, closure, GRPC_ERROR_NONE);
};
auto pass = MapReclamationPass(cfg.pass());
WithAllocator(action.allocator(),
[pass, reclaimer](MemoryOwner* a) {
a->PostReclaimer(pass, reclaimer);
});
WithAllocator(
action.allocator(), [pass, reclaimer](MemoryOwner* a) {
// ensure called exactly once
auto call_checker = CallChecker::Make();
a->PostReclaimer(pass,
[reclaimer, call_checker](
absl::optional<ReclamationSweep> sweep) {
call_checker->Called();
reclaimer(std::move(sweep));
});
});
}
} break;
case memory_quota_fuzzer::Action::ACTION_TYPE_NOT_SET:
@ -154,7 +164,7 @@ class Fuzzer {
};
} // namespace
} // namespace testing
} // namespace grpc_core
static void dont_log(gpr_log_func_args* /*args*/) {}
@ -163,5 +173,5 @@ DEFINE_PROTO_FUZZER(const memory_quota_fuzzer::Msg& msg) {
if (squelch) gpr_set_log_function(dont_log);
gpr_log_verbosity_init();
grpc_tracer_init();
grpc_core::Fuzzer().Run(msg);
grpc_core::testing::Fuzzer().Run(msg);
}

@ -0,0 +1,859 @@
actions {
quota: 7496448
}
actions {
quota: 2048
allocator: 2162720
create_quota {
}
}
actions {
quota: 2048
allocator: 144
allocation: 4225395
}
actions {
quota: 2048
allocation: 8
}
actions {
quota: 262152
allocator: 117440513
allocation: 6
}
actions {
quota: 2048
allocator: 111
allocation: 2048
}
actions {
quota: 2048
allocator: 6
allocation: 2048
set_quota_size: 0
}
actions {
allocator: 175972352
}
actions {
quota: 2048
allocator: 2048
}
actions {
quota: 2049
allocator: 2048
allocation: 3
}
actions {
quota: 2048
allocator: 2048
allocation: 2048
}
actions {
quota: 16713728
allocator: 2048
}
actions {
allocator: 30768
}
actions {
quota: 2048
allocator: 6
allocation: 117440513
}
actions {
quota: 2048
allocator: 2048
allocation: 9459968
}
actions {
allocator: 6
allocation: -65536
}
actions {
quota: 2048
allocator: 218103807
allocation: 2048
}
actions {
quota: 111
}
actions {
quota: 6
allocator: 6
allocation: 3
delete_quota {
}
}
actions {
quota: 2162720
allocator: 1
allocation: 9437184
delete_allocator {
}
}
actions {
quota: 2048
allocator: 111
allocation: -196608
}
actions {
quota: 111
allocator: 6
allocation: 2048
}
actions {
}
actions {
quota: 2048
allocator: 6
allocation: 2048
set_quota_size: 2785017856
}
actions {
quota: 2048
allocator: 117440513
allocation: 2048
}
actions {
quota: 2048
allocator: 111
allocation: -196608
create_allocation {
max: 1986199552
}
}
actions {
quota: 2048
allocator: 111
allocation: 2048
set_quota_size: 0
}
actions {
allocation: 256
}
actions {
quota: 2048
allocator: 2048
allocation: 2048
}
actions {
quota: 2048
allocator: 117440513
allocation: 9437184
}
actions {
quota: 2048
allocator: 507
allocation: -65536
}
actions {
quota: 2048
allocator: 28416
allocation: 2048
set_quota_size: 0
}
actions {
}
actions {
quota: 2048
allocator: 6
allocation: 2048
create_allocator {
}
}
actions {
quota: 2048
allocator: 65543
allocation: 2048
create_allocator {
}
}
actions {
quota: 2048
allocator: 111
allocation: -196608
}
actions {
quota: 2048
allocator: 111
allocation: 6
set_quota_size: 0
}
actions {
}
actions {
quota: 2048
allocator: 1
}
actions {
quota: 2048
allocator: 2099835
allocation: 9437184
create_allocator {
}
}
actions {
quota: 2048
allocator: 111
allocation: 2048
create_allocator {
}
}
actions {
quota: 2048
allocator: 111
allocation: 2048
}
actions {
delete_quota {
}
}
actions {
quota: 2048
allocator: -2
allocation: 2048
set_quota_size: 0
}
actions {
quota: 2048
allocator: 1
allocation: 2048
}
actions {
quota: 2048
allocator: 111
allocation: 2048
}
actions {
quota: 2048
allocator: 111
allocation: 2099488
create_allocation {
}
}
actions {
allocator: 61295
}
actions {
quota: 2048
allocation: 2048
create_allocator {
}
}
actions {
quota: 2048
allocator: 117440513
allocation: 9437184
set_quota_size: 2785017856
}
actions {
quota: 2048
allocator: 6
allocation: 9437184
}
actions {
quota: -5
allocator: 111
allocation: 2048
set_quota_size: 0
}
actions {
}
actions {
quota: 2048
allocator: 6
allocation: 2048
create_allocator {
}
}
actions {
allocator: 117440513
allocation: 9437184
create_allocator {
}
}
actions {
quota: 2048
allocator: 111
allocation: 111
}
actions {
quota: 2048
allocator: 4
allocation: 2048
}
actions {
quota: 6
}
actions {
quota: 2048
allocator: 6
allocation: 16775680
create_allocator {
}
}
actions {
quota: 2048
allocator: 117440513
create_allocator {
}
}
actions {
quota: 2048
allocator: 111
allocation: -196608
}
actions {
quota: 2048
allocator: 65
set_quota_size: 0
}
actions {
}
actions {
quota: 2048
allocator: 6
allocation: 2048
post_reclaimer {
pass: IDLE
msg {
actions {
post_reclaimer {
pass: IDLE
msg {
actions {
create_allocation {
}
}
actions {
create_allocation {
}
}
actions {
quota: 2048
allocation: 3
delete_quota {
}
}
actions {
post_reclaimer {
pass: IDLE
msg {
actions {
allocation: 1862299392
create_allocation {
max: 14624
}
}
actions {
create_allocation {
}
}
actions {
delete_quota {
}
}
actions {
post_reclaimer {
msg {
actions {
create_allocation {
max: 14624
}
}
actions {
create_allocation {
}
}
actions {
quota: 2048
allocator: 2048
set_quota_size: 0
}
actions {
quota: 2048
allocation: 3
}
actions {
post_reclaimer {
pass: IDLE
msg {
actions {
create_allocation {
max: 14624
}
}
actions {
}
actions {
}
actions {
set_quota_size: 0
}
}
}
}
actions {
create_allocation {
}
}
}
}
}
}
}
}
}
}
}
actions {
allocator: -256
allocation: 2048
}
actions {
quota: 111
create_allocation {
max: 14624
}
}
}
}
}
actions {
quota: 536832
allocator: 117440513
allocation: 9437184
create_allocator {
}
}
actions {
quota: 2048
allocator: 111
allocation: -9671427
create_allocation {
max: 1024
}
}
actions {
quota: 2048
allocator: 111
allocation: 2048
}
actions {
}
actions {
quota: 2048
allocator: 28416
allocation: 12544
create_allocator {
}
}
actions {
quota: -5
allocator: 2048
allocation: 9437184
}
actions {
quota: 2048
allocator: -196608
allocation: -196608
}
actions {
quota: 2048
allocator: 6
allocation: 2048
post_reclaimer {
msg {
actions {
}
actions {
create_allocation {
}
}
actions {
quota: 111
allocator: 4
allocation: 536870912
}
actions {
quota: 2048
allocator: -5
allocation: 65
create_allocator {
}
}
actions {
quota: 4259840
allocator: -5
allocation: 771763712
create_allocator {
}
}
actions {
allocator: 2048
post_reclaimer {
pass: DESTRUCTIVE
msg {
actions {
}
actions {
allocation: 65
create_allocation {
}
}
actions {
create_allocation {
}
}
actions {
quota: 2
post_reclaimer {
pass: IDLE
msg {
actions {
}
actions {
create_allocation {
}
}
actions {
quota: 2048
allocation: 3
}
actions {
allocation: 2048
post_reclaimer {
pass: IDLE
msg {
actions {
create_allocation {
max: 14624
}
}
actions {
create_allocation {
}
}
actions {
}
actions {
}
}
}
}
}
}
}
}
}
}
}
}
}
actions {
quota: 111
}
actions {
quota: 2048
allocator: 6
allocation: 2048
create_allocator {
}
}
actions {
quota: 2048
allocator: 2048
allocation: 9437184
create_allocator {
}
}
actions {
quota: 2048
allocator: 6
allocation: -196608
}
actions {
quota: 2048
allocator: 111
allocation: 2048
set_quota_size: 0
}
actions {
quota: 2048
allocator: 8
allocation: 9437184
}
actions {
quota: 2048
allocation: 301989889
create_allocator {
}
}
actions {
quota: 2048
allocator: 2048
allocation: 9437184
create_allocation {
max: 14624
}
}
actions {
quota: 111
allocator: 117440513
allocation: -1869611008
create_allocation {
max: 1986199552
}
}
actions {
quota: 2048
allocator: 111
}
actions {
allocator: 111
flush_exec_ctx {
}
}
actions {
quota: 9437184
allocator: 4
}
actions {
quota: 2048
allocator: 16779008
allocation: 6
rebind_quota {
}
}
actions {
allocator: 79
allocation: 2048
}
actions {
quota: 2048
allocator: 111
allocation: 2048
set_quota_size: 16646144
}
actions {
}
actions {
quota: 2048
allocator: 6
allocation: 12544
create_allocator {
}
}
actions {
quota: 2048
allocator: 1792
allocation: 9437184
}
actions {
quota: 65
allocator: 6
allocation: -196608
post_reclaimer {
}
}
actions {
quota: 2048
allocator: 6
allocation: 2048
post_reclaimer {
msg {
actions {
create_quota {
}
}
actions {
create_allocation {
}
}
actions {
allocator: 111
allocation: 536870912
}
actions {
quota: 2048
allocator: -5
allocation: 2048
}
actions {
quota: 4259840
allocator: -5
allocation: 65
create_allocation {
min: 32
max: 32
}
}
actions {
allocator: 2048
post_reclaimer {
pass: DESTRUCTIVE
msg {
actions {
}
actions {
allocation: 65
create_allocation {
}
}
actions {
allocator: 908081664
delete_allocation {
}
}
actions {
quota: 111
post_reclaimer {
pass: IDLE
msg {
actions {
post_reclaimer {
msg {
actions {
create_allocation {
}
}
actions {
create_allocation {
}
}
actions {
quota: 2048
allocation: 3
delete_quota {
}
}
actions {
post_reclaimer {
pass: IDLE
msg {
actions {
allocation: 1862299392
create_allocation {
max: 32
}
}
actions {
create_allocation {
}
}
actions {
delete_quota {
}
}
actions {
post_reclaimer {
pass: IDLE
msg {
actions {
create_allocation {
max: 14624
}
}
actions {
create_allocation {
}
}
actions {
quota: 2048
allocator: 111
allocation: 111
set_quota_size: 0
}
actions {
quota: 2048
allocation: 3
}
actions {
post_reclaimer {
pass: IDLE
msg {
actions {
create_allocation {
max: 14624
}
}
actions {
create_allocation {
}
}
actions {
}
actions {
set_quota_size: 0
}
}
}
}
actions {
create_allocation {
}
}
}
}
}
}
}
}
}
}
}
actions {
allocator: 61295
}
actions {
create_allocation {
max: 14624
}
}
}
}
}
}
}
}
}
}
}
actions {
}
actions {
quota: 204
create_allocation {
max: 1
}
}
actions {
allocator: 111
allocation: 9437184
create_allocation {
max: 3
}
}
actions {
quota: 2048
allocator: 111
flush_exec_ctx {
}
}
actions {
allocator: 111
create_quota {
}
}
actions {
quota: 9437184
}
actions {
quota: 2048
allocator: 16779008
allocation: -7706983
create_allocator {
}
}

@ -0,0 +1,9 @@
actions {
create_quota {}
}
actions {
create_allocator {}
}
actions {
create_allocation {}
}

@ -57,7 +57,10 @@ class StressTest {
if (st->RememberReservation(allocator->allocator()->MakeReservation(
st->RandomRequest()))) {
allocator->PostReclaimer(
pass, [st](ReclamationSweep) { st->ForgetReservations(); });
pass, [st](absl::optional<ReclamationSweep> sweep) {
if (!sweep.has_value()) return;
st->ForgetReservations();
});
}
}));
}

@ -20,6 +20,7 @@
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/slice/slice_refcount.h"
#include "test/core/resource_quota/call_checker.h"
namespace grpc_core {
namespace testing {
@ -75,16 +76,26 @@ TEST(MemoryQuotaTest, CreateSomeObjectsAndExpectReclamation) {
auto memory_allocator = memory_quota.CreateMemoryOwner();
auto object = memory_allocator.allocator()->MakeUnique<Sized<2048>>();
auto checker1 = CallChecker::Make();
memory_allocator.PostReclaimer(
ReclamationPass::kDestructive,
[&object](ReclamationSweep) { object.reset(); });
[&object, checker1](absl::optional<ReclamationSweep> sweep) {
checker1->Called();
EXPECT_TRUE(sweep.has_value());
object.reset();
});
auto object2 = memory_allocator.allocator()->MakeUnique<Sized<2048>>();
exec_ctx.Flush();
EXPECT_EQ(object.get(), nullptr);
auto checker2 = CallChecker::Make();
memory_allocator.PostReclaimer(
ReclamationPass::kDestructive,
[&object2](ReclamationSweep) { object2.reset(); });
[&object2, checker2](absl::optional<ReclamationSweep> sweep) {
checker2->Called();
EXPECT_TRUE(sweep.has_value());
object2.reset();
});
auto object3 = memory_allocator.allocator()->MakeUnique<Sized<2048>>();
exec_ctx.Flush();
EXPECT_EQ(object2.get(), nullptr);
@ -104,22 +115,28 @@ TEST(MemoryQuotaTest, BasicRebind) {
memory_allocator.Rebind(&memory_quota);
auto memory_allocator2 = memory_quota2.CreateMemoryOwner();
memory_allocator2.PostReclaimer(ReclamationPass::kDestructive,
[](ReclamationSweep) {
// Taken memory should be reassigned to
// memory_quota, so this should never be
// reached.
abort();
});
memory_allocator.PostReclaimer(ReclamationPass::kDestructive,
[&object](ReclamationSweep) {
// The new memory allocator should reclaim
// the object allocated against the previous
// quota because that's now part of this
// quota.
object.reset();
});
auto checker1 = CallChecker::Make();
memory_allocator2.PostReclaimer(
ReclamationPass::kDestructive,
[checker1](absl::optional<ReclamationSweep> sweep) {
checker1->Called();
// Taken memory should be reassigned to
// memory_quota, so this should be cancelled
EXPECT_FALSE(sweep.has_value());
});
auto checker2 = CallChecker::Make();
memory_allocator.PostReclaimer(
ReclamationPass::kDestructive,
[&object, checker2](absl::optional<ReclamationSweep> sweep) {
checker2->Called();
EXPECT_TRUE(sweep.has_value());
// The new memory allocator should reclaim
// the object allocated against the previous
// quota because that's now part of this
// quota.
object.reset();
});
auto object2 = memory_allocator.allocator()->MakeUnique<Sized<2048>>();
exec_ctx.Flush();

Loading…
Cancel
Save