Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'udpor-phase6' into 'master'
[simgrid.git] / src / mc / remote / RemotePtr.hpp
1 /* Copyright (c) 2008-2023. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #ifndef SIMGRID_MC_REMOTE_PTR_HPP
7 #define SIMGRID_MC_REMOTE_PTR_HPP
8
9 #include "src/kernel/actor/ActorImpl.hpp"
10
11 namespace simgrid::mc {
12
13 /** HACK, A value from another process
14  *
15  *  This represents a value from another process:
16  *
17  *  * constructor/destructor are disabled;
18  *
19  *  * raw memory copy (std::memcpy) is used to copy Remote<T>;
20  *
21  *  * when T is a trivial type, Remote is convertible to a T.
22  *
23  *  We currently only handle the case where the type has the same layout
24  *  in the current process and in the target process: we don't handle
25  *  cross-architecture (such as 32-bit/64-bit access).
26  */
27 template <class T> class Remote {
28 private:
29   typename std::aligned_storage_t<sizeof(T), alignof(T)> buffer;
30
31 public:
32   Remote() = default;
33   explicit Remote(T const& p) { std::memcpy(&buffer, &p, sizeof buffer); }
34
35   T* get_buffer() { return reinterpret_cast<T*>(&buffer); }
36   const T* get_buffer() const { return reinterpret_cast<const T*>(&buffer); }
37   std::size_t get_buffer_size() const { return sizeof(T); }
38   operator T() const
39   {
40     static_assert(std::is_trivial<T>::value, "Cannot convert non trivial type");
41     return *get_buffer();
42   }
43   void clear() { std::memset(&buffer, 0, sizeof buffer); }
44 };
45
46 /** Pointer to a remote address-space (process, snapshot)
47  *
48  *  With this we can clearly identify the expected type of an address in the
49  *  remote process while avoiding to use native local pointers.
50  *
51  *  Some operators (+/-) assume use the size of the underlying element. This
52  *  only works if the target applications is using the same target: it won't
53  *  work for example, when inspecting a 32 bit application from a 64 bit
54  *  model-checker.
55  *
56  *  We do not actually store the target address space because we can
57  *  always detect it in context. This way `RemotePtr` is as efficient
58  *  as a `uint64_t`.
59  */
60 template <class T> class RemotePtr {
61   std::uint64_t address_ = 0;
62
63 public:
64   RemotePtr() = default;
65   explicit RemotePtr(std::nullptr_t) {}
66   explicit RemotePtr(std::uint64_t address) : address_(address) {}
67   explicit RemotePtr(T* address) : address_((std::uintptr_t)address) {}
68   explicit RemotePtr(Remote<T*> p) : address_((std::uintptr_t)*p.get_buffer()) {}
69   std::uint64_t address() const { return address_; }
70
71   /** Turn into a local pointer
72    *
73    (if the remote process is not, in fact, remote) */
74   T* local() const { return (T*)address_; }
75
76   operator bool() const { return address_; }
77   bool operator!() const { return not address_; }
78   operator RemotePtr<void>() const { return RemotePtr<void>(address_); }
79   RemotePtr<T>& operator=(std::nullptr_t)
80   {
81     address_ = 0;
82     return *this;
83   }
84   RemotePtr<T> operator+(std::uint64_t n) const { return RemotePtr<T>(address_ + n * sizeof(T)); }
85   RemotePtr<T> operator-(std::uint64_t n) const { return RemotePtr<T>(address_ - n * sizeof(T)); }
86   RemotePtr<T>& operator+=(std::uint64_t n)
87   {
88     address_ += n * sizeof(T);
89     return *this;
90   }
91   RemotePtr<T>& operator-=(std::uint64_t n)
92   {
93     address_ -= n * sizeof(T);
94     return *this;
95   }
96 };
97
98 template <class X, class Y> bool operator<(RemotePtr<X> const& x, RemotePtr<Y> const& y)
99 {
100   return x.address() < y.address();
101 }
102
103 template <class X, class Y> bool operator>(RemotePtr<X> const& x, RemotePtr<Y> const& y)
104 {
105   return x.address() > y.address();
106 }
107
108 template <class X, class Y> bool operator>=(RemotePtr<X> const& x, RemotePtr<Y> const& y)
109 {
110   return x.address() >= y.address();
111 }
112
113 template <class X, class Y> bool operator<=(RemotePtr<X> const& x, RemotePtr<Y> const& y)
114 {
115   return x.address() <= y.address();
116 }
117
118 template <class X, class Y> bool operator==(RemotePtr<X> const& x, RemotePtr<Y> const& y)
119 {
120   return x.address() == y.address();
121 }
122
123 template <class X, class Y> bool operator!=(RemotePtr<X> const& x, RemotePtr<Y> const& y)
124 {
125   return x.address() != y.address();
126 }
127
128 template <class T> inline RemotePtr<T> remote(T* p)
129 {
130   return RemotePtr<T>(p);
131 }
132
133 template <class T = void> inline RemotePtr<T> remote(uint64_t p)
134 {
135   return RemotePtr<T>(p);
136 }
137 } // namespace simgrid::mc
138
139 #endif