Branch data Line data Source code
1 : : // Copyright 2026 HPActor Contributors
2 : : //
3 : : // Licensed under the Apache License, Version 2.0 (the "License");
4 : : // you may not use this file except in compliance with the License.
5 : : // You may obtain a copy of the License at
6 : : //
7 : : // http://www.apache.org/licenses/LICENSE-2.0
8 : : //
9 : : // Unless required by applicable law or agreed to in writing, software
10 : : // distributed under the License is distributed on an "AS IS" BASIS,
11 : : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : // See the License for the specific language governing permissions and
13 : : // limitations under the License.
14 : :
15 : : #include <hpactor/sched/coroutine_frame_pool.hpp>
16 : :
17 : : namespace hpactor::sched {
18 : :
19 : 11 : CoroutineFramePool::CoroutineFramePool(size_t num_frames, size_t stack_size)
20 : 22 : : frames_(num_frames), stack_size_(stack_size) {
21 : : // Pre-allocate all stacks and build the free list
22 : 11 : stacks_.reserve(num_frames);
23 : :
24 : 60 : for (size_t i = 0; i < num_frames; ++i) {
25 : : // Allocate stack memory
26 : 49 : auto* stack = new std::byte[stack_size];
27 : 49 : stacks_.emplace_back(stack);
28 : :
29 : : // Initialize frame
30 : 49 : frames_[i].stack_ptr = stack;
31 : 49 : frames_[i].stack_size = stack_size;
32 : 49 : frames_[i].in_use = false;
33 : :
34 : : // Push onto free stack with frame index
35 : 49 : auto* node = reinterpret_cast<FreeNode*>(stack);
36 : 49 : node->next = free_stack_.load(std::memory_order_relaxed);
37 : 49 : node->index = i;
38 : 49 : free_stack_.store(node, std::memory_order_release);
39 : : }
40 : :
41 : 11 : free_count_.store(num_frames, std::memory_order_release);
42 : 11 : }
43 : :
44 : 11 : CoroutineFramePool::~CoroutineFramePool() = default;
45 : :
46 : 46 : CoroutineFramePool::Frame* CoroutineFramePool::acquire() {
47 : : // Pop from free stack
48 : 46 : FreeNode* node = free_stack_.load(std::memory_order_acquire);
49 : 46 : while (node != nullptr) {
50 : 45 : FreeNode* next = node->next;
51 : 45 : if (free_stack_.compare_exchange_weak(node, next, std::memory_order_acq_rel,
52 : : std::memory_order_acquire)) {
53 : 45 : free_count_.fetch_sub(1, std::memory_order_release);
54 : :
55 : : // Retrieve frame directly from stored index
56 : 45 : size_t index = node->index;
57 : 45 : Frame* frame = &frames_[index];
58 : 45 : frame->in_use = true;
59 : 45 : return frame;
60 : : }
61 : : // CAS failed, node was updated, retry
62 : : }
63 : 1 : return nullptr; // Pool exhausted
64 : : }
65 : :
66 : 47 : void CoroutineFramePool::release(Frame* frame) {
67 : 47 : if (!frame || !frame->in_use) {
68 : 2 : return;
69 : : }
70 : :
71 : 45 : frame->in_use = false;
72 : :
73 : : // Push onto free stack (restore index first, since the stack region may
74 : : // have been written to)
75 : 45 : size_t index = static_cast<size_t>(frame - frames_.data());
76 : 45 : auto* node = reinterpret_cast<FreeNode*>(frame->stack_ptr);
77 : 45 : node->index = index;
78 : 45 : FreeNode* current = free_stack_.load(std::memory_order_acquire);
79 : : do {
80 : 45 : node->next = current;
81 : 45 : } while (!free_stack_.compare_exchange_weak(
82 : : current, node, std::memory_order_acq_rel, std::memory_order_acquire));
83 : :
84 : 45 : free_count_.fetch_add(1, std::memory_order_release);
85 : : }
86 : :
87 : : } // namespace hpactor::sched
|