MySQL 8.4.0
Source Code Documentation
gcs_mpsc_queue.h
Go to the documentation of this file.
1/* Copyright (c) 2018, 2024, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is designed to work with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have either included with
13 the program or referenced in the documentation.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
23
24#ifndef GCS_MPSC_QUEUE_INCLUDED
25#define GCS_MPSC_QUEUE_INCLUDED
26
27#include <atomic>
28#include <cassert>
29#include <memory>
30
31/**
32 * MPSC queue with FIFO semantics.
33 *
34 * Implemented as a linked list of nodes.
35 * Inspired by Dmitry Vyukov's "non-intrusive MPSC node-based queue" algorithm,
36 * available on 2017-07-10 at
37 * http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue
38 */
39template <typename T, typename Deleter = std::default_delete<T>>
41 private:
42 /**
43 * Node that holds an element (payload) of the MPSC queue.
44 */
46 public:
47 /**
48 * Creates an unlinked and empty node.
49 */
51 /**
52 * Creates an unlinked node with the given payload.
53 * The node takes ownership of @c initial_payload.
54 *
55 * @param initial_payload the payload
56 */
57 Gcs_mpsc_queue_node(T *initial_payload) : m_payload(initial_payload) {
58 m_next.store(nullptr, std::memory_order_relaxed);
59 }
60 /* Not copyable nor movable. */
65 /**
66 * Gets the next node in the linked list.
67 *
68 * @param memory_order the desired memory ordering semantics for the load
69 * @retval Gcs_mpsc_queue_node* if there is a linked node
70 * @retval nullptr otherwise
71 */
72 Gcs_mpsc_queue_node *get_next(std::memory_order memory_order) {
73 return m_next.load(memory_order);
74 }
75 /**
76 * Links a node to this node.
77 *
78 * @param node the node to link
79 * @param memory_order the desired memory ordering semantics for the store
80 */
81 void set_next(Gcs_mpsc_queue_node *node, std::memory_order memory_order) {
82 m_next.store(node, memory_order);
83 }
84 /**
85 * Extracts the payload from this node.
86 * Transfers ownership of the payload to the caller, i.e. after calling this
87 * method this node has no payload.
88 *
89 * @retval T* if there is a payload
90 * @retval nullptr otherwise
91 */
93 T *result = m_payload;
94 m_payload = nullptr;
95 return result;
96 }
97
98 private:
99 /**
100 * The next node in the linked list.
101 */
102 std::atomic<Gcs_mpsc_queue_node *> m_next;
103 /**
104 * The payload.
105 */
107 };
108
109 public:
110 /**
111 * Create an empty queue.
112 */
114 Gcs_mpsc_queue(Deleter custom_deleter)
115 : m_payload_deleter(custom_deleter), m_tail(new Gcs_mpsc_queue_node()) {
116 m_head.store(m_tail, std::memory_order_relaxed);
117 }
118 /**
119 * Destroy the queued nodes.
120 */
122 // delete the list
123 for (T *payload = pop(); payload != nullptr; payload = pop()) {
124 m_payload_deleter(payload);
125 }
126 // delete stub node
127 assert(m_tail == m_head.load(std::memory_order_relaxed));
128 delete m_tail;
129 }
130 /* Not copyable nor movable. */
135 /**
136 * Insert @c payload at the end of the queue.
137 *
138 * @param payload the element to insert
139 * @returns true if the insertion was successful, false otherwise
140 */
141 bool push(T *payload) {
142 bool successful = false;
143 auto *new_node = new (std::nothrow) Gcs_mpsc_queue_node(payload);
144 if (new_node != nullptr) {
145 Gcs_mpsc_queue_node *previous =
146 m_head.exchange(new_node, std::memory_order_acq_rel);
147 previous->set_next(new_node, std::memory_order_release);
148 successful = true;
149 }
150 return successful;
151 }
152 /**
153 * Attempt to retrieve the first element from the queue.
154 *
155 * Note that this is a non-blocking method.
156 *
157 * @retval T* if the queue is not empty
158 * @retval nullptr if the queue is empty
159 */
160 T *pop() {
161 T *result = nullptr;
162 Gcs_mpsc_queue_node *old_tail = m_tail;
164 m_tail->get_next(std::memory_order_acquire);
165 if (next_node != nullptr) {
167 delete old_tail;
169 }
170 return result;
171 }
172
173 private:
176 std::atomic<Gcs_mpsc_queue_node *> m_head; // last in
177};
178
179#endif /* GCS_MPSC_QUEUE_INCLUDED */
Kerberos Client Authentication nullptr
Definition: auth_kerberos_client_plugin.cc:251
Definition: tls_cipher.cc:37
Node that holds an element (payload) of the MPSC queue.
Definition: gcs_mpsc_queue.h:45
T * m_payload
The payload.
Definition: gcs_mpsc_queue.h:106
Gcs_mpsc_queue_node(Gcs_mpsc_queue_node &&)=delete
Gcs_mpsc_queue_node & operator=(Gcs_mpsc_queue_node const &)=delete
void set_next(Gcs_mpsc_queue_node *node, std::memory_order memory_order)
Links a node to this node.
Definition: gcs_mpsc_queue.h:81
Gcs_mpsc_queue_node()
Creates an unlinked and empty node.
Definition: gcs_mpsc_queue.h:50
std::atomic< Gcs_mpsc_queue_node * > m_next
The next node in the linked list.
Definition: gcs_mpsc_queue.h:102
Gcs_mpsc_queue_node(T *initial_payload)
Creates an unlinked node with the given payload.
Definition: gcs_mpsc_queue.h:57
Gcs_mpsc_queue_node * get_next(std::memory_order memory_order)
Gets the next node in the linked list.
Definition: gcs_mpsc_queue.h:72
Gcs_mpsc_queue_node & operator=(Gcs_mpsc_queue_node &&)=delete
Gcs_mpsc_queue_node(Gcs_mpsc_queue_node const &)=delete
T * extract_payload()
Extracts the payload from this node.
Definition: gcs_mpsc_queue.h:92
MPSC queue with FIFO semantics.
Definition: gcs_mpsc_queue.h:40
Gcs_mpsc_queue_node * m_tail
Definition: gcs_mpsc_queue.h:175
Gcs_mpsc_queue & operator=(Gcs_mpsc_queue &&)=delete
std::atomic< Gcs_mpsc_queue_node * > m_head
Definition: gcs_mpsc_queue.h:176
Gcs_mpsc_queue(Deleter custom_deleter)
Definition: gcs_mpsc_queue.h:114
Gcs_mpsc_queue(Gcs_mpsc_queue &&)=delete
Deleter m_payload_deleter
Definition: gcs_mpsc_queue.h:174
T * pop()
Attempt to retrieve the first element from the queue.
Definition: gcs_mpsc_queue.h:160
Gcs_mpsc_queue & operator=(Gcs_mpsc_queue const &)=delete
~Gcs_mpsc_queue()
Destroy the queued nodes.
Definition: gcs_mpsc_queue.h:121
Gcs_mpsc_queue()
Create an empty queue.
Definition: gcs_mpsc_queue.h:113
bool push(T *payload)
Insert payload at the end of the queue.
Definition: gcs_mpsc_queue.h:141
Gcs_mpsc_queue(Gcs_mpsc_queue const &)=delete
static std::atomic< uchar * > & next_node(LF_PINBOX *P, uchar *X)
Definition: lf_alloc-pin.cc:350
struct result result
Definition: result.h:34
Definition: result.h:30