greenlet_cpython_compat.hpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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. #ifndef Py_SET_REFCNT
  58. /* Py_REFCNT and Py_SIZE macros are converted to functions
  59. https://bugs.python.org/issue39573 */
  60. # define Py_SET_REFCNT(obj, refcnt) Py_REFCNT(obj) = (refcnt)
  61. #endif
  62. #ifdef _Py_DEC_REFTOTAL
  63. # define GREENLET_Py_DEC_REFTOTAL _Py_DEC_REFTOTAL
  64. #else
  65. /* _Py_DEC_REFTOTAL macro has been removed from Python 3.9 by:
  66. https://github.com/python/cpython/commit/49932fec62c616ec88da52642339d83ae719e924
  67. The symbol we use to replace it was removed by at least 3.12.
  68. */
  69. # ifdef Py_REF_DEBUG
  70. # if GREENLET_PY312
  71. # define GREENLET_Py_DEC_REFTOTAL
  72. # else
  73. # define GREENLET_Py_DEC_REFTOTAL _Py_RefTotal--
  74. # endif
  75. # else
  76. # define GREENLET_Py_DEC_REFTOTAL
  77. # endif
  78. #endif
  79. // Define these flags like Cython does if we're on an old version.
  80. #ifndef Py_TPFLAGS_CHECKTYPES
  81. #define Py_TPFLAGS_CHECKTYPES 0
  82. #endif
  83. #ifndef Py_TPFLAGS_HAVE_INDEX
  84. #define Py_TPFLAGS_HAVE_INDEX 0
  85. #endif
  86. #ifndef Py_TPFLAGS_HAVE_NEWBUFFER
  87. #define Py_TPFLAGS_HAVE_NEWBUFFER 0
  88. #endif
  89. #ifndef Py_TPFLAGS_HAVE_VERSION_TAG
  90. #define Py_TPFLAGS_HAVE_VERSION_TAG 0
  91. #endif
  92. #define G_TPFLAGS_DEFAULT Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_VERSION_TAG | Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_HAVE_NEWBUFFER | Py_TPFLAGS_HAVE_GC
  93. #if PY_VERSION_HEX < 0x03090000
  94. // The official version only became available in 3.9
  95. # define PyObject_GC_IsTracked(o) _PyObject_GC_IS_TRACKED(o)
  96. #endif
  97. // bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2
  98. #if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION)
  99. static inline void PyThreadState_EnterTracing(PyThreadState *tstate)
  100. {
  101. tstate->tracing++;
  102. #if PY_VERSION_HEX >= 0x030A00A1
  103. tstate->cframe->use_tracing = 0;
  104. #else
  105. tstate->use_tracing = 0;
  106. #endif
  107. }
  108. #endif
  109. // bpo-43760 added PyThreadState_LeaveTracing() to Python 3.11.0a2
  110. #if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION)
  111. static inline void PyThreadState_LeaveTracing(PyThreadState *tstate)
  112. {
  113. tstate->tracing--;
  114. int use_tracing = (tstate->c_tracefunc != NULL
  115. || tstate->c_profilefunc != NULL);
  116. #if PY_VERSION_HEX >= 0x030A00A1
  117. tstate->cframe->use_tracing = use_tracing;
  118. #else
  119. tstate->use_tracing = use_tracing;
  120. #endif
  121. }
  122. #endif
  123. #if !defined(Py_C_RECURSION_LIMIT) && defined(C_RECURSION_LIMIT)
  124. # define Py_C_RECURSION_LIMIT C_RECURSION_LIMIT
  125. #endif
  126. #endif /* GREENLET_CPYTHON_COMPAT_H */