Logo AND Algorithmique Numérique Distribuée

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