generic_shared_internal.hpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #ifndef CASADI_GENERIC_SHARED_INTERNAL_HPP
27 #define CASADI_GENERIC_SHARED_INTERNAL_HPP
28 
29 #include "generic_shared.hpp"
30 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
31 #include <memory>
32 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
33 
34 #ifdef CASADI_WITH_THREAD
35 #include <atomic>
36 #endif // CASADI_WITH_THREAD
37 
38 namespace casadi {
39 
42  template<typename Shared, typename Internal>
43  class GenericSharedInternal {
44  friend class GenericShared<Shared, Internal>;
45  public:
46 
48  GenericSharedInternal();
49 
51  GenericSharedInternal(const GenericSharedInternal& node);
52 
54  GenericSharedInternal& operator=(const GenericSharedInternal& node);
55 
57  virtual ~GenericSharedInternal() = 0;
58 
60  casadi_int getCount() const;
61 
62  std::string debug_repr(const Internal*) const;
63 
67  GenericWeakRef<Shared, Internal>* weak();
68 
69  protected:
71  void initSingleton() {
72  casadi_assert_dev(static_cast<Internal*>(this)->count==0);
73  static_cast<Internal*>(this)->count++;
74  }
75 
77  void destroySingleton() {
78  static_cast<Internal*>(this)->count--;
79  }
80 
82  template<class B>
83  B shared_from_this() {
84  casadi_assert_dev(B::test_cast(static_cast<Internal*>(this)));
85  B ret;
86  ret.own(static_cast<Internal*>(this));
87  return ret;
88  }
89 
91  template<class B>
92  const B shared_from_this() const {
93  casadi_assert_dev(B::test_cast(static_cast<const Internal*>(this)));
94  B ret;
95  ret.own(const_cast<Internal*>(static_cast<const Internal*>(this)));
96  return ret;
97  }
98 
99  private:
101 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
102  // Atomic so lazy publication in weak() races count_down()/teardown safely
103  std::atomic<GenericWeakRef<Shared, Internal>*> weak_ref_;
104 #else
105  GenericWeakRef<Shared, Internal>* weak_ref_;
106 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
107  };
108 
109  template<typename Shared, typename Internal>
110  class GenericWeakRefInternal : public Internal {
111  public:
112  // Constructor
113  GenericWeakRefInternal(Internal* raw);
114 
115  // Destructor
116  ~GenericWeakRefInternal() override;
117 
118  // Raw pointer to the cached object
119 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
120  // Liveness checks may race destruction; acquiring ownership still needs mutex_.
121  std::atomic<Internal*> raw_;
122 #else
123  Internal* raw_;
124 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
125 
126 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
127  mutable std::shared_ptr<std::mutex> mutex_;
128 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
129  };
130 
131 
132  template<class A>
133  A getcopy(const A& a,
134  std::map<typename A::base_type*,
135  typename A::internal_base_type> & already_copied) {
136  A ret;
137  if (!a.is_null()) {
138  auto it =
139  already_copied.find(const_cast<typename A::base_type*>(a.get()));
140  if (it!=already_copied.end()) {
141  ret.own(it->second.get());
142  }
143  }
144  return ret;
145  }
146 
148 
149 
150  template<typename Shared, typename Internal>
151  GenericSharedInternal<Shared, Internal>::
152  GenericSharedInternal(const GenericSharedInternal& node) {
153  static_cast<Internal*>(this)->count = 0; // reference counter is _not_ copied
154 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
155  weak_ref_.store(nullptr, std::memory_order_relaxed); // nor same weak references
156 #else
157  weak_ref_ = nullptr; // nor will they have the same weak references
158 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
159  }
160 
161  template<typename Shared, typename Internal>
162  GenericSharedInternal<Shared, Internal>&
163  GenericSharedInternal<Shared, Internal>::
164  operator=(const GenericSharedInternal<Shared, Internal>& node) {
165  // do _not_ copy the reference counter
166  return *this;
167  }
168 
169  template<typename Shared, typename Internal>
170  GenericSharedInternal<Shared, Internal>::GenericSharedInternal() {
171  static_cast<Internal*>(this)->count = 0;
172 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
173  weak_ref_.store(nullptr, std::memory_order_relaxed);
174 #else
175  weak_ref_ = nullptr;
176 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
177  }
178 
179  template<typename Shared, typename Internal>
180  std::string GenericSharedInternal<Shared, Internal>::debug_repr(const Internal* i) const {
181  // Note: i != this because of something something multiple inheritance
182  return str( (casadi_int)(i)) + "/" + static_cast<const Internal*>(this)->class_name();
183  }
184 
185  template<typename Shared, typename Internal>
186  GenericSharedInternal<Shared, Internal>::~GenericSharedInternal() {
187  #ifdef WITH_REFCOUNT_WARNINGS
188  if (static_cast<Internal*>(this)->count!=0) {
189  // Note that casadi_assert_warning cannot be used in destructors
190  std::cerr << "Reference counting failure." <<
191  "Possible cause: Circular dependency in user code." << std::endl;
192  }
193  #endif // WITH_REFCOUNT_WARNINGS
194 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
195  GenericWeakRef<Shared, Internal>* weak_ref =
196  weak_ref_.exchange(nullptr, std::memory_order_acq_rel);
197 #else
198  GenericWeakRef<Shared, Internal>* weak_ref = weak_ref_;
199  weak_ref_ = nullptr;
200 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
201  if (weak_ref != nullptr) {
202  // Assumption: no other GenericSharedInternal instances
203  // point to the same WeakRefInternal through weak_ref
204  weak_ref->kill();
205  delete weak_ref;
206  }
207  }
208 
209  template<typename Shared, typename Internal>
210  casadi_int GenericSharedInternal<Shared, Internal>::getCount() const {
211  return static_cast<const Internal*>(this)->count;
212  }
213 
214  template<typename Shared, typename Internal>
215  GenericWeakRef<Shared, Internal>* GenericSharedInternal<Shared, Internal>::weak() {
216 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
217  auto* w = weak_ref_.load(std::memory_order_acquire);
218  if (!w) {
219  auto* nw = new GenericWeakRef<Shared, Internal>(static_cast<Internal*>(this));
220  GenericWeakRef<Shared, Internal>* expected = nullptr;
221  if (weak_ref_.compare_exchange_strong(
222  expected, nw, std::memory_order_release, std::memory_order_acquire)) {
223  w = nw;
224  } else {
225  delete nw; // lost the race; another thread published first
226  w = expected;
227  }
228  }
229  return w;
230 #else
231  if (weak_ref_==nullptr) {
232  weak_ref_ = new GenericWeakRef<Shared, Internal>(static_cast<Internal*>(this));
233  }
234  return weak_ref_;
235 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
236  }
237 
238  template<typename Shared, typename Internal>
239  GenericWeakRefInternal<Shared, Internal>::GenericWeakRefInternal(Internal* raw) :
240  raw_(raw)
241 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
242  , mutex_(std::make_shared<std::mutex>())
243 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
244  {
245  }
246 
247  template<typename Shared, typename Internal>
248  GenericWeakRefInternal<Shared, Internal>::~GenericWeakRefInternal() {
249  }
250 
251 
252 } // namespace casadi
253 
254 
255 #endif // CASADI_GENERIC_SHARED_INTERNAL_HPP
The casadi namespace.
Definition: archiver.hpp:32