greenlet_cpython_compat.hpp 3.9 KB

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