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 | }; |
---|