Skip to content

Commit 4606285

Browse files
xavierarteagacodebot
authored andcommitted
phy: fix resource grid pool destructor
1 parent 8a9772a commit 4606285

File tree

7 files changed

+175
-167
lines changed

7 files changed

+175
-167
lines changed

include/srsran/phy/support/shared_resource_grid.h

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,11 @@ class shared_resource_grid
3232
/// Default destructor.
3333
virtual ~pool_interface() = default;
3434

35-
/// \brief Gets the reference to the resource grid from a given identifier.
36-
///
37-
/// \param[in] identifier Internal pool resource grid identifier.
38-
/// \return A reference to the selected resource grid.
39-
/// \remark An assertion is triggered if the identifier is invalid.
40-
virtual resource_grid& get(unsigned identifier) = 0;
41-
42-
/// \brief Notifies the pool of the release of the resource grid.
43-
///
44-
/// \param[in] identifier Internal pool resource grid identifier.
45-
/// \remark An assertion is triggered if the identifier is invalid.
46-
virtual void notify_release_scope(unsigned identifier) = 0;
35+
/// Gets the reference to the resource grid.
36+
virtual resource_grid& get() = 0;
37+
38+
/// Notifies the pool of the release of the resource grid.
39+
virtual void notify_release_scope() = 0;
4740
};
4841

4942
/// Default constructor creates an invalid resource grid.
@@ -52,19 +45,15 @@ class shared_resource_grid
5245
/// \brief Constructs a shared resource grid.
5346
/// \param pool_ Reference to the resource grid pool.
5447
/// \param ref_count_ Reference counter.
55-
/// \param identifier_ Resource grid identifier within the pool.
56-
shared_resource_grid(pool_interface& pool_, std::atomic<unsigned>& ref_count_, unsigned identifier_) :
57-
pool(&pool_), ref_count(&ref_count_), identifier(identifier_)
48+
shared_resource_grid(pool_interface& pool_, std::atomic<unsigned>& ref_count_) : pool(&pool_), ref_count(&ref_count_)
5849
{
5950
}
6051

6152
/// \brief Move constructor - moves the ownership of other resource grid.
6253
///
63-
/// Copies the pool reference, reference count and grid identifier. It invalidates the other instance without .
54+
/// Copies the pool reference and reference count. It invalidates the other instance.
6455
shared_resource_grid(shared_resource_grid&& other) noexcept :
65-
pool(std::exchange(other.pool, nullptr)),
66-
ref_count(std::exchange(other.ref_count, nullptr)),
67-
identifier(other.identifier)
56+
pool(std::exchange(other.pool, nullptr)), ref_count(std::exchange(other.ref_count, nullptr))
6857
{
6958
}
7059

@@ -102,7 +91,7 @@ class shared_resource_grid
10291
if (is_valid()) {
10392
bool last = dec_ref_count();
10493
if (last) {
105-
pool->notify_release_scope(identifier);
94+
pool->notify_release_scope();
10695
}
10796
pool = nullptr;
10897
ref_count = nullptr;
@@ -113,28 +102,28 @@ class shared_resource_grid
113102
resource_grid& get()
114103
{
115104
srsran_assert(is_valid(), "The resource grid is invalid.");
116-
return pool->get(identifier);
105+
return pool->get();
117106
}
118107

119108
/// Gets the resource grid for read-only.
120109
resource_grid& get() const
121110
{
122111
srsran_assert(pool != nullptr, "The resource grid is invalid.");
123-
return pool->get(identifier);
112+
return pool->get();
124113
}
125114

126115
/// Gets the resource grid reader.
127116
const resource_grid_reader& get_reader() const
128117
{
129118
srsran_assert(pool != nullptr, "The resource grid is invalid.");
130-
return pool->get(identifier).get_reader();
119+
return pool->get().get_reader();
131120
}
132121

133122
/// Gets the resource grid writer.
134123
resource_grid_writer& get_writer() const
135124
{
136125
srsran_assert(pool != nullptr, "The resource grid is invalid.");
137-
return pool->get(identifier).get_writer();
126+
return pool->get().get_writer();
138127
}
139128

140129
/// Explicit copy of the resource grid.

lib/phy/support/resource_grid_pool_impl.cpp

Lines changed: 64 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -21,107 +21,59 @@
2121

2222
using namespace srsran;
2323

24-
resource_grid_pool_impl::resource_grid_pool_impl(task_executor* async_executor_,
25-
std::vector<resource_grid_ptr> grids_) :
26-
logger(srslog::fetch_basic_logger("PHY", true)),
27-
grids(std::move(grids_)),
28-
grids_scope_count(grids.size()),
29-
grids_str_zero(grids.size()),
30-
grids_str_reserved(grids.size()),
31-
async_executor(async_executor_)
24+
shared_resource_grid resource_grid_pool_wrapper::try_reserve(srsran::stop_event_token token)
3225
{
33-
// Create tracing list.
34-
for (unsigned i_grid = 0, i_grid_end = grids.size(); i_grid != i_grid_end; ++i_grid) {
35-
grids_str_zero[i_grid] = "set_all_zero#" + std::to_string(i_grid);
36-
grids_str_reserved[i_grid] = "rg_reserved#" + std::to_string(i_grid);
37-
}
38-
39-
// All grids scopes must be zero.
40-
std::fill(grids_scope_count.begin(), grids_scope_count.end(), ref_counter_available);
41-
}
42-
43-
resource_grid_pool_impl::~resource_grid_pool_impl()
44-
{
45-
// Wait for all resource grid to be returned to the pool.
46-
std::for_each(grids_scope_count.begin(), grids_scope_count.end(), [](auto& ref_counter) {
47-
for (unsigned current_ref_counter = ref_counter.load(std::memory_order_acquire);
48-
current_ref_counter != ref_counter_available;
49-
current_ref_counter = ref_counter.load(std::memory_order_acquire)) {
50-
std::this_thread::sleep_for(std::chrono::milliseconds(1));
51-
};
52-
});
53-
}
54-
55-
shared_resource_grid resource_grid_pool_impl::allocate_resource_grid(slot_point slot)
56-
{
57-
// Trace point for grid reservation.
58-
trace_point tp = l1_common_tracer.now();
59-
60-
// Select an identifier from the current request counter.
61-
unsigned identifier = counter;
26+
// Try to transition from available to one scope.
27+
unsigned expected = ref_counter_available;
28+
bool success = scope_count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel);
6229

63-
// Increment request counter and wrap it with the number of grids.
64-
counter = (counter + 1) % grids.size();
65-
66-
// Select counter for the selected identifier.
67-
std::atomic<unsigned>& ref_count = grids_scope_count[identifier];
68-
69-
// Try to reset the reference counter.
70-
unsigned expected = ref_counter_available;
71-
bool available = ref_count.compare_exchange_strong(expected, 1, std::memory_order_acq_rel);
72-
73-
// Return an invalid grid if not available.
74-
if (!available) {
75-
logger.warning(slot.sfn(), slot.slot_index(), "Resource grid with identifier {} is not available.", identifier);
30+
// Return an invalid shared grid if the state transition is unsuccessful.
31+
if (!success) {
7632
return {};
7733
}
7834

79-
// Trace the resource grid reservation.
80-
l1_common_tracer << trace_event(grids_str_reserved[identifier].c_str(), tp);
35+
// Keep token if successful.
36+
stop_token = std::move(token);
8137

82-
return {*this, ref_count, identifier};
38+
// Create valid shared resource grid.
39+
return shared_resource_grid{*this, scope_count};
8340
}
8441

85-
resource_grid& resource_grid_pool_impl::get(unsigned identifier)
42+
void resource_grid_pool_wrapper::release()
8643
{
87-
srsran_assert(identifier < grids.size(),
88-
"RG identifier (i.e., {}) is out of range {}.",
89-
identifier,
90-
interval<unsigned>(0, grids.size()));
91-
return *grids[identifier];
44+
// Move token to the scope of this method before transitioning to available.
45+
stop_event_token token = std::move(stop_token);
46+
47+
// Transition to available.
48+
[[maybe_unused]] unsigned prev_scope_count = scope_count.exchange(ref_counter_available, std::memory_order_acq_rel);
49+
50+
// Assert that the grid is not present in any scope before becoming available.
51+
srsran_assert((prev_scope_count == ref_counter_available) || (prev_scope_count == 0),
52+
"The resource grid state cannot transition to available while it is present in {} scopes.",
53+
prev_scope_count);
9254
}
9355

94-
void resource_grid_pool_impl::notify_release_scope(unsigned identifier)
56+
void resource_grid_pool_wrapper::notify_release_scope()
9557
{
96-
// verify the identifier is valid.
97-
srsran_assert(identifier < grids.size(),
98-
"RG identifier (i.e., {}) is out of range {}.",
99-
identifier,
100-
interval<unsigned>(0, grids.size()));
101-
10258
// Skip zeroing if the grid is empty.
103-
if (grids[identifier]->get_reader().is_empty()) {
104-
grids_scope_count[identifier] = ref_counter_available;
59+
if (grid->get_reader().is_empty()) {
60+
release();
10561
return;
10662
}
10763

10864
// If the pool is not configured with an asynchronous executor, it skips the zeroing process.
10965
if (async_executor == nullptr) {
110-
grids_scope_count[identifier] = ref_counter_available;
66+
release();
11167
return;
11268
}
11369

11470
// Create lambda function for setting the grid to zero.
115-
auto set_all_zero_func = [this, identifier]() noexcept SRSRAN_RTSAN_NONBLOCKING {
116-
trace_point tp = l1_common_tracer.now();
117-
71+
auto set_all_zero_func = [this]() noexcept SRSRAN_RTSAN_NONBLOCKING {
11872
// Set grid to zero.
119-
grids[identifier]->set_all_zero();
73+
grid->set_all_zero();
12074

12175
// Make the grid available.
122-
grids_scope_count[identifier] = ref_counter_available;
123-
124-
l1_common_tracer << trace_event(grids_str_zero[identifier].c_str(), tp);
76+
release();
12577
};
12678

12779
// Try to execute the asynchronous housekeeping task.
@@ -130,6 +82,41 @@ void resource_grid_pool_impl::notify_release_scope(unsigned identifier)
13082
// Ensure the resource grid is marked as available even if it is not empty.
13183
// Avoid warnings about failure to prevent false alarms during gNb teardown.
13284
if (!success) {
133-
grids_scope_count[identifier] = ref_counter_available;
85+
release();
13486
}
13587
}
88+
89+
resource_grid& resource_grid_pool_wrapper::get()
90+
{
91+
return *grid;
92+
}
93+
94+
resource_grid_pool_impl::~resource_grid_pool_impl()
95+
{
96+
stop_control.stop();
97+
}
98+
99+
shared_resource_grid resource_grid_pool_impl::allocate_resource_grid(slot_point slot)
100+
{
101+
// Get a stop token, return an invalid grid if it is stopping.
102+
stop_event_token token = stop_control.get_token();
103+
if (token.stop_requested()) {
104+
return {};
105+
}
106+
107+
// Select an identifier from the current request counter.
108+
unsigned identifier = counter;
109+
110+
// Increment request counter and wrap it with the number of grids.
111+
counter = (counter + 1) % grids.size();
112+
113+
// Try reserving the resource grid.
114+
shared_resource_grid grid = grids[identifier].try_reserve(std::move(token));
115+
116+
// Log a warning message if the grid is not available.
117+
if (!grid) {
118+
logger.warning(slot.sfn(), slot.slot_index(), "Resource grid with identifier {} is not available.", identifier);
119+
}
120+
121+
return grid;
122+
}

lib/phy/support/resource_grid_pool_impl.h

Lines changed: 68 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "srsran/phy/support/resource_grid_pool.h"
1616
#include "srsran/phy/support/shared_resource_grid.h"
1717
#include "srsran/srslog/srslog.h"
18+
#include "srsran/support/synchronization/stop_event.h"
1819
#include "srsran/support/tracing/event_tracing.h"
1920
#include <memory>
2021
#include <vector>
@@ -23,19 +24,76 @@ namespace srsran {
2324

2425
class task_executor;
2526

27+
/// \brief Resource grid state control.
28+
///
29+
/// This class controls the number of scopes in which a shared resource grid is present. Also, it guarantees that the
30+
/// resource grid is returned to the pool prior the destruction.
31+
class resource_grid_pool_wrapper : private shared_resource_grid::pool_interface
32+
{
33+
public:
34+
/// Constructs a resource grid wrapper for the pool.
35+
resource_grid_pool_wrapper(std::unique_ptr<resource_grid> grid_, task_executor* async_executor_) :
36+
grid(std::move(grid_)), async_executor(async_executor_)
37+
{
38+
srsran_assert(grid, "Invalid resource grid pointer.");
39+
}
40+
41+
/// Forbid copy constructor.
42+
resource_grid_pool_wrapper(const resource_grid_pool_wrapper& other) = delete;
43+
44+
/// Move constructor.
45+
resource_grid_pool_wrapper(resource_grid_pool_wrapper&& other) :
46+
grid(std::move(other.grid)), async_executor(other.async_executor)
47+
{
48+
}
49+
50+
/// \brief Try to reserve the resource grid.
51+
///
52+
/// \return True if the resource grid is reserved successfully. Otherwise, false.
53+
shared_resource_grid try_reserve(stop_event_token token);
54+
55+
private:
56+
/// Reference counter value to indicate the availability of a resource grid.
57+
static constexpr unsigned ref_counter_available = std::numeric_limits<unsigned>::max();
58+
59+
/// \brief Release resource grid.
60+
///
61+
/// This method transitions the reference count from zero to available.
62+
///
63+
/// \remark An assertion is triggered if the resource grid is present in any scope.
64+
void release();
65+
66+
// See the shared_resource_grid::pool_interface interface for documentation.
67+
void notify_release_scope() override;
68+
69+
// See the shared_resource_grid::pool_interface interface for documentation.
70+
resource_grid& get() override;
71+
72+
/// Internal resource grid;
73+
std::unique_ptr<resource_grid> grid;
74+
/// Asynchronous task executor.
75+
task_executor* async_executor;
76+
/// \brief Internal resource grid scope count.
77+
///
78+
/// A resource grid is available when the counter is equal to \c ref_counter_available.
79+
std::atomic<unsigned> scope_count = ref_counter_available;
80+
/// Signaling mechanism for safe stop.
81+
stop_event_token stop_token;
82+
};
83+
2684
/// \brief Implements a resource grid pool.
2785
///
2886
/// It zeroes the resource grids asynchronously upon their scope release if it is given an asynchronous executor.
2987
/// Otherwise, it does not zero the resource grid.
30-
class resource_grid_pool_impl : public resource_grid_pool, private shared_resource_grid::pool_interface
88+
class resource_grid_pool_impl : public resource_grid_pool
3189
{
3290
public:
33-
using resource_grid_ptr = std::unique_ptr<resource_grid>;
34-
3591
/// \brief Constructs a resource grid pool.
36-
/// \param async_executor_ Asynchronous housekeeping executor.
37-
/// \param grids_ Resource grids.
38-
resource_grid_pool_impl(task_executor* async_executor_, std::vector<resource_grid_ptr> grids_);
92+
/// \param grids_ Resource grids.
93+
resource_grid_pool_impl(std::vector<resource_grid_pool_wrapper> grids_) :
94+
logger(srslog::fetch_basic_logger("PHY", true)), grids(std::move(grids_))
95+
{
96+
}
3997

4098
/// The destructor waits until all resource grids are available to avoid dereferencing the reference counter.
4199
~resource_grid_pool_impl() override;
@@ -44,31 +102,14 @@ class resource_grid_pool_impl : public resource_grid_pool, private shared_resour
44102
shared_resource_grid allocate_resource_grid(slot_point slot) override;
45103

46104
private:
47-
/// Reference counter value to indicate the availability of a resource grid.
48-
static constexpr unsigned ref_counter_available = std::numeric_limits<unsigned>::max();
49-
50-
// See shared_resource_grid::pool_interface for documentation.
51-
resource_grid& get(unsigned identifier) override;
52-
53-
// See shared_resource_grid::pool_interface for documentation.
54-
void notify_release_scope(unsigned identifier) override;
55-
56105
/// PHY logger.
57106
srslog::basic_logger& logger;
58-
/// Actual pool of resource grids.
59-
std::vector<resource_grid_ptr> grids;
60107
/// Counts the resource grid requests.
61108
unsigned counter = 0;
62-
/// \brief Resource grid scope count.
63-
///
64-
/// A resource grid is available when the counter is equal to \c ref_counter_available.
65-
std::vector<std::atomic<unsigned>> grids_scope_count;
66-
/// Pool of resource grid zero set string for tracing.
67-
std::vector<std::string> grids_str_zero;
68-
/// Pool of resource grid reservation string for tracing.
69-
std::vector<std::string> grids_str_reserved;
70-
/// Asynchronous task executor.
71-
task_executor* async_executor;
109+
/// Resource grid state controllers. There is a controller for each grid.
110+
std::vector<resource_grid_pool_wrapper> grids;
111+
/// Stop control.
112+
stop_event_source stop_control;
72113
};
73114

74115
} // namespace srsran

0 commit comments

Comments
 (0)