Qucs-S S-parameter Viewer & RF Synthesis Tools
Loading...
Searching...
No Matches
TStackState.cpp
1#ifndef GREENLET_STACK_STATE_CPP
2#define GREENLET_STACK_STATE_CPP
3
4#include "TGreenlet.hpp"
5
6namespace greenlet {
7
8#ifdef GREENLET_USE_STDIO
9#include <iostream>
10using std::cerr;
11using std::endl;
12
13std::ostream& operator<<(std::ostream& os, const StackState& s)
14{
15 os << "StackState(stack_start=" << (void*)s._stack_start
16 << ", stack_stop=" << (void*)s.stack_stop
17 << ", stack_copy=" << (void*)s.stack_copy
18 << ", stack_saved=" << s._stack_saved
19 << ", stack_prev=" << s.stack_prev
20 << ", addr=" << &s
21 << ")";
22 return os;
23}
24#endif
25
27 : _stack_start(nullptr),
28 stack_stop((char*)mark),
29 stack_copy(nullptr),
30 _stack_saved(0),
31 /* Skip a dying greenlet */
32 stack_prev(current._stack_start
33 ? &current
34 : current.stack_prev)
35{
36}
37
39 : _stack_start(nullptr),
40 stack_stop(nullptr),
41 stack_copy(nullptr),
42 _stack_saved(0),
43 stack_prev(nullptr)
44{
45}
46
48// can't use a delegating constructor because of
49// MSVC for Python 2.7
50 : _stack_start(nullptr),
51 stack_stop(nullptr),
52 stack_copy(nullptr),
53 _stack_saved(0),
54 stack_prev(nullptr)
55{
56 this->operator=(other);
57}
58
59StackState& StackState::operator=(const StackState& other)
60{
61 if (&other == this) {
62 return *this;
63 }
64 if (other._stack_saved) {
65 throw std::runtime_error("Refusing to steal memory.");
66 }
67
68 //If we have memory allocated, dispose of it
69 this->free_stack_copy();
70
71 this->_stack_start = other._stack_start;
72 this->stack_stop = other.stack_stop;
73 this->stack_copy = other.stack_copy;
74 this->_stack_saved = other._stack_saved;
75 this->stack_prev = other.stack_prev;
76 return *this;
77}
78
79inline void StackState::free_stack_copy() noexcept
80{
81 PyMem_Free(this->stack_copy);
82 this->stack_copy = nullptr;
83 this->_stack_saved = 0;
84}
85
86inline void StackState::copy_heap_to_stack(const StackState& current) noexcept
87{
88
89 /* Restore the heap copy back into the C stack */
90 if (this->_stack_saved != 0) {
91 memcpy(this->_stack_start, this->stack_copy, this->_stack_saved);
92 this->free_stack_copy();
93 }
94 StackState* owner = const_cast<StackState*>(&current);
95 if (!owner->_stack_start) {
96 owner = owner->stack_prev; /* greenlet is dying, skip it */
97 }
98 while (owner && owner->stack_stop <= this->stack_stop) {
99 // cerr << "\tOwner: " << owner << endl;
100 owner = owner->stack_prev; /* find greenlet with more stack */
101 }
102 this->stack_prev = owner;
103 // cerr << "\tFinished with: " << *this << endl;
104}
105
106inline int StackState::copy_stack_to_heap_up_to(const char* const stop) noexcept
107{
108 /* Save more of g's stack into the heap -- at least up to 'stop'
109 g->stack_stop |________|
110 | |
111 | __ stop . . . . .
112 | | ==> . .
113 |________| _______
114 | | | |
115 | | | |
116 g->stack_start | | |_______| g->stack_copy
117 */
118 intptr_t sz1 = this->_stack_saved;
119 intptr_t sz2 = stop - this->_stack_start;
120 assert(this->_stack_start);
121 if (sz2 > sz1) {
122 char* c = (char*)PyMem_Realloc(this->stack_copy, sz2);
123 if (!c) {
124 PyErr_NoMemory();
125 return -1;
126 }
127 memcpy(c + sz1, this->_stack_start + sz1, sz2 - sz1);
128 this->stack_copy = c;
129 this->_stack_saved = sz2;
130 }
131 return 0;
132}
133
134inline int StackState::copy_stack_to_heap(char* const stackref,
135 const StackState& current) noexcept
136{
137 /* must free all the C stack up to target_stop */
138 const char* const target_stop = this->stack_stop;
139
140 StackState* owner = const_cast<StackState*>(&current);
141 assert(owner->_stack_saved == 0); // everything is present on the stack
142 if (!owner->_stack_start) {
143 owner = owner->stack_prev; /* not saved if dying */
144 }
145 else {
146 owner->_stack_start = stackref;
147 }
148
149 while (owner->stack_stop < target_stop) {
150 /* ts_current is entierely within the area to free */
151 if (owner->copy_stack_to_heap_up_to(owner->stack_stop)) {
152 return -1; /* XXX */
153 }
154 owner = owner->stack_prev;
155 }
156 if (owner != this) {
157 if (owner->copy_stack_to_heap_up_to(target_stop)) {
158 return -1; /* XXX */
159 }
160 }
161 return 0;
162}
163
164inline bool StackState::started() const noexcept
165{
166 return this->stack_stop != nullptr;
167}
168
169inline bool StackState::main() const noexcept
170{
171 return this->stack_stop == (char*)-1;
172}
173
174inline bool StackState::active() const noexcept
175{
176 return this->_stack_start != nullptr;
177}
178
179inline void StackState::set_active() noexcept
180{
181 assert(this->_stack_start == nullptr);
182 this->_stack_start = (char*)1;
183}
184
185inline void StackState::set_inactive() noexcept
186{
187 this->_stack_start = nullptr;
188 // XXX: What if we still have memory out there?
189 // That case is actually triggered by
190 // test_issue251_issue252_explicit_reference_not_collectable (greenlet.tests.test_leaks.TestLeaks)
191 // and
192 // test_issue251_issue252_need_to_collect_in_background
193 // (greenlet.tests.test_leaks.TestLeaks)
194 //
195 // Those objects never get deallocated, so the destructor never
196 // runs.
197 // It *seems* safe to clean up the memory here?
198 if (this->_stack_saved) {
199 this->free_stack_copy();
200 }
201}
202
203inline intptr_t StackState::stack_saved() const noexcept
204{
205 return this->_stack_saved;
206}
207
208inline char* StackState::stack_start() const noexcept
209{
210 return this->_stack_start;
211}
212
213
214inline StackState StackState::make_main() noexcept
215{
216 StackState s;
217 s._stack_start = (char*)1;
218 s.stack_stop = (char*)-1;
219 return s;
220}
221
222StackState::~StackState()
223{
224 if (this->_stack_saved != 0) {
225 this->free_stack_copy();
226 }
227}
228
229void StackState::copy_from_stack(void* vdest, const void* vsrc, size_t n) const
230{
231 char* dest = static_cast<char*>(vdest);
232 const char* src = static_cast<const char*>(vsrc);
233 if (src + n <= this->_stack_start
234 || src >= this->_stack_start + this->_stack_saved
235 || this->_stack_saved == 0) {
236 // Nothing we're copying was spilled from the stack
237 memcpy(dest, src, n);
238 return;
239 }
240
241 if (src < this->_stack_start) {
242 // Copy the part before the saved stack.
243 // We know src + n > _stack_start due to the test above.
244 const size_t nbefore = this->_stack_start - src;
245 memcpy(dest, src, nbefore);
246 dest += nbefore;
247 src += nbefore;
248 n -= nbefore;
249 }
250 // We know src >= _stack_start after the before-copy, and
251 // src < _stack_start + _stack_saved due to the first if condition
252 size_t nspilled = std::min<size_t>(n, this->_stack_start + this->_stack_saved - src);
253 memcpy(dest, this->stack_copy + (src - this->_stack_start), nspilled);
254 dest += nspilled;
255 src += nspilled;
256 n -= nspilled;
257 if (n > 0) {
258 // Copy the part after the saved stack
259 memcpy(dest, src, n);
260 }
261}
262
263}; // namespace greenlet
264
265#endif // GREENLET_STACK_STATE_CPP
Definition TGreenlet.hpp:185
StackState()
Definition TStackState.cpp:38
Definition __init__.py:1