| [b232745] | 1 | #pragma once | 
|---|
|  | 2 |  | 
|---|
|  | 3 | #include "assert.hpp" | 
|---|
|  | 4 | #include "utils.hpp" | 
|---|
|  | 5 |  | 
|---|
|  | 6 | template<typename node_t> | 
|---|
|  | 7 | struct _LinksFields_t { | 
|---|
|  | 8 | node_t * prev = nullptr; | 
|---|
|  | 9 | node_t * next = nullptr; | 
|---|
|  | 10 | volatile unsigned long long ts = 0; | 
|---|
|  | 11 | unsigned hint = (unsigned)-1; | 
|---|
|  | 12 | }; | 
|---|
|  | 13 |  | 
|---|
|  | 14 | template<typename node_t> | 
|---|
|  | 15 | class __attribute__((aligned(128))) intrusive_queue_t { | 
|---|
|  | 16 | public: | 
|---|
|  | 17 | typedef spinlock_t lock_t; | 
|---|
|  | 18 |  | 
|---|
|  | 19 | struct stat { | 
|---|
|  | 20 | ssize_t diff = 0; | 
|---|
|  | 21 | size_t  push = 0; | 
|---|
|  | 22 | size_t  pop  = 0; | 
|---|
|  | 23 | }; | 
|---|
|  | 24 |  | 
|---|
|  | 25 | private: | 
|---|
|  | 26 | struct sentinel_t { | 
|---|
|  | 27 | _LinksFields_t<node_t> _links; | 
|---|
|  | 28 | }; | 
|---|
|  | 29 |  | 
|---|
|  | 30 | public: | 
|---|
|  | 31 | lock_t lock; | 
|---|
|  | 32 |  | 
|---|
|  | 33 | private: | 
|---|
|  | 34 | sentinel_t before; | 
|---|
|  | 35 | sentinel_t after; | 
|---|
|  | 36 |  | 
|---|
|  | 37 | #pragma GCC diagnostic push | 
|---|
|  | 38 | #pragma GCC diagnostic ignored "-Winvalid-offsetof" | 
|---|
|  | 39 | static constexpr auto fields_offset = offsetof( node_t, _links ); | 
|---|
|  | 40 | #pragma GCC diagnostic pop | 
|---|
|  | 41 | public: | 
|---|
|  | 42 | intrusive_queue_t() | 
|---|
|  | 43 | : before{{ nullptr, tail() }} | 
|---|
|  | 44 | , after {{ head(), nullptr }} | 
|---|
|  | 45 | { | 
|---|
|  | 46 | /* paranoid */ assert((reinterpret_cast<uintptr_t>( head() ) + fields_offset) == reinterpret_cast<uintptr_t>(&before)); | 
|---|
|  | 47 | /* paranoid */ assert((reinterpret_cast<uintptr_t>( tail() ) + fields_offset) == reinterpret_cast<uintptr_t>(&after )); | 
|---|
|  | 48 | /* paranoid */ assert(head()->_links.prev == nullptr); | 
|---|
|  | 49 | /* paranoid */ assert(head()->_links.next == tail() ); | 
|---|
|  | 50 | /* paranoid */ assert(tail()->_links.next == nullptr); | 
|---|
|  | 51 | /* paranoid */ assert(tail()->_links.prev == head() ); | 
|---|
|  | 52 | /* paranoid */ assert(sizeof(*this) == 128); | 
|---|
|  | 53 | /* paranoid */ assert((intptr_t(this) % 128) == 0); | 
|---|
|  | 54 | } | 
|---|
|  | 55 |  | 
|---|
|  | 56 | ~intrusive_queue_t() = default; | 
|---|
|  | 57 |  | 
|---|
|  | 58 | inline node_t * head() const { | 
|---|
|  | 59 | node_t * rhead = reinterpret_cast<node_t *>( | 
|---|
|  | 60 | reinterpret_cast<uintptr_t>( &before ) - fields_offset | 
|---|
|  | 61 | ); | 
|---|
|  | 62 | assert(rhead); | 
|---|
|  | 63 | return rhead; | 
|---|
|  | 64 | } | 
|---|
|  | 65 |  | 
|---|
|  | 66 | inline node_t * tail() const { | 
|---|
|  | 67 | node_t * rtail = reinterpret_cast<node_t *>( | 
|---|
|  | 68 | reinterpret_cast<uintptr_t>( &after ) - fields_offset | 
|---|
|  | 69 | ); | 
|---|
|  | 70 | assert(rtail); | 
|---|
|  | 71 | return rtail; | 
|---|
|  | 72 | } | 
|---|
|  | 73 |  | 
|---|
|  | 74 | inline bool push(node_t * node) { | 
|---|
|  | 75 | assert(lock); | 
|---|
|  | 76 | assert(node->_links.ts != 0); | 
|---|
|  | 77 | node_t * tail = this->tail(); | 
|---|
|  | 78 |  | 
|---|
|  | 79 | node_t * prev = tail->_links.prev; | 
|---|
|  | 80 | // assertf(node->_links.ts >= prev->_links.ts, | 
|---|
|  | 81 | //      "New node has smaller timestamp: %llu < %llu", node->_links.ts, prev->_links.ts); | 
|---|
|  | 82 | node->_links.next = tail; | 
|---|
|  | 83 | node->_links.prev = prev; | 
|---|
|  | 84 | prev->_links.next = node; | 
|---|
|  | 85 | tail->_links.prev = node; | 
|---|
|  | 86 |  | 
|---|
|  | 87 | if(before._links.ts == 0l) { | 
|---|
|  | 88 | before._links.ts = node->_links.ts; | 
|---|
|  | 89 | assert(node->_links.prev == this->head()); | 
|---|
|  | 90 | return true; | 
|---|
|  | 91 | } | 
|---|
|  | 92 | return false; | 
|---|
|  | 93 | } | 
|---|
|  | 94 |  | 
|---|
|  | 95 | inline std::pair<node_t *, bool> pop() { | 
|---|
|  | 96 | assert(lock); | 
|---|
|  | 97 | node_t * head = this->head(); | 
|---|
|  | 98 | node_t * tail = this->tail(); | 
|---|
|  | 99 |  | 
|---|
|  | 100 | node_t * node = head->_links.next; | 
|---|
|  | 101 | node_t * next = node->_links.next; | 
|---|
|  | 102 | if(node == tail) return {nullptr, false}; | 
|---|
|  | 103 |  | 
|---|
|  | 104 | head->_links.next = next; | 
|---|
|  | 105 | next->_links.prev = head; | 
|---|
|  | 106 |  | 
|---|
|  | 107 | if(next == tail) { | 
|---|
|  | 108 | before._links.ts = 0l; | 
|---|
|  | 109 | return {node, true}; | 
|---|
|  | 110 | } | 
|---|
|  | 111 | else { | 
|---|
|  | 112 | assert(next->_links.ts != 0); | 
|---|
|  | 113 | before._links.ts = next->_links.ts; | 
|---|
|  | 114 | assert(before._links.ts != 0); | 
|---|
|  | 115 | return {node, false}; | 
|---|
|  | 116 | } | 
|---|
|  | 117 | } | 
|---|
|  | 118 |  | 
|---|
|  | 119 | long long ts() const { | 
|---|
|  | 120 | return before._links.ts; | 
|---|
|  | 121 | } | 
|---|
|  | 122 | }; | 
|---|