Path: blob/master/src/hotspot/share/jfr/utilities/jfrConcurrentLinkedListHost.hpp
41149 views
/*1* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#ifndef SHARE_JFR_UTILITIES_JFRCONCURRENTLINKEDLISTHOST_HPP25#define SHARE_JFR_UTILITIES_JFRCONCURRENTLINKEDLISTHOST_HPP2627#include "jfr/utilities/jfrAllocation.hpp"2829/*30* This implementation is a derivation from Harris31* https://www.cl.cam.ac.uk/research/srg/netos/papers/2001-caslists.pdf32*33* A concurrent LIFO structure can be built using the pair:34*35* insert_head() and remove()36*37* The LIFO algorithm is non-blocking, more specifically wait-free.38* When combined with a system for safe memory reclamation, where a thread will require39* to know if other threads are possibly reading the memory that is to be reclaimed (more below),40* a potential wait point is introduced, so technically, we are no longer wait-free.41* The combination is still lock-free, but since it is no longer pure non-blocking,42* we instead say the solution is concurrent.43*44* It is also possible to build a FIFO structure using the pair:45*46* insert_tail() and remove()47*48* To allow FIFO, the solution extends support to mark, or reserve a node, not only as part of deletions49* as with the LIFO case, but also, to enable tail insertions.50*51* Compared to the LIFO algorithm, the FIFO algorithm is not non-blocking, because inserts to the tail block,52* making it not lock-free. remove() is lock-free up until the last node in the list. In practice, the FIFO53* solution can be used in certain ways that very closely approximate non-blocking, for example, situations54* involving a single producer and multiple consumers.55*56* Although the FIFO algorithm is not non-blocking, it includes an optimization for remove() that is attractive:57* In the LIFO case, a slow path taken as the result of a failed excision would have to re-traverse the list58* to find the updated adjacent node pair for the already marked node. However, that node might already have59* been excised by some other thread, letting the thread potentially traverse the entire list just to discover60* it is no longer present (not an issue if the list is ordered by a key, then traversal is only to node >= key).61* In the FIFO case, premised on the invariant that inserts only come in from the tail, it is possible to prove62* a failed cas not to be the result of a new node inserted as with the LIFO case. With FIFO, there is only a single63* failure mode, i.e. some other thread excised the node already. Therefore, in the FIFO case, we skip the slow-path search pass.64*65* We say that the FIFO solution is "mostly" concurrent, in certain situations.66*67* Safe memory reclamation is based on a reference tracking scheme based on versioning, implemented using JfrVersionSystem.68* An access to the list is "versioned", with clients checking out the latest version describing the list.69* Destructive modifications made by clients, i.e. deletions, are signalled by incrementing the version.70* Before reclamation, a client inspects JfrVersionSystem to ensure checkouts with versions strictly71* less than the version of the modification have been relinquished. See utilities/JfrVersionSystem.hpp.72*73* Insertions can only take place from one end of the list, head or tail, exclusively.74* Specializations, a.k.a clients, must ensure this requirement.75*/7677template <typename Client, template <typename> class SearchPolicy, typename AllocPolicy = JfrCHeapObj>78class JfrConcurrentLinkedListHost : public AllocPolicy {79private:80Client* _client;81typedef typename Client::Node Node;82typedef Node* NodePtr;83typedef const Node* ConstNodePtr;84typedef typename Client::VersionSystem::Type VersionType;85typedef typename Client::VersionSystem::Handle VersionHandle;86public:87JfrConcurrentLinkedListHost(Client* client);88bool initialize();89void insert_head(NodePtr node, NodePtr head, ConstNodePtr tail) const;90void insert_tail(NodePtr node, NodePtr head, NodePtr last, ConstNodePtr tail) const;91NodePtr remove(NodePtr head, ConstNodePtr tail, NodePtr last = NULL, bool insert_is_head = true);92template <typename Callback>93void iterate(NodePtr head, ConstNodePtr tail, Callback& cb);94bool in_list(ConstNodePtr node, NodePtr head, ConstNodePtr tail) const;95};9697#endif // SHARE_JFR_UTILITIES_JFRCONCURRENTLINKEDLISTHOST_HPP9899100