Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
TStackState.cpp266 linesDownload Raw Back to greenlet
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
26StackState::StackState(void* mark, StackState& current)
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
38StackState::StackState()
39    : _stack_start(nullptr),
40      stack_stop(nullptr),
41      stack_copy(nullptr),
42      _stack_saved(0),
43      stack_prev(nullptr)
44{
45}
46
47StackState::StackState(const StackState& other)
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
266 
codekingpro/portable-devtools · Team Ai