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 | unsigned long long ts() const {
|
---|
120 | return before._links.ts;
|
---|
121 | }
|
---|
122 | };
|
---|