TThreadStateCreator.hpp 2.5 KB

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