Advertisement
Chris_M_Thomasson

C++17 Proxy Collector ver -1 by Chris M. Thomasson

Jan 28th, 2021
1,028
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.12 KB | None | 0 0
  1. #include <iostream>
  2. #include <atomic>
  3. #include <thread>
  4. #include <cstdlib>
  5. #include <cstdint>
  6.  
  7.  
  8. // Some debug/sanity check things...
  9. // Need to make this conditional in compilation with some macros
  10. static std::atomic<unsigned long> g_debug_node_allocations(0);
  11. static std::atomic<unsigned long> g_debug_node_deallocations(0);
  12.  
  13.  
  14. struct ct_node
  15. {
  16.     std::atomic<ct_node*> m_next;
  17.     ct_node* m_defer_next;
  18.  
  19.     ct_node()
  20.     {
  21.         g_debug_node_allocations.fetch_add(1, std::memory_order_relaxed);
  22.     }
  23.  
  24.     ~ct_node()
  25.     {
  26.         g_debug_node_deallocations.fetch_add(1, std::memory_order_relaxed);
  27.     }
  28. };
  29.  
  30.  
  31.  
  32.  
  33. template<std::size_t T_defer_limit>
  34. class ct_proxy
  35. {
  36.     static void prv_destroy(ct_node* n)
  37.     {
  38.         while (n)
  39.         {
  40.             ct_node* next = n->m_defer_next;
  41.             delete n;
  42.             n = next;
  43.         }
  44.     }
  45.  
  46.  
  47. public:
  48.     class collector
  49.     {
  50.         friend class ct_proxy;
  51.  
  52.     private:
  53.         std::atomic<ct_node*> m_defer;
  54.         std::atomic<unsigned int> m_defer_count;
  55.         std::atomic<unsigned int> m_count;
  56.  
  57.  
  58.  
  59.     public:
  60.         collector()
  61.             : m_defer(nullptr),
  62.             m_defer_count(0),
  63.             m_count(0)
  64.         {
  65.  
  66.         }
  67.  
  68.  
  69.         ~collector()
  70.         {
  71.             prv_destroy(m_defer.load(std::memory_order_relaxed));
  72.         }
  73.     };
  74.  
  75.  
  76.  
  77. private:
  78.     std::atomic<unsigned int> m_current;
  79.     std::atomic<bool> m_quiesce;
  80.     ct_node* m_defer;
  81.     collector m_collectors[2];
  82.  
  83.  
  84.  
  85. public:
  86.     ct_proxy()
  87.         : m_current(0),
  88.         m_quiesce(false),
  89.         m_defer(nullptr)
  90.     {
  91.  
  92.     }
  93.  
  94.     ~ct_proxy()
  95.     {
  96.         prv_destroy(m_defer);
  97.     }
  98.  
  99. private:
  100.     void prv_quiesce_begin()
  101.     {
  102.         // Try to begin the quiescence process.
  103.         if (!m_quiesce.exchange(true, std::memory_order_acquire))
  104.         {
  105.             // advance the current collector and grab the old one.
  106.             unsigned int old = m_current.load(std::memory_order_relaxed) & 0xFU;
  107.             old = m_current.exchange((old + 1) & 1, std::memory_order_acq_rel);
  108.             collector& c = m_collectors[old & 0xFU];
  109.  
  110.             // decode reference count.
  111.             //unsigned int refs = old & 0xFFFFFFF0U;  HOLY SHIT!!!
  112.             long refs = old & 0xFFFFFFF0U;
  113.  
  114.             // verify reference count and previous collector index.
  115.            // RL_ASSERT(!(refs & 0x10U) && (old & 0xFU) == (&c - m_collectors));
  116.  
  117.             // increment and generate an odd reference count.
  118.             if (c.m_count.fetch_add(refs + 0x10U, std::memory_order_release) == (unsigned int)-refs)
  119.             {
  120.                 // odd reference count and drop-to-zero condition detected!
  121.                 prv_quiesce_complete(c);
  122.             }
  123.         }
  124.     }
  125.  
  126.  
  127.     void prv_quiesce_complete(collector& c)
  128.     {
  129.         // the collector `c' is now in a quiescent state! :^)
  130.         std::atomic_thread_fence(std::memory_order_acquire);
  131.  
  132.         // maintain the back link and obtain "fresh" objects from
  133.         // this collection.
  134.         ct_node* n = m_defer;
  135.         m_defer = c.m_defer.load(std::memory_order_relaxed);
  136.         c.m_defer.store(0, std::memory_order_relaxed);
  137.  
  138.         // verify and reset the reference count.
  139.         //RL_ASSERT(c.m_count.load(std::memory_order_relaxed) == 0x10U);
  140.         c.m_count.store(0, std::memory_order_relaxed);
  141.         c.m_defer_count.store(0, std::memory_order_relaxed);
  142.  
  143.         // release the quiesce lock.
  144.         m_quiesce.store(false, std::memory_order_release);
  145.  
  146.         // destroy nodes.
  147.         prv_destroy(n);
  148.     }
  149.  
  150.  
  151. public:
  152.     collector& acquire()
  153.     {
  154.         // increment the master count _and_ obtain current collector.
  155.         unsigned int current =
  156.             m_current.fetch_add(0x20U, std::memory_order_acquire);
  157.  
  158.         // decode the collector index.
  159.         return m_collectors[current & 0xFU];
  160.     }
  161.  
  162.  
  163.     void release(collector& c)
  164.     {
  165.         // decrement the collector.
  166.         unsigned int count =
  167.             c.m_count.fetch_sub(0x20U, std::memory_order_release);
  168.  
  169.         // check for the completion of the quiescence process.
  170.         if ((count & 0xFFFFFFF0U) == 0x30U)
  171.         {
  172.             // odd reference count and drop-to-zero condition detected!
  173.             prv_quiesce_complete(c);
  174.         }
  175.     }
  176.  
  177.  
  178.     collector& sync(collector& c)
  179.     {
  180.         // check if the `c' is in the middle of a quiescence process.
  181.         if (c.m_count.load(std::memory_order_relaxed) & 0x10U)
  182.         {
  183.             // drop `c' and get the next collector.
  184.             release(c);
  185.  
  186.             return acquire();
  187.         }
  188.  
  189.         return c;
  190.     }
  191.  
  192.  
  193.     void collect()
  194.     {
  195.         prv_quiesce_begin();
  196.     }
  197.  
  198.  
  199.     void collect(collector& c, ct_node* n)
  200.     {
  201.         if (!n) return;
  202.  
  203.         // link node into the defer list.
  204.         ct_node* prev = c.m_defer.exchange(n, std::memory_order_relaxed);
  205.         n->m_defer_next = prev;
  206.  
  207.         // bump the defer count and begin quiescence process if over
  208.         // the limit.
  209.         unsigned int count =
  210.             c.m_defer_count.fetch_add(1, std::memory_order_relaxed) + 1;
  211.  
  212.         if (count >= (T_defer_limit / 2))
  213.         {
  214.             prv_quiesce_begin();
  215.         }
  216.     }
  217. };
  218.  
  219.  
  220.  
  221.  
  222. // you're basic lock-free stack...
  223. // well, minus ABA counter and DWCAS of course!  ;^)
  224. class ct_stack
  225. {
  226.     std::atomic<ct_node*> m_head;
  227.  
  228.  
  229.  
  230. public:
  231.     ct_stack()
  232.         : m_head(nullptr)
  233.     {
  234.  
  235.     }
  236.  
  237.  
  238.  
  239. public:
  240.     void push(ct_node* n)
  241.     {
  242.         ct_node* head = m_head.load(std::memory_order_relaxed);
  243.  
  244.         do
  245.         {
  246.             n->m_next.store(head, std::memory_order_relaxed);
  247.         }
  248.  
  249.         while (!m_head.compare_exchange_weak(
  250.             head,
  251.             n,
  252.             std::memory_order_release));
  253.     }
  254.  
  255.  
  256.     ct_node* flush()
  257.     {
  258.         return m_head.exchange(NULL, std::memory_order_acquire);
  259.     }
  260.  
  261.  
  262.     ct_node* get_head()
  263.     {
  264.         return m_head.load(std::memory_order_acquire);
  265.     }
  266.  
  267.  
  268.     ct_node* pop()
  269.     {
  270.         ct_node* head = m_head.load(std::memory_order_acquire);
  271.         ct_node* xchg;
  272.  
  273.         do
  274.         {
  275.             if (!head) return NULL;
  276.  
  277.             xchg = head->m_next.load(std::memory_order_relaxed);
  278.         }
  279.  
  280.         while (!m_head.compare_exchange_weak(
  281.             head,
  282.             xchg,
  283.             std::memory_order_acquire));
  284.  
  285.         return head;
  286.     }
  287. };
  288.  
  289.  
  290.  
  291. int main()
  292. {
  293.     std::cout << "Hello World!\n\n";
  294.     std::cout << "Chris M. Thom:assons Proxy Collector Port ver -1... lol ;^D\n\n";
  295.  
  296.     {
  297.         typedef ct_proxy<5> proxy;
  298.         proxy gc;
  299.  
  300.         gc.collect();
  301.  
  302.         {
  303.             proxy::collector& c = gc.acquire();
  304.  
  305.                 gc.collect(c, new ct_node);
  306.                 gc.collect(c, new ct_node);
  307.  
  308.                 gc.collect();
  309.  
  310.                 gc.collect(c, new ct_node);
  311.                 gc.collect(c, new ct_node);
  312.                 gc.collect(c, new ct_node);
  313.  
  314.             gc.release(c);
  315.         }
  316.  
  317.         {
  318.             proxy::collector& c = gc.acquire();
  319.  
  320.             gc.release(c);
  321.         }
  322.        
  323.         {
  324.             proxy::collector& c = gc.acquire();
  325.  
  326.             gc.collect(c, new ct_node);
  327.             gc.collect(c, new ct_node);
  328.             gc.collect();
  329.             gc.collect(c, new ct_node);
  330.             gc.collect();
  331.             gc.collect(c, new ct_node);
  332.             gc.collect(c, new ct_node);
  333.             gc.collect(c, new ct_node);
  334.             gc.release(c);
  335.         }
  336.  
  337.         gc.collect();
  338.         gc.collect();
  339.     }
  340.  
  341.     {
  342.         unsigned long node_allocations = g_debug_node_allocations.load(std::memory_order_relaxed);
  343.         unsigned long node_deallocations = g_debug_node_deallocations.load(std::memory_order_relaxed);
  344.  
  345.         std::cout << "node_allocations = " << node_allocations << "\n";
  346.         std::cout << "node_deallocations = " << node_deallocations << "\n";
  347.  
  348.         if (node_allocations != node_deallocations)
  349.         {
  350.             std::cout << "OH SHIT! NODE LEAK!!! SHIT! = " << node_allocations - node_deallocations << "\n\n";
  351.         }
  352.  
  353.     }
  354.  
  355.     return 0;
  356. }
  357.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement