static constexpr ReadOptions lazy() { return ReadOptions(1); }
};
-/** HACK, A value from another process
- *
- * This represents a value from another process:
- *
- * * constructor/destructor are disabled;
- *
- * * raw memory copy (std::memcpy) is used to copy Remote<T>;
- *
- * * raw memory comparison is used to compare them;
- *
- * * when T is a trivial type, Remote is convertible to a T.
- *
- * We currently only handle the case where the type has the same layout
- * in the current process and in the target process: we don't handle
- * cross-architecture (such as 32-bit/64-bit access).
- */
-template<class T>
-union Remote {
-private:
- T buffer;
-public:
- Remote() {}
- ~Remote() {}
- Remote(Remote const& that)
- {
- std::memcpy(&buffer, &that.buffer, sizeof(buffer));
- }
- Remote& operator=(Remote const& that)
- {
- std::memcpy(&buffer, &that.buffer, sizeof(buffer));
- return *this;
- }
- T* getBuffer() { return &buffer; }
- const T* getBuffer() const { return &buffer; }
- std::size_t getBufferSize() const { return sizeof(T); }
- operator T() const {
- static_assert(std::is_trivial<T>::value, "Cannot convert non trivial type");
- return buffer;
- }
- void clear()
- {
- std::memset(static_cast<void*>(&buffer), 0, sizeof(T));
- }
-};
-
/** A given state of a given process (abstract base class)
*
* Currently, this might either be:
const void* read_bytes(void* buffer, std::size_t size,
RemotePtr<void> address, int process_index = ProcessIndexAny,
ReadOptions options = ReadOptions::none()) const override;
+
void read_variable(const char* name, void* target, size_t size) const;
+ template<class T> void read_variable(const char* name, T* target) const
+ {
+ read_variable(name, target, sizeof(*target));
+ }
template<class T>
- T read_variable(const char *name) const
+ Remote<T> read_variable(const char *name) const
{
- static_assert(std::is_trivial<T>::value, "Cannot read a non-trivial type");
- T res;
- read_variable(name, &res, sizeof(T));
+ Remote<T> res;
+ read_variable(name, res.getBuffer(), sizeof(T));
return res;
}
+
std::string read_string(RemotePtr<char> address) const;
std::string read_string(RemotePtr<char> address, std::size_t len) const
{
#ifndef SIMGRID_MC_REMOTE_PTR_HPP
#define SIMGRID_MC_REMOTE_PTR_HPP
+#include <cstddef>
#include <cstdint>
+#include <cstring>
+
+#include <stdexcept>
+#include <type_traits>
namespace simgrid {
namespace mc {
+template<class M, class T, class Enable = void>
+struct pointer_to_data_member {};
+template<class M, class T>
+struct pointer_to_data_member<M,T,typename std::enable_if< std::is_union<M>::value || std::is_class<M>::value >::type> {
+ typedef T M::* type;
+};
+
+template<class M, class T>
+using pointer_to_data_member_t = typename pointer_to_data_member<M,T>::type;
+
+/** HACK, A value from another process
+ *
+ * This represents a value from another process:
+ *
+ * * constructor/destructor are disabled;
+ *
+ * * raw memory copy (std::memcpy) is used to copy Remote<T>;
+ *
+ * * raw memory comparison is used to compare them;
+ *
+ * * when T is a trivial type, Remote is convertible to a T.
+ *
+ * We currently only handle the case where the type has the same layout
+ * in the current process and in the target process: we don't handle
+ * cross-architecture (such as 32-bit/64-bit access).
+ */
+template<class T>
+union Remote {
+private:
+ T buffer;
+public:
+ Remote() {}
+ ~Remote() {}
+ Remote(T& p)
+ {
+ std::memcpy(&buffer, &p, sizeof(buffer));
+ }
+ Remote(Remote const& that)
+ {
+ std::memcpy(&buffer, &that.buffer, sizeof(buffer));
+ }
+ Remote& operator=(Remote const& that)
+ {
+ std::memcpy(&buffer, &that.buffer, sizeof(buffer));
+ return *this;
+ }
+ T* getBuffer() { return &buffer; }
+ const T* getBuffer() const { return &buffer; }
+ std::size_t getBufferSize() const { return sizeof(T); }
+ operator T() const {
+ static_assert(std::is_trivial<T>::value, "Cannot convert non trivial type");
+ return buffer;
+ }
+ void clear()
+ {
+ std::memset(static_cast<void*>(&buffer), 0, sizeof(T));
+ }
+
+};
+
/** Pointer to a remote address-space (process, snapshot)
*
* With this we can clearly identify the expected type of an address in the
RemotePtr() : address_(0) {}
RemotePtr(std::uint64_t address) : address_(address) {}
RemotePtr(T* address) : address_((std::uintptr_t)address) {}
+ RemotePtr(Remote<T*> p) : RemotePtr(*p.getBuffer()) {}
std::uint64_t address() const { return address_; }
/** Turn into a local pointer
*
(if the remote process is not, in fact, remote) */
- T* local() { return (T*) address_; }
+ T* local() const { return (T*) address_; }
operator bool() const
{
*/
static void MC_process_refresh_simix_process_list(
simgrid::mc::Process* process,
- std::vector<simgrid::mc::SimixProcessInformation>& target, xbt_swag_t remote_swag)
+ std::vector<simgrid::mc::SimixProcessInformation>& target,
+ simgrid::mc::RemotePtr<s_xbt_swag_t> remote_swag)
{
target.clear();
// swag = REMOTE(*simix_global->process_list)
s_xbt_swag_t swag;
- process->read_bytes(&swag, sizeof(swag), remote(remote_swag));
+ process->read_bytes(&swag, sizeof(swag), remote_swag);
// Load each element of the vector from the MCed process:
int i = 0;
// TODO, avoid to reload `&simix_global`, `simix_global`, `*simix_global`
- // simix_global_p = REMOTE(simix_global);
- smx_global_t simix_global_p;
- this->read_variable("simix_global", &simix_global_p, sizeof(simix_global_p));
+ static_assert(std::is_same<
+ std::unique_ptr<simgrid::simix::Global>,
+ decltype(simix_global)
+ >::value, "Unexpected type for simix_global");
+ static_assert(sizeof(simix_global) == sizeof(simgrid::simix::Global*),
+ "Bad size for simix_global");
+
+ // simix_global_p = REMOTE(simix_global.get());
+ RemotePtr<simgrid::simix::Global> simix_global_p =
+ this->read_variable<simgrid::simix::Global*>("simix_global");
// simix_global = REMOTE(*simix_global)
- union { simgrid::simix::Global simix_global };
- this->read_bytes(&simix_global, sizeof(simix_global),
- remote(simix_global_p));
+ Remote<simgrid::simix::Global> simix_global =
+ this->read<simgrid::simix::Global>(simix_global_p);
MC_process_refresh_simix_process_list(
- this, this->smx_process_infos, simix_global.process_list);
+ this, this->smx_process_infos,
+ remote(simix_global.getBuffer()->process_list));
MC_process_refresh_simix_process_list(
- this, this->smx_old_process_infos, simix_global.process_to_destroy);
+ this, this->smx_old_process_infos,
+ remote(simix_global.getBuffer()->process_to_destroy));
this->cache_flags_ |= Process::cache_simix_processes;
}