Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Replace ReadMode with strongly-type/safe ReadOptions
[simgrid.git] / src / mc / AddressSpace.hpp
1 /* Copyright (c) 2008-2015. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #ifndef SIMGRID_MC_ADDRESS_SPACE_H
8 #define SIMGRID_MC_ADDRESS_SPACE_H
9
10 #include <cstddef>
11 #include <cstdint>
12 #include <type_traits>
13
14 #include <xbt/misc.h>
15
16 #include "src/mc/mc_forward.hpp"
17
18 namespace simgrid {
19 namespace mc {
20
21 /** Pointer to a remote address-space (process, snapshot)
22  *
23  *  With this we can clearly identify the expected type of an address in the
24  *  remote process while avoiding to use native local pointers.
25  *
26  *  Some operators (+/-) assume use the size of the underlying element. This
27  *  only works if the target applications is using the same target: it won't
28  *  work for example, when inspecting a 32 bit application from a 64 bit
29  *  model-checker.
30  */
31 template<class T> class remote_ptr {
32   std::uint64_t address_;
33 public:
34   remote_ptr() : address_(0) {}
35   remote_ptr(std::uint64_t address) : address_(address) {}
36   remote_ptr(T* address) : address_((std::uintptr_t)address) {}
37   std::uint64_t address() const { return address_; }
38
39   operator bool() const
40   {
41     return address_;
42   }
43   bool operator!() const
44   {
45     return !address_;
46   }
47   operator remote_ptr<void>() const
48   {
49     return remote_ptr<void>(address_);
50   }
51   remote_ptr<T> operator+(std::uint64_t n) const
52   {
53     return remote_ptr<T>(address_ + n * sizeof(T));
54   }
55   remote_ptr<T> operator-(std::uint64_t n) const
56   {
57     return remote_ptr<T>(address_ - n * sizeof(T));
58   }
59   remote_ptr<T>& operator+=(std::uint64_t n)
60   {
61     address_ += n * sizeof(T);
62     return *this;
63   }
64   remote_ptr<T>& operator-=(std::uint64_t n)
65   {
66     address_ -= n * sizeof(T);
67     return *this;
68   }
69 };
70
71 template<class X, class Y>
72 bool operator<(remote_ptr<X> const& x, remote_ptr<Y> const& y)
73 {
74   return x.address() < y.address();
75 }
76
77 template<class X, class Y>
78 bool operator>(remote_ptr<X> const& x, remote_ptr<Y> const& y)
79 {
80   return x.address() > y.address();
81 }
82
83 template<class X, class Y>
84 bool operator>=(remote_ptr<X> const& x, remote_ptr<Y> const& y)
85 {
86   return x.address() >= y.address();
87 }
88
89 template<class X, class Y>
90 bool operator<=(remote_ptr<X> const& x, remote_ptr<Y> const& y)
91 {
92   return x.address() <= y.address();
93 }
94
95 template<class X, class Y>
96 bool operator==(remote_ptr<X> const& x, remote_ptr<Y> const& y)
97 {
98   return x.address() == y.address();
99 }
100
101 template<class X, class Y>
102 bool operator!=(remote_ptr<X> const& x, remote_ptr<Y> const& y)
103 {
104   return x.address() != y.address();
105 }
106
107 template<class T> inline
108 remote_ptr<T> remote(T *p)
109 {
110   return remote_ptr<T>(p);
111 }
112
113 template<class T=void> inline
114 remote_ptr<T> remote(uint64_t p)
115 {
116   return remote_ptr<T>(p);
117 }
118
119 /** Process index used when no process is available
120  *
121  *  The expected behaviour is that if a process index is needed it will fail.
122  * */
123 const int ProcessIndexMissing = -1;
124
125 /** Process index used when we don't care about the process index
126  * */
127 const int ProcessIndexDisabled = -2;
128
129 /** Constant used when any process will do.
130  *
131  *  This is is index of the first process.
132  */
133 const int ProcessIndexAny = 0;
134
135 /** Options for read operations
136  *
137  *  This is a set of flags managed with bitwise operators. Only the
138  *  meaningful operations are defined: addition, conversions to/from
139  *  integers are not allowed.
140  */
141 class ReadOptions {
142   std::uint32_t value_;
143   constexpr explicit ReadOptions(std::uint32_t value) : value_(value) {}
144 public:
145   constexpr ReadOptions() : value_(0) {}
146
147   constexpr operator bool() const { return value_ != 0; }
148   constexpr operator!() const { return value_ == 0; }
149
150   constexpr ReadOptions operator|(ReadOptions const& that) const
151   {
152     return ReadOptions(value_ | that.value_);
153   }
154   constexpr ReadOptions operator&(ReadOptions const& that) const
155   {
156     return ReadOptions(value_ & that.value_);
157   }
158   constexpr ReadOptions operator^(ReadOptions const& that) const
159   {
160     return ReadOptions(value_ ^ that.value_);
161   }
162   constexpr ReadOptions operator~() const
163   {
164     return ReadOptions(~value_);
165   }
166
167   ReadOptions& operator|=(ReadOptions const& that)
168   {
169     value_ |= that.value_;
170     return *this;
171   }
172   ReadOptions& operator&=(ReadOptions const& that)
173   {
174     value_ &= that.value_;
175     return *this;
176   }
177   ReadOptions& operator^=(ReadOptions const& that)
178   {
179     value_ &= that.value_;
180     return *this;
181   }
182
183   /** Copy the data to the given buffer */
184   static constexpr ReadOptions none() { return ReadOptions(0); }
185
186   /** Allows to return a pointer to another buffer where the data is
187    *  available instead of copying the data into the buffer
188    */
189   static constexpr ReadOptions lazy() { return ReadOptions(1); }
190 };
191
192 /** A given state of a given process (abstract base class)
193  *
194  *  Currently, this might either be:
195  *
196  *  * the current state of an existing process;
197  *
198  *  * a snapshot.
199  */
200 class AddressSpace {
201 private:
202   Process* process_;
203 public:
204   AddressSpace(Process* process) : process_(process) {}
205   virtual ~AddressSpace();
206
207   simgrid::mc::Process* process() const { return process_; }
208
209   /** Read data from the address space
210    *
211    *  @param buffer        target buffer for the data
212    *  @param size          number of bytes
213    *  @param address       remote source address of the data
214    *  @param process_index which process (used for SMPI privatization)
215    *  @param options
216    */
217   virtual const void* read_bytes(void* buffer, std::size_t size,
218     remote_ptr<void> address, int process_index = ProcessIndexAny,
219     ReadOptions options = ReadOptions::none()) const = 0;
220
221   /** Read a given data structure from the address space */
222   template<class T> inline
223   void read(T *buffer, remote_ptr<T> ptr, int process_index = ProcessIndexAny)
224   {
225     this->read_bytes(buffer, sizeof(T), ptr, process_index);
226   }
227
228   /** Read a given data structure from the address space */
229   template<class T> inline
230   T read(remote_ptr<T> ptr, int process_index = ProcessIndexMissing)
231   {
232     static_assert(std::is_trivial<T>::value, "Cannot read a non-trivial type");
233     T res;
234     return *(T*)this->read_bytes(&res, sizeof(T), ptr, process_index);
235   }
236 };
237
238 }
239 }
240
241 #endif