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 : : #pragma once
16 : :
17 : : #include <atomic>
18 : : #include <cstddef>
19 : : #include <cstdint>
20 : : #include <memory>
21 : : #include <vector>
22 : :
23 : : namespace hpactor::sched {
24 : :
25 : : // -----------------------------------------------------------------------------
26 : : // CoroutineFramePool: Fixed-size pool for coroutine stack frames
27 : : // -----------------------------------------------------------------------------
28 : : // Provides pre-allocated stack frames for stackful coroutines.
29 : : // Uses a lock-free stack for O(1) acquire and release.
30 : : //
31 : : // This is used by actors that need to suspend (e.g., blocking receive, await).
32 : : // Instead of allocating stacks dynamically, frames are acquired from this pool.
33 : : // -----------------------------------------------------------------------------
34 : : class CoroutineFramePool {
35 : : public:
36 : : struct Frame {
37 : : std::byte* stack_ptr;
38 : : size_t stack_size;
39 : : bool in_use{false};
40 : : };
41 : :
42 : : // Create pool with given number of frames and stack size
43 : : // stack_size: bytes per coroutine stack (e.g., 8KB, 64KB)
44 : : explicit CoroutineFramePool(size_t num_frames, size_t stack_size = 8 * 1024);
45 : :
46 : : ~CoroutineFramePool();
47 : :
48 : : CoroutineFramePool(const CoroutineFramePool&) = delete;
49 : : CoroutineFramePool& operator=(const CoroutineFramePool&) = delete;
50 : : CoroutineFramePool(CoroutineFramePool&&) = delete;
51 : : CoroutineFramePool& operator=(CoroutineFramePool&&) = delete;
52 : :
53 : : // Acquire a frame from the pool
54 : : // Returns nullptr if pool is exhausted
55 : : Frame* acquire();
56 : :
57 : : // Release a frame back to the pool
58 : : void release(Frame* frame);
59 : :
60 : : // Check if pool is exhausted
61 : 7 : bool empty() const {
62 : 14 : return free_count_.load(std::memory_order_acquire) == 0;
63 : : }
64 : :
65 : : // Number of available frames
66 : 9 : size_t available() const {
67 : 18 : return free_count_.load(std::memory_order_acquire);
68 : : }
69 : :
70 : : // Total number of frames
71 : 4 : size_t total() const {
72 : 4 : return frames_.size();
73 : : }
74 : :
75 : : // Maximum stack size
76 : 2 : size_t stack_size() const {
77 : 2 : return stack_size_;
78 : : }
79 : :
80 : : private:
81 : : struct FreeNode {
82 : : FreeNode* next;
83 : : size_t index;
84 : : };
85 : :
86 : : std::atomic<FreeNode*> free_stack_{nullptr};
87 : : std::atomic<size_t> free_count_{0};
88 : : std::vector<std::unique_ptr<std::byte[]>> stacks_;
89 : : std::vector<Frame> frames_;
90 : : size_t stack_size_;
91 : : };
92 : :
93 : : } // namespace hpactor::sched
|