Line data Source code
1 : //
2 : // Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/cppalliance/capy
8 : //
9 :
10 : #ifndef BOOST_CAPY_FRAME_ALLOCATOR_HPP
11 : #define BOOST_CAPY_FRAME_ALLOCATOR_HPP
12 :
13 : #include <boost/capy/detail/config.hpp>
14 :
15 : #include <memory_resource>
16 :
17 : /* Design rationale (pdimov):
18 :
19 : This accessor is a thin wrapper over a thread-local pointer.
20 : It returns exactly what was stored, including nullptr. No
21 : dynamic initializer on the thread-local; a dynamic TLS
22 : initializer moves you into a costlier implementation bucket
23 : on some platforms - avoid it.
24 :
25 : Null handling is the caller's responsibility (e.g. in
26 : promise_type::operator new). The accessor must not substitute
27 : a default, because there are multiple valid choices
28 : (new_delete_resource, the default pmr resource, etc.). If
29 : the allocator is not set, it reports "not set" and the
30 : caller interprets that however it wants.
31 : */
32 :
33 : namespace boost {
34 : namespace capy {
35 :
36 : namespace detail {
37 :
38 : inline std::pmr::memory_resource*&
39 20850 : current_frame_allocator_ref() noexcept
40 : {
41 : static thread_local std::pmr::memory_resource* mr = nullptr;
42 20850 : return mr;
43 : }
44 :
45 : } // namespace detail
46 :
47 : /** Return the current frame allocator for this thread.
48 :
49 : These accessors exist to implement the allocator
50 : propagation portion of the @ref IoAwaitable protocol.
51 : Launch functions (`run_async`, `run`) set the
52 : thread-local value before invoking a child coroutine;
53 : the child's `promise_type::operator new` reads it to
54 : allocate the coroutine frame from the correct resource.
55 :
56 : The value is only valid during a narrow execution
57 : window. Between a coroutine's resumption
58 : and the next suspension point, the protocol guarantees
59 : that TLS contains the allocator associated with the
60 : currently running chain. Outside that window the value
61 : is indeterminate. Only code that implements an
62 : @ref IoAwaitable should call these functions.
63 :
64 : A return value of `nullptr` means "not specified" -
65 : no allocator has been established for this chain.
66 : The awaitable is free to use whatever allocation
67 : strategy makes best sense (e.g.
68 : `std::pmr::new_delete_resource()`).
69 :
70 : Use of the frame allocator is optional. An awaitable
71 : that does not consult this value to allocate its
72 : coroutine frame is never wrong. However, a conforming
73 : awaitable must still propagate the allocator faithfully
74 : so that downstream coroutines can use it.
75 :
76 : @return The thread-local memory_resource pointer,
77 : or `nullptr` if none has been set.
78 :
79 : @see set_current_frame_allocator, IoAwaitable
80 : */
81 : inline
82 : std::pmr::memory_resource*
83 5780 : get_current_frame_allocator() noexcept
84 : {
85 5780 : return detail::current_frame_allocator_ref();
86 : }
87 :
88 : /** Set the current frame allocator for this thread.
89 :
90 : Installs @p mr as the frame allocator that will be
91 : read by the next coroutine's `promise_type::operator
92 : new` on this thread. Only launch functions and
93 : @ref IoAwaitable machinery should call this; see
94 : @ref get_current_frame_allocator for the full protocol
95 : description.
96 :
97 : Passing `nullptr` means "not specified" - no
98 : particular allocator is established for the chain.
99 :
100 : @param mr The memory_resource to install, or
101 : `nullptr` to clear.
102 :
103 : @see get_current_frame_allocator, IoAwaitable
104 : */
105 : inline void
106 15070 : set_current_frame_allocator(
107 : std::pmr::memory_resource* mr) noexcept
108 : {
109 15070 : detail::current_frame_allocator_ref() = mr;
110 15070 : }
111 :
112 : } // namespace capy
113 : } // namespace boost
114 :
115 : #endif
|