greenlet_cpython_compat.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /* -*- indent-tabs-mode: nil; tab-width: 4; -*- */
  2. #ifndef GREENLET_CPYTHON_COMPAT_H
  3. #define GREENLET_CPYTHON_COMPAT_H
  4. /**
  5. * Helpers for compatibility with multiple versions of CPython.
  6. */
  7. #define PY_SSIZE_T_CLEAN
  8. #include "Python.h"
  9. #if PY_VERSION_HEX >= 0x30A00B1
  10. # define GREENLET_PY310 1
  11. #else
  12. # define GREENLET_PY310 0
  13. #endif
  14. /*
  15. Python 3.10 beta 1 changed tstate->use_tracing to a nested cframe member.
  16. See https://github.com/python/cpython/pull/25276
  17. We have to save and restore this as well.
  18. Python 3.13 removed PyThreadState.cframe (GH-108035).
  19. */
  20. #if GREENLET_PY310 && PY_VERSION_HEX < 0x30D0000
  21. # define GREENLET_USE_CFRAME 1
  22. #else
  23. # define GREENLET_USE_CFRAME 0
  24. #endif
  25. #if PY_VERSION_HEX >= 0x30B00A4
  26. /*
  27. Greenlet won't compile on anything older than Python 3.11 alpha 4 (see
  28. https://bugs.python.org/issue46090). Summary of breaking internal changes:
  29. - Python 3.11 alpha 1 changed how frame objects are represented internally.
  30. - https://github.com/python/cpython/pull/30122
  31. - Python 3.11 alpha 3 changed how recursion limits are stored.
  32. - https://github.com/python/cpython/pull/29524
  33. - Python 3.11 alpha 4 changed how exception state is stored. It also includes a
  34. change to help greenlet save and restore the interpreter frame "data stack".
  35. - https://github.com/python/cpython/pull/30122
  36. - https://github.com/python/cpython/pull/30234
  37. */
  38. # define GREENLET_PY311 1
  39. #else
  40. # define GREENLET_PY311 0
  41. #endif
  42. #if PY_VERSION_HEX >= 0x30C0000
  43. # define GREENLET_PY312 1
  44. #else
  45. # define GREENLET_PY312 0
  46. #endif
  47. #if PY_VERSION_HEX >= 0x30D0000
  48. # define GREENLET_PY313 1
  49. #else
  50. # define GREENLET_PY313 0
  51. #endif
  52. #if PY_VERSION_HEX >= 0x30E0000
  53. # define GREENLET_PY314 1
  54. #else
  55. # define GREENLET_PY314 0
  56. #endif
  57. #if PY_VERSION_HEX >= 0x30F0000
  58. # define GREENLET_PY315 1
  59. #else
  60. # define GREENLET_PY315 0
  61. #endif
  62. #ifndef Py_SET_REFCNT
  63. /* Py_REFCNT and Py_SIZE macros are converted to functions
  64. https://bugs.python.org/issue39573 */
  65. # define Py_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt)
  66. #endif
  67. #ifdef _Py_DEC_REFTOTAL
  68. # define GREENLET_Py_DEC_REFTOTAL _Py_DEC_REFTOTAL
  69. #else
  70. /* _Py_DEC_REFTOTAL macro has been removed from Python 3.9 by:
  71. https://github.com/python/cpython/commit/49932fec62c616ec88da52642339d83ae719e924
  72. The symbol we use to replace it was removed by at least 3.12.
  73. */
  74. # ifdef Py_REF_DEBUG
  75. # if GREENLET_PY312
  76. # define GREENLET_Py_DEC_REFTOTAL
  77. # else
  78. # define GREENLET_Py_DEC_REFTOTAL _Py_RefTotal--
  79. # endif
  80. # else
  81. # define GREENLET_Py_DEC_REFTOTAL
  82. # endif
  83. #endif
  84. // Define these flags like Cython does if we're on an old version.
  85. #ifndef Py_TPFLAGS_CHECKTYPES
  86. #define Py_TPFLAGS_CHECKTYPES 0
  87. #endif
  88. #ifndef Py_TPFLAGS_HAVE_INDEX
  89. #define Py_TPFLAGS_HAVE_INDEX 0
  90. #endif
  91. #ifndef Py_TPFLAGS_HAVE_NEWBUFFER
  92. #define Py_TPFLAGS_HAVE_NEWBUFFER 0
  93. #endif
  94. #ifndef Py_TPFLAGS_HAVE_VERSION_TAG
  95. #define Py_TPFLAGS_HAVE_VERSION_TAG 0
  96. #endif
  97. #define G_TPFLAGS_DEFAULT Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_VERSION_TAG | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_HAVE_GC
  98. #if PY_VERSION_HEX < 0x03090000
  99. // The official version only became available in 3.9
  100. # define PyObject_GC_IsTracked(o) _PyObject_GC_IS_TRACKED(o)
  101. #endif
  102. // bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2
  103. #if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION)
  104. static inline void PyThreadState_EnterTracing(PyThreadState *tstate)
  105. {
  106. tstate->tracing++;
  107. #if PY_VERSION_HEX >= 0x030A00A1
  108. tstate->cframe->use_tracing = 0;
  109. #else
  110. tstate->use_tracing = 0;
  111. #endif
  112. }
  113. #endif
  114. // bpo-43760 added PyThreadState_LeaveTracing() to Python 3.11.0a2
  115. #if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION)
  116. static inline void PyThreadState_LeaveTracing(PyThreadState *tstate)
  117. {
  118. tstate->tracing--;
  119. int use_tracing = (tstate->c_tracefunc != NULL
  120. || tstate->c_profilefunc != NULL);
  121. #if PY_VERSION_HEX >= 0x030A00A1
  122. tstate->cframe->use_tracing = use_tracing;
  123. #else
  124. tstate->use_tracing = use_tracing;
  125. #endif
  126. }
  127. #endif
  128. #if !defined(Py_C_RECURSION_LIMIT) && defined(C_RECURSION_LIMIT)
  129. # define Py_C_RECURSION_LIMIT C_RECURSION_LIMIT
  130. #endif
  131. #endif /* GREENLET_CPYTHON_COMPAT_H */