Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
d608dffdaba1c3f9f89cc08150619a83ab4b16f9
[simgrid.git] / src / sthread / ObjectAccess.cpp
1 /* Copyright (c) 2002-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 /* Object access checker, for use in sthread. */
7
8 #include "simgrid/modelchecker.h"
9 #include "simgrid/s4u/Actor.hpp"
10 #include "simgrid/simix.hpp"
11 #include "src/kernel/actor/ActorImpl.hpp"
12 #include "src/kernel/actor/SimcallObserver.hpp"
13 #include "src/sthread/sthread.h"
14 #include "xbt/string.hpp"
15
16 #include <unordered_map>
17
18 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(sthread);
19
20 namespace simgrid::sthread {
21 XBT_DECLARE_ENUM_CLASS(AccessType, ENTER, EXIT, BOTH);
22
23 class ObjectAccessObserver final : public simgrid::kernel::actor::SimcallObserver {
24   AccessType type_;
25   void* objaddr_;
26   const char* objname_;
27   const char* file_;
28   int line_;
29
30 public:
31   ObjectAccessObserver(simgrid::kernel::actor::ActorImpl* actor, AccessType type, void* objaddr, const char* objname,
32                        const char* file, int line)
33       : SimcallObserver(actor), type_(type), objaddr_(objaddr), objname_(objname), file_(file), line_(line)
34   {
35   }
36   void serialize(std::stringstream& stream) const override;
37   std::string to_string() const override;
38   bool is_visible() const override { return true; }
39 };
40 void ObjectAccessObserver::serialize(std::stringstream& stream) const
41 {
42   stream << (short)mc::Transition::Type::OBJECT_ACCESS << ' ';
43   stream << (short)type_ << ' ' << objaddr_ << ' ' << objname_ << ' ' << file_ << ' ' << line_;
44 }
45 std::string ObjectAccessObserver::to_string() const
46 {
47   return std::string("AccessObject(") + objname_ + ")";
48 }
49 }; // namespace simgrid::sthread
50
51 struct ObjectOwner {
52   simgrid::kernel::actor::ActorImpl* owner = nullptr;
53   const char* file                         = nullptr;
54   int line                                 = -1;
55   ObjectOwner(simgrid::kernel::actor::ActorImpl* o) : owner(o) {}
56 };
57
58 std::unordered_map<void*, ObjectOwner*> owners;
59 static void clean_owners()
60 {
61   for (auto it = owners.begin(); it != owners.end();) {
62     delete it->second;
63     it = owners.erase(it);
64   }
65 }
66 static ObjectOwner* get_owner(void* object)
67 {
68   if (owners.empty())
69     std::atexit(clean_owners);
70   auto it = owners.find(object);
71   if (it != owners.end())
72     return it->second;
73   auto* o = new ObjectOwner(nullptr);
74   owners.insert({object, o});
75   return o;
76 }
77
78 int sthread_access_begin(void* objaddr, const char* objname, const char* file, int line)
79 {
80   sthread_disable();
81   auto* self = simgrid::kernel::actor::ActorImpl::self();
82   simgrid::sthread::ObjectAccessObserver observer(self, simgrid::sthread::AccessType::ENTER, objaddr, objname, file,
83                                                   line);
84   bool success = simgrid::kernel::actor::simcall_answered(
85       [self, objaddr, objname, file, line]() -> bool {
86         XBT_INFO("%s takes %s", self->get_cname(), objname);
87         auto* ownership = get_owner(objaddr);
88         if (ownership->owner != nullptr) {
89           auto msg = std::string("Unprotected concurent access to ") + objname + ": " + ownership->owner->get_name();
90           if (not xbt_log_no_loc)
91             msg += simgrid::xbt::string_printf(" at %s:%d", ownership->file, ownership->line);
92           msg += " vs " + self->get_name();
93           if (xbt_log_no_loc)
94             msg += std::string(" (locations hidden because of --log=no_loc).");
95           else
96             msg += simgrid::xbt::string_printf(" at %s:%d.", file, line);
97           XBT_CRITICAL("%s", msg.c_str());
98           return false;
99         }
100         ownership->owner = self;
101         ownership->file  = file;
102         ownership->line  = line;
103         return true;
104       },
105       &observer);
106   MC_assert(success);
107   xbt_assert(success, "Problem detected, bailing out");
108   sthread_enable();
109   return true;
110 }
111 void sthread_access_end(void* objaddr, const char* objname, const char* file, int line)
112 {
113   sthread_disable();
114   auto* self = simgrid::kernel::actor::ActorImpl::self();
115   simgrid::sthread::ObjectAccessObserver observer(self, simgrid::sthread::AccessType::EXIT, objaddr, objname, file,
116                                                   line);
117   simgrid::kernel::actor::simcall_answered(
118       [self, objaddr, objname]() -> void {
119         XBT_INFO("%s releases %s", self->get_cname(), objname);
120         auto* ownership = get_owner(objaddr);
121         xbt_assert(ownership->owner == self, "safety check failed: %s is not owner of the object it's releasing.",
122                    self->get_cname());
123         ownership->owner = nullptr;
124       },
125       &observer);
126   sthread_enable();
127 }