1
2
3
4
5
6 #include <cmajor/rt/Statics.hpp>
7 #include <cmajor/rt/Error.hpp>
8 #include <cmajor/rt/Io.hpp>
9 #include <soulng/util/Error.hpp>
10 #include <boost/functional/hash.hpp>
11 #include <memory>
12 #include <mutex>
13 #include <stdexcept>
14 #include <sstream>
15 #include <unordered_map>
16
17 namespace cmajor {namespace rt {
18
19 class StaticInitTable
20 {
21 public:
22 static void Init();
23 static void Done();
24 static StaticInitTable& Instance() { return *instance; }
25 void AllocateMutexes(const std::std::vector<boost::uuids::uuid>&staticClassIds);
26 void BeginCriticalSection(const boost::uuids::uuid& classId);
27 void EndCriticalSection(const boost::uuids::uuid& classId);
28 private:
29 static std::unique_ptr<StaticInitTable> instance;
30 std::vector<std::std::unique_ptr<std::recursive_mutex>>mutexes;
31 std::unordered_map<boost::uuids::uuid, int, boost::boost::hash<boost::uuids::uuid>>mutexMap;
32 };
33
34 std::unique_ptr<StaticInitTable> StaticInitTable::instance;
35
36 void StaticInitTable::Init()
37 {
38 instance.reset(new StaticInitTable());
39 }
40
41 void StaticInitTable::Done()
42 {
43 instance.reset();
44 }
45
46 void StaticInitTable::AllocateMutexes(const std::std::vector<boost::uuids::uuid>&staticClassIds)
47 {
48 int n = staticClassIds.size();
49 for (int i = 0; i < n; ++i)
50 {
51 const boost::uuids::uuid& classId = staticClassIds[i];
52 mutexMap[classId] = mutexes.size();
53 mutexes.push_back(std::unique_ptr<std::recursive_mutex>(new std::recursive_mutex()));
54 }
55 }
56
57 void StaticInitTable::BeginCriticalSection(const boost::uuids::uuid& classId)
58 {
59 auto it = mutexMap.find(classId);
60 if (it != mutexMap.cend())
61 {
62 int mutexIndex = it->second;
63 Assert(mutexIndex >= 0 && mutexIndex < mutexes.size(), "invalid mutex index");
64 std::recursive_mutex* mutex = mutexes[mutexIndex].get();
65 mutex->lock();
66 }
67 else
68 {
69 Assert(false, "invalid class id");
70 }
71 }
72
73 void StaticInitTable::EndCriticalSection(const boost::uuids::uuid& classId)
74 {
75 auto it = mutexMap.find(classId);
76 if (it != mutexMap.cend())
77 {
78 int mutexIndex = it->second;
79 Assert(mutexIndex >= 0 && mutexIndex < mutexes.size(), "invalid mutex index");
80 std::recursive_mutex* mutex = mutexes[mutexIndex].get();
81 mutex->unlock();
82 }
83 else
84 {
85 Assert(false, "invalid class id");
86 }
87 }
88
89 void AllocateMutexes(const std::std::vector<boost::uuids::uuid>&staticClassIds)
90 {
91 StaticInitTable::Instance().AllocateMutexes(staticClassIds);
92 }
93
94 typedef void(*destructor_ptr)(void* arg);
95
96 struct Destruction
97 {
98 Destruction(destructor_ptr destructor_, void* arg_, Destruction* next_) : destructor(destructor_), arg(arg_), next(next_)
99 {
100 }
101 destructor_ptr destructor;
102 void* arg;
103 Destruction* next;
104 };
105
106 Destruction* destructionList = nullptr;
107
108 void ExecuteDestructors()
109 {
110 Destruction* destruction = destructionList;
111 while (destruction)
112 {
113 destructionList = destructionList->next;
114 destruction->destructor(destruction->arg);
115 delete destruction;
116 destruction = destructionList;
117 }
118 }
119
120 void InitStatics()
121 {
122 StaticInitTable::Init();
123 }
124
125 void DoneStatics()
126 {
127 ExecuteDestructors();
128 StaticInitTable::Done();
129 }
130
131 } }
132
133 extern "C" void RtBeginStaticInitCriticalSection(void* staticClassId)
134 {
135 try
136 {
137 boost::uuids::uuid* classId = reinterpret_cast<boost::uuids::uuid*>(staticClassId);
138 cmajor::rt::StaticInitTable::Instance().BeginCriticalSection(*classId);
139 }
140 catch (const std::exception& ex)
141 {
142 std::stringstream s;
143 s << "internal error: " << ex.what() << "\n";
144 std::string str = s.str();
145 int32_t errorStringHandle = -1;
146 void* stdError = RtOpenStdFile(2, errorStringHandle);
147 RtWrite(stdError, reinterpret_cast<const uint8_t*>(str.c_str()), str.length(), errorStringHandle);
148 RtFlush(stdError, errorStringHandle);
149 exit(exitCodeInternalError);
150 }
151 }
152
153 extern "C" void RtEndStaticInitCriticalSection(void* staticClassId)
154 {
155 try
156 {
157 boost::uuids::uuid* classId = reinterpret_cast<boost::uuids::uuid*>(staticClassId);
158 cmajor::rt::StaticInitTable::Instance().EndCriticalSection(*classId);
159 }
160 catch (const std::exception& ex)
161 {
162 std::stringstream s;
163 s << "internal error: " << ex.what() << "\n";
164 std::string str = s.str();
165 int32_t errorStringHandle = -1;
166 void* stdError = RtOpenStdFile(2, errorStringHandle);
167 RtWrite(stdError, reinterpret_cast<const uint8_t*>(str.c_str()), str.length(), errorStringHandle);
168 RtFlush(stdError, errorStringHandle);
169 exit(exitCodeInternalError);
170 }
171 }
172
173 std::mutex destructionListMutex;
174
175 extern "C" void RtEnqueueDestruction(void* destructor, void* arg)
176 {
177 std::lock_guard<std::mutex> lock(destructionListMutex);
178 cmajor::rt::destructionList = new cmajor::rt::Destruction(reinterpret_cast<cmajor::rt::destructor_ptr>(destructor), arg, cmajor::rt::destructionList);
179 }
180