greenlet_allocator.hpp 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #ifndef GREENLET_ALLOCATOR_HPP
  2. #define GREENLET_ALLOCATOR_HPP
  3. #define PY_SSIZE_T_CLEAN
  4. #include <Python.h>
  5. #include <memory>
  6. #include "greenlet_compiler_compat.hpp"
  7. #include "greenlet_cpython_compat.hpp"
  8. namespace greenlet
  9. {
  10. #if defined(Py_GIL_DISABLED)
  11. // Python on free threaded builds says this
  12. // (https://docs.python.org/3/howto/free-threading-extensions.html#memory-allocation-apis):
  13. //
  14. // For thread-safety, the free-threaded build requires that only
  15. // Python objects are allocated using the object domain, and that all
  16. // Python object are allocated using that domain.
  17. //
  18. // This turns out to be important because the GC implementation on
  19. // free threaded Python uses internal mimalloc APIs to find allocated
  20. // objects. If we allocate non-PyObject objects using that API, then
  21. // Bad Things could happen, including crashes and improper results.
  22. // So in that case, we revert to standard C++ allocation.
  23. template <class T>
  24. struct PythonAllocator : public std::allocator<T> {
  25. // This member is deprecated in C++17 and removed in C++20
  26. template< class U >
  27. struct rebind {
  28. typedef PythonAllocator<U> other;
  29. };
  30. };
  31. #else
  32. // This allocator is stateless; all instances are identical.
  33. // It can *ONLY* be used when we're sure we're holding the GIL
  34. // (Python's allocators require the GIL).
  35. template <class T>
  36. struct PythonAllocator : public std::allocator<T> {
  37. PythonAllocator(const PythonAllocator& UNUSED(other))
  38. : std::allocator<T>()
  39. {
  40. }
  41. PythonAllocator(const std::allocator<T> other)
  42. : std::allocator<T>(other)
  43. {}
  44. template <class U>
  45. PythonAllocator(const std::allocator<U>& other)
  46. : std::allocator<T>(other)
  47. {
  48. }
  49. PythonAllocator() : std::allocator<T>() {}
  50. T* allocate(size_t number_objects, const void* UNUSED(hint)=0)
  51. {
  52. void* p;
  53. if (number_objects == 1)
  54. p = PyObject_Malloc(sizeof(T));
  55. else
  56. p = PyMem_Malloc(sizeof(T) * number_objects);
  57. return static_cast<T*>(p);
  58. }
  59. void deallocate(T* t, size_t n)
  60. {
  61. void* p = t;
  62. if (n == 1) {
  63. PyObject_Free(p);
  64. }
  65. else
  66. PyMem_Free(p);
  67. }
  68. // This member is deprecated in C++17 and removed in C++20
  69. template< class U >
  70. struct rebind {
  71. typedef PythonAllocator<U> other;
  72. };
  73. };
  74. #endif // allocator type
  75. }
  76. #endif