blob: 38cdef579350933f91b25e1f81e172da665bce74 [file] [log] [blame]
Avi Drissman8ba1bad2022-09-13 19:22:361// Copyright 2020 The Chromium Authors
Leonid Baraz3e8af4b2020-11-23 19:04:472// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Leonid Baraz2b2e0b52022-12-13 03:25:075#ifndef COMPONENTS_REPORTING_RESOURCES_RESOURCE_MANAGER_H_
6#define COMPONENTS_REPORTING_RESOURCES_RESOURCE_MANAGER_H_
Leonid Baraz3e8af4b2020-11-23 19:04:477
Leonid Baraz0be7196b2022-12-13 00:02:528#include <atomic>
Leonid Baraz3e8af4b2020-11-23 19:04:479#include <cstdint>
Arthur Sonzognic571efb2024-01-26 20:26:1810#include <optional>
Leonid Baraz0be7196b2022-12-13 00:02:5211#include <queue>
12#include <utility>
Leonid Baraz3e8af4b2020-11-23 19:04:4713
Leonid Baraz0be7196b2022-12-13 00:02:5214#include "base/functional/callback_forward.h"
Leonid Baraz960ea8f2022-05-17 01:01:0615#include "base/memory/ref_counted.h"
16#include "base/memory/scoped_refptr.h"
Leonid Baraz0be7196b2022-12-13 00:02:5217#include "base/task/sequenced_task_runner.h"
18#include "base/thread_annotations.h"
Leonid Baraz3e8af4b2020-11-23 19:04:4719
20namespace reporting {
21
Leonid Baraz2b2e0b52022-12-13 03:25:0722// Resource management class. The class is thread-safe.
23// Each resource instance is created with its own total size; the rest of the
24// functionality is identical. All APIs are non-blocking.
25class ResourceManager : public base::RefCountedThreadSafe<ResourceManager> {
Leonid Baraz3e8af4b2020-11-23 19:04:4726 public:
Leonid Baraz2b2e0b52022-12-13 03:25:0727 explicit ResourceManager(uint64_t total_size);
Leonid Baraz0be7196b2022-12-13 00:02:5228
Leonid Baraz3e8af4b2020-11-23 19:04:4729 // Needs to be called before attempting to allocate specified size.
30 // Returns true if requested amount can be allocated.
31 // After that the caller can actually allocate it or must call
32 // |Discard| if decided not to allocate.
Leonid Baraz0be7196b2022-12-13 00:02:5233 bool Reserve(uint64_t size);
Leonid Baraz3e8af4b2020-11-23 19:04:4734
Leonid Baraz0be7196b2022-12-13 00:02:5235 // Reverts reservation, arranges for callbacks calls as necessary.
Leonid Baraz3e8af4b2020-11-23 19:04:4736 // Must be called after the specified amount is released.
Leonid Baraz0be7196b2022-12-13 00:02:5237 void Discard(uint64_t size);
Leonid Baraz3e8af4b2020-11-23 19:04:4738
39 // Returns total amount.
Leonid Baraz0be7196b2022-12-13 00:02:5240 uint64_t GetTotal() const;
Leonid Baraz3e8af4b2020-11-23 19:04:4741
42 // Returns current used amount.
Leonid Baraz0be7196b2022-12-13 00:02:5243 uint64_t GetUsed() const;
44
45 // Registers a callback to be invoked once there is specified amount
46 // of resource available (does not reserve it, so once called back
47 // the respective code must attempt to reserve again, and if unsuccessful,
48 // may need ot re-register the callback).
49 // Callbacks will be invoked in the context of the sequenced task runner
50 // it was registered in.
51 void RegisterCallback(uint64_t size, base::OnceClosure cb);
Leonid Baraz3e8af4b2020-11-23 19:04:4752
53 // Test only: Sets non-default usage limit.
Leonid Baraz0be7196b2022-12-13 00:02:5254 void Test_SetTotal(uint64_t test_total);
Leonid Baraz3e8af4b2020-11-23 19:04:4755
Leonid Baraz0be7196b2022-12-13 00:02:5256 private:
Leonid Baraz2b2e0b52022-12-13 03:25:0757 friend class base::RefCountedThreadSafe<ResourceManager>;
Leonid Baraz960ea8f2022-05-17 01:01:0658
Leonid Baraz2b2e0b52022-12-13 03:25:0759 ~ResourceManager();
Leonid Baraz0be7196b2022-12-13 00:02:5260
61 // Flushes as many callbacks as possible given the current resource
62 // availability. Callbacks only signal that resource may be available,
63 // the resumed task must try to actually reserve it after that.
64 void FlushCallbacks();
65
66 uint64_t total_; // Remains constant in prod code, changes only in tests.
67 std::atomic<uint64_t> used_{0};
68
69 // Sequenced task runner for callbacks handling (not for calling callbacks!)
70 const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
71 SEQUENCE_CHECKER(sequence_checker_);
72
73 // Queue of pairs [size, callback].
74 // When `Discard` leaves enough space available (even momentarily),
75 // calls as many of the callbacks as fit in that size, in the queue order.
76 // Note that in a meantime reservation may change - the called back code
77 // must attempt reservation before using it.
78 std::queue<std::pair<uint64_t, base::OnceClosure>> resource_callbacks_
79 GUARDED_BY_CONTEXT(sequence_checker_);
Leonid Baraz3e8af4b2020-11-23 19:04:4780};
81
82// Moveable RAII class used for scoped Reserve-Discard.
83//
84// Usage:
85// {
Leonid Baraz960ea8f2022-05-17 01:01:0686// ScopedReservation reservation(1024u, options.memory_resource());
Leonid Baraz3e8af4b2020-11-23 19:04:4787// if (!reservation.reserved()) {
88// // Allocation failed.
89// return;
90// }
91// // Allocation succeeded.
92// ...
93// } // Automatically discarded.
94//
Leonid Baraza2064292022-07-07 00:18:4195// Can be handed over to another owner by move-constructor or using HandOver
96// method:
97// {
98// ScopedReservation summary;
99// for (const uint64_t size : sizes) {
100// ScopedReservation single_reservation(size, resource);
101// ...
102// summary.HandOver(single_reservation);
103// }
104// }
Leonid Baraz3e8af4b2020-11-23 19:04:47105class ScopedReservation {
106 public:
Leonid Baraza2064292022-07-07 00:18:41107 // Zero-size reservation with no resource interface attached.
108 // reserved() returns false.
109 ScopedReservation() noexcept;
110 // Specified reservation, must have resource interface attached.
Leonid Baraz2b2e0b52022-12-13 03:25:07111 ScopedReservation(uint64_t size,
112 scoped_refptr<ResourceManager> resource_manager) noexcept;
Leonid Barazb4553922022-07-12 23:32:53113 // New reservation on the same resource interface as |other_reservation|.
114 ScopedReservation(uint64_t size,
115 const ScopedReservation& other_reservation) noexcept;
116 // Move constructor.
Leonid Barazaf0a319f2022-06-15 02:17:47117 ScopedReservation(ScopedReservation&& other) noexcept;
Leonid Baraz3e8af4b2020-11-23 19:04:47118 ScopedReservation(const ScopedReservation& other) = delete;
Leonid Barazaf0a319f2022-06-15 02:17:47119 ScopedReservation& operator=(ScopedReservation&& other) = delete;
Leonid Baraz3e8af4b2020-11-23 19:04:47120 ScopedReservation& operator=(const ScopedReservation& other) = delete;
121 ~ScopedReservation();
122
123 bool reserved() const;
Leonid Barazaf0a319f2022-06-15 02:17:47124
125 // Reduces reservation to |new_size|.
Santiago Castano Moreno150ba5f2021-11-12 21:34:52126 bool Reduce(uint64_t new_size);
Leonid Baraz3e8af4b2020-11-23 19:04:47127
Leonid Barazaf0a319f2022-06-15 02:17:47128 // Adds |other| to |this| without assigning or releasing any reservation.
129 // Used for seamless transition from one reservation to another (more generic
130 // than std::move). Resets |other| to non-reserved state upon return from this
131 // method.
132 void HandOver(ScopedReservation& other);
133
Leonid Baraz3e8af4b2020-11-23 19:04:47134 private:
Leonid Baraz2b2e0b52022-12-13 03:25:07135 scoped_refptr<ResourceManager> resource_manager_;
Arthur Sonzognic571efb2024-01-26 20:26:18136 std::optional<uint64_t> size_;
Leonid Baraz3e8af4b2020-11-23 19:04:47137};
138
Leonid Baraz3e8af4b2020-11-23 19:04:47139} // namespace reporting
140
Leonid Baraz2b2e0b52022-12-13 03:25:07141#endif // COMPONENTS_REPORTING_RESOURCES_RESOURCE_MANAGER_H_