Buf.cpp 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /*
  2. * Copyright (c)2013-2020 ZeroTier, Inc.
  3. *
  4. * Use of this software is governed by the Business Source License included
  5. * in the LICENSE.TXT file in the project's root directory.
  6. *
  7. * Change Date: 2025-01-01
  8. *
  9. * On the date above, in accordance with the Business Source License, use
  10. * of this software will be governed by version 2.0 of the Apache License.
  11. */
  12. /****/
  13. #include "Buf.hpp"
  14. #ifdef __WINDOWS__
  15. #define sched_yield() Sleep(0)
  16. #endif
  17. namespace ZeroTier {
  18. static std::atomic<uintptr_t> s_pool(0);
  19. static std::atomic<long> s_allocated(0);
  20. // uintptr_max can never be a valid pointer, so use it to indicate that s_pool is locked (very short duration spinlock)
  21. #define ZT_ATOMIC_PTR_LOCKED (~((uintptr_t)0))
  22. void *Buf::operator new(std::size_t sz)
  23. {
  24. uintptr_t bb;
  25. for (;;) {
  26. bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED);
  27. if (bb != ZT_ATOMIC_PTR_LOCKED)
  28. break;
  29. sched_yield();
  30. }
  31. Buf *b;
  32. if (bb) {
  33. s_pool.store(((Buf *) bb)->__nextInPool);
  34. b = (Buf *) bb;
  35. } else {
  36. s_pool.store(0);
  37. b = (Buf *) malloc(sz);
  38. if (!b)
  39. throw Utils::BadAllocException;
  40. ++s_allocated;
  41. }
  42. b->__refCount.store(0);
  43. return (void *) b;
  44. }
  45. void Buf::operator delete(void *ptr)
  46. {
  47. if (ptr) {
  48. if (s_allocated.load() > ZT_BUF_MAX_POOL_SIZE) {
  49. --s_allocated;
  50. free(ptr);
  51. } else {
  52. uintptr_t bb;
  53. for (;;) {
  54. bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED);
  55. if (bb != ZT_ATOMIC_PTR_LOCKED)
  56. break;
  57. sched_yield();
  58. }
  59. ((Buf *) ptr)->__nextInPool.store(bb);
  60. s_pool.store((uintptr_t) ptr);
  61. }
  62. }
  63. }
  64. void Buf::freePool() noexcept
  65. {
  66. uintptr_t bb;
  67. for (;;) {
  68. bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED);
  69. if (bb != ZT_ATOMIC_PTR_LOCKED)
  70. break;
  71. sched_yield();
  72. }
  73. s_pool.store(0);
  74. while (bb != 0) {
  75. const uintptr_t next = ((Buf *) bb)->__nextInPool;
  76. --s_allocated;
  77. free((void *) bb);
  78. bb = next;
  79. }
  80. }
  81. long Buf::poolAllocated() noexcept
  82. {
  83. return s_allocated.load();
  84. }
  85. } // namespace ZeroTier