Seastar
High performance C++ framework for concurrent servers
deleter.hh
1 /*
2  * This file is open source software, licensed to you under the terms
3  * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4  * distributed with this work for additional information regarding copyright
5  * ownership. You may not use this file except in compliance with the License.
6  *
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing,
12  * software distributed under the License is distributed on an
13  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14  * KIND, either express or implied. See the License for the
15  * specific language governing permissions and limitations
16  * under the License.
17  */
18 /*
19  * Copyright (C) 2014 Cloudius Systems, Ltd.
20  */
21 
22 #pragma once
23 
24 #ifndef SEASTAR_MODULE
25 #include <memory>
26 #include <cassert>
27 #include <cstdlib>
28 #include <type_traits>
29 #include <seastar/util/modules.hh>
30 #endif
31 
32 namespace seastar {
33 
36 
50 SEASTAR_MODULE_EXPORT
51 class deleter final {
52 public:
54  struct impl;
55  struct raw_object_tag {};
57 private:
58  // if bit 0 set, point to object to be freed directly.
59  impl* _impl = nullptr;
60 public:
62  deleter() noexcept = default;
63  deleter(const deleter&) = delete;
65  deleter(deleter&& x) noexcept : _impl(x._impl) { x._impl = nullptr; }
67  explicit deleter(impl* i) noexcept : _impl(i) {}
68  deleter(raw_object_tag, void* object) noexcept
69  : _impl(from_raw_object(object)) {}
72  ~deleter();
73  deleter& operator=(deleter&& x) noexcept;
74  deleter& operator=(deleter&) = delete;
80  deleter share();
82  explicit operator bool() const noexcept { return bool(_impl); }
84  void reset(impl* i) {
85  this->~deleter();
86  new (this) deleter(i);
87  }
91  void append(deleter d);
92 private:
93  static bool is_raw_object(impl* i) noexcept {
94  auto x = reinterpret_cast<uintptr_t>(i);
95  return x & 1;
96  }
97  bool is_raw_object() const noexcept {
98  return is_raw_object(_impl);
99  }
100  static void* to_raw_object(impl* i) noexcept {
101  auto x = reinterpret_cast<uintptr_t>(i);
102  return reinterpret_cast<void*>(x & ~uintptr_t(1));
103  }
104  void* to_raw_object() const noexcept {
105  return to_raw_object(_impl);
106  }
107  impl* from_raw_object(void* object) noexcept {
108  auto x = reinterpret_cast<uintptr_t>(object);
109  return reinterpret_cast<impl*>(x | 1);
110  }
111 };
112 
114 struct deleter::impl {
115  unsigned refs = 1;
116  deleter next;
117  impl(deleter next) : next(std::move(next)) {}
118  virtual ~impl() {}
119 };
121 
122 inline
124  if (is_raw_object()) {
125  std::free(to_raw_object());
126  return;
127  }
128  if (_impl && --_impl->refs == 0) {
129  delete _impl;
130  }
131 }
132 
133 inline
134 deleter& deleter::operator=(deleter&& x) noexcept {
135  if (this != &x) {
136  this->~deleter();
137  new (this) deleter(std::move(x));
138  }
139  return *this;
140 }
141 
143 template <typename Deleter>
144 struct lambda_deleter_impl final : deleter::impl {
145  Deleter del;
146  lambda_deleter_impl(deleter next, Deleter&& del)
147  : impl(std::move(next)), del(std::move(del)) {}
148  virtual ~lambda_deleter_impl() override { del(); }
149 };
150 
151 template <typename Object>
152 struct object_deleter_impl final : deleter::impl {
153  Object obj;
154  object_deleter_impl(deleter next, Object&& obj)
155  : impl(std::move(next)), obj(std::move(obj)) {}
156 };
157 
158 template <typename Object>
159 inline
160 object_deleter_impl<Object>* make_object_deleter_impl(deleter next, Object obj) {
161  return new object_deleter_impl<Object>(std::move(next), std::move(obj));
162 }
164 
165 
166 SEASTAR_MODULE_EXPORT_BEGIN
174 template <typename Object>
175 deleter
176 make_deleter(deleter next, Object o) {
177  return deleter(new lambda_deleter_impl<Object>(std::move(next), std::move(o)));
178 }
179 
185 template <typename Object>
186 deleter
187 make_deleter(Object o) {
188  return make_deleter(deleter(), std::move(o));
189 }
190 SEASTAR_MODULE_EXPORT_END
191 
193 struct free_deleter_impl final : deleter::impl {
194  void* obj;
195  free_deleter_impl(void* obj) : impl(deleter()), obj(obj) {}
196  free_deleter_impl(const free_deleter_impl&) = delete;
197  free_deleter_impl(free_deleter_impl&&) = delete;
198  virtual ~free_deleter_impl() override { std::free(obj); }
199 };
201 
202 inline
203 deleter
205  if (!_impl) {
206  return deleter();
207  }
208  if (is_raw_object()) {
209  _impl = new free_deleter_impl(to_raw_object());
210  }
211  ++_impl->refs;
212  return deleter(_impl);
213 }
214 
215 // Appends 'd' to the chain of deleters. Avoids allocation if possible. For
216 // performance reasons the current chain should be shorter and 'd' should be
217 // longer.
218 inline
220  if (!d._impl) {
221  return;
222  }
223  impl* next_impl = _impl;
224  deleter* next_d = this;
225  while (next_impl) {
226  if (next_impl == d._impl) {
227  return; // Already appended
228  }
229  if (is_raw_object(next_impl)) {
230  next_d->_impl = next_impl = new free_deleter_impl(to_raw_object(next_impl));
231  }
232 
233  if (next_impl->refs != 1) {
234  next_d->_impl = next_impl = make_object_deleter_impl(deleter(next_impl), std::move(d));
235  return;
236  }
237 
238  next_d = &next_impl->next;
239  next_impl = next_d->_impl;
240  }
241  next_d->_impl = d._impl;
242  d._impl = nullptr;
243 }
244 
245 SEASTAR_MODULE_EXPORT_BEGIN
250 inline
251 deleter
252 make_free_deleter(void* obj) {
253  if (!obj) {
254  return deleter();
255  }
256  return deleter(deleter::raw_object_tag(), obj);
257 }
258 
265 inline
266 deleter
267 make_free_deleter(deleter next, void* obj) {
268  return make_deleter(std::move(next), [obj] () mutable { std::free(obj); });
269 }
270 
273 template <typename T>
274 inline
275 deleter
277  return deleter{make_object_deleter_impl(deleter(), std::move(obj))};
278 }
279 
282 template <typename T>
283 inline
284 deleter
286  return deleter{make_object_deleter_impl(std::move(d), std::move(obj))};
287 }
288 SEASTAR_MODULE_EXPORT_END
289 
291 
292 }
Definition: deleter.hh:51
deleter() noexcept=default
Constructs an empty deleter that does nothing in its destructor.
deleter make_free_deleter(deleter next, void *obj)
Definition: deleter.hh:267
deleter make_object_deleter(T &&obj)
Definition: deleter.hh:276
void append(deleter d)
Definition: deleter.hh:219
deleter make_object_deleter(deleter d, T &&obj)
Definition: deleter.hh:285
deleter make_deleter(Object o)
Definition: deleter.hh:187
~deleter()
Destroys the deleter and carries out the encapsulated action.
Definition: deleter.hh:123
deleter share()
Definition: deleter.hh:204
deleter make_free_deleter(void *obj)
Definition: deleter.hh:252
deleter make_deleter(deleter next, Object o)
Definition: deleter.hh:176
holds the implementation parts of the metrics layer, do not use directly.
Seastar API namespace.
Definition: abort_on_ebadf.hh:26