1/*
2 * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#ifndef SHARE_JFR_UTILITIES_JFRREFCOUNTPOINTER_HPP
26#define SHARE_JFR_UTILITIES_JFRREFCOUNTPOINTER_HPP
27
28#include "jfr/utilities/jfrAllocation.hpp"
29#include "runtime/atomic.hpp"
30
31template <typename T>
32class RefCountHandle {
33 template <typename, typename>
34 friend class RefCountPointer;
35 private:
36 const T* _ptr;
37
38 RefCountHandle(const T* ptr) : _ptr(ptr) {
39 assert(_ptr != NULL, "invariant");
40 _ptr->add_ref();
41 }
42
43 public:
44 RefCountHandle() : _ptr(NULL) {}
45
46 RefCountHandle(const RefCountHandle<T>& rhs) : _ptr(rhs._ptr) {
47 if (_ptr != NULL) {
48 _ptr->add_ref();
49 }
50 }
51
52 ~RefCountHandle() {
53 if (_ptr != NULL) {
54 const T* temp = _ptr;
55 _ptr = NULL;
56 temp->remove_ref();
57 }
58 }
59
60 // The copy-and-swap idiom upholds reference counting semantics
61 void operator=(RefCountHandle<T> rhs) {
62 const T* temp = rhs._ptr;
63 rhs._ptr = _ptr;
64 _ptr = temp;
65 }
66
67 bool operator==(const RefCountHandle<T>& rhs) const {
68 return _ptr == rhs._ptr;
69 }
70
71 bool operator!=(const RefCountHandle<T>& rhs) const {
72 return !operator==(rhs);
73 }
74
75 bool valid() const {
76 return _ptr != NULL;
77 }
78
79 const T & operator->() const {
80 return *_ptr;
81 }
82
83 T& operator->() {
84 return *const_cast<T*>(_ptr);
85 }
86};
87
88class MultiThreadedRefCounter {
89 private:
90 mutable volatile int _refs;
91 public:
92 MultiThreadedRefCounter() : _refs(0) {}
93
94 void inc() const {
95 Atomic::add(1, &_refs);
96 }
97
98 bool dec() const {
99 return 0 == Atomic::add((-1), &_refs);
100 }
101
102 int current() const {
103 return _refs;
104 }
105};
106
107template <typename T, typename RefCountImpl = MultiThreadedRefCounter>
108class RefCountPointer : public JfrCHeapObj {
109 template <typename>
110 friend class RefCountHandle;
111 typedef RefCountHandle<RefCountPointer<T, RefCountImpl> > RefHandle;
112 private:
113 const T* _ptr;
114 mutable RefCountImpl _refs;
115
116 // disallow multiple copies
117 RefCountPointer(const RefCountPointer<T, RefCountImpl>& rhs);
118 void operator=(const RefCountPointer<T, RefCountImpl>& rhs);
119
120 ~RefCountPointer() {
121 assert(_refs.current() == 0, "invariant");
122 delete const_cast<T*>(_ptr);
123 }
124
125 void add_ref() const {
126 _refs.inc();
127 }
128
129 void remove_ref() const {
130 if (_refs.dec()) {
131 delete this;
132 }
133 }
134
135 RefCountPointer(const T* ptr) : _ptr(ptr), _refs() {
136 assert(_ptr != NULL, "invariant");
137 }
138
139 public:
140 const T* operator->() const {
141 return _ptr;
142 }
143
144 T* operator->() {
145 return const_cast<T*>(_ptr);
146 }
147
148 static RefHandle make(const T* ptr) {
149 assert(ptr != NULL, "invariant");
150 return RefHandle(new RefCountPointer<T, RefCountImpl>(ptr));
151 }
152};
153
154#endif // SHARE_JFR_UTILITIES_JFRREFCOUNTPOINTER_HPP
155