codekingpro/portable-devtools
115k
1#ifndef GREENLET_THREAD_STATE_CREATOR_HPP
2#define GREENLET_THREAD_STATE_CREATOR_HPP
3
4#include <ctime>
5#include <stdexcept>
6
7#include "greenlet_internal.hpp"
8#include "greenlet_refs.hpp"
9#include "greenlet_thread_support.hpp"
10
11#include "TThreadState.hpp"
12
13namespace greenlet {
14
15
16typedef void (*ThreadStateDestructor)(ThreadState* const);
17
18// Only one of these, auto created per thread as a thread_local.
19// This means we don't have to worry about atomic access to the
20// internals, because by definition all access is happening on a
21// single thread.
22// Constructing the state constructs the MainGreenlet.
23template<ThreadStateDestructor Destructor>
24class ThreadStateCreator
25{
26private:
27 // Initialized to 1, and, if still 1, created on access.
28 // Set to 0 on destruction.
29 ThreadState* _state;
30 G_NO_COPIES_OF_CLS(ThreadStateCreator);
31
32 inline bool has_initialized_state() const noexcept
33 {
34 return this->_state != (ThreadState*)1;
35 }
36
37 inline bool has_state() const noexcept
38 {
39 return this->has_initialized_state() && this->_state != nullptr;
40 }
41
42public:
43
44 ThreadStateCreator() :
45 _state((ThreadState*)1)
46 {
47 }
48
49 ~ThreadStateCreator()
50 {
51 if (this->has_state()) {
52 Destructor(this->_state);
53 }
54
55 this->_state = nullptr;
56 }
57
58 inline ThreadState& state()
59 {
60 // The main greenlet will own this pointer when it is created,
61 // which will be right after this. The plan is to give every
62 // greenlet a pointer to the main greenlet for the thread it
63 // runs in; if we are doing something cross-thread, we need to
64 // access the pointer from the main greenlet. Deleting the
65 // thread, and hence the thread-local storage, will delete the
66 // state pointer in the main greenlet.
67 if (!this->has_initialized_state()) {
68 // XXX: Assuming allocation never fails
69 this->_state = new ThreadState;
70 // For non-standard threading, we need to store an object
71 // in the Python thread state dictionary so that it can be
72 // DECREF'd when the thread ends (ideally; the dict could
73 // last longer) and clean this object up.
74 }
75 if (!this->_state) {
76 throw std::runtime_error("Accessing state after destruction.");
77 }
78 return *this->_state;
79 }
80
81 operator ThreadState&()
82 {
83 return this->state();
84 }
85
86 operator ThreadState*()
87 {
88 return &this->state();
89 }
90
91 inline int tp_traverse(visitproc visit, void* arg)
92 {
93 if (this->has_state()) {
94 return this->_state->tp_traverse(visit, arg);
95 }
96 return 0;
97 }
98
99};
100
101
102
103}; // namespace greenlet
104
105#endif
106 