1 : // Copyright 2015 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/bard/story.h"
16 :
17 : #include "base/bind.h"
18 : #include "base/synchronization/condition_variable.h"
19 : #include "syzygy/bard/events/heap_alloc_event.h"
20 : #include "syzygy/bard/events/heap_create_event.h"
21 : #include "syzygy/bard/events/heap_destroy_event.h"
22 : #include "syzygy/bard/events/heap_free_event.h"
23 : #include "syzygy/bard/events/heap_realloc_event.h"
24 : #include "syzygy/bard/events/heap_set_information_event.h"
25 : #include "syzygy/bard/events/heap_size_event.h"
26 : #include "syzygy/bard/events/linked_event.h"
27 :
28 : namespace bard {
29 :
30 : namespace {
31 :
32 : using events::LinkedEvent;
33 :
34 : } // namespace
35 :
36 E : Story::PlotLine* Story::AddPlotLine(std::unique_ptr<PlotLine> plot_line) {
37 E : PlotLine* pl = plot_line.get();
38 E : plot_lines_.push_back(plot_line.release());
39 E : return pl;
40 E : }
41 :
42 E : Story::PlotLine* Story::CreatePlotLine() {
43 E : PlotLine* plot_line = new PlotLine();
44 E : plot_lines_.push_back(plot_line);
45 E : return plot_line;
46 E : }
47 :
48 E : bool Story::Save(core::OutArchive* out_archive) const {
49 E : std::map<const LinkedEvent*, size_t> linked_event_ids;
50 :
51 : // Serialize the number of plot lines.
52 E : out_archive->Save(plot_lines_.size());
53 :
54 : // Save each plot line.
55 E : for (PlotLine* plot_line : plot_lines_) {
56 E : if (!out_archive->Save(plot_line->size())) {
57 i : return false;
58 : }
59 :
60 E : for (const EventInterface* event : *plot_line) {
61 E : if (!EventInterface::Save(event, out_archive))
62 i : return false;
63 :
64 : // Assign an integer ID to linked events so that the connections
65 : // between them can be expressed.
66 E : if (event->type() == EventInterface::kLinkedEvent) {
67 : const LinkedEvent* linked_event =
68 E : reinterpret_cast<const LinkedEvent*>(event);
69 E : linked_event_ids.insert(
70 : std::make_pair(linked_event, linked_event_ids.size()));
71 : }
72 E : }
73 E : }
74 :
75 : // Serialize the linked event connections.
76 E : for (auto event_id_pair : linked_event_ids) {
77 E : const LinkedEvent* linked_event = event_id_pair.first;
78 :
79 : // Save the ID of this event and the number of input dependencies.
80 E : if (!out_archive->Save(event_id_pair.second))
81 i : return false;
82 E : if (!out_archive->Save(linked_event->deps().size()))
83 i : return false;
84 :
85 : // Save the ID of each input dependency.
86 E : for (auto dep : linked_event->deps()) {
87 E : auto it = linked_event_ids.find(dep);
88 E : DCHECK(it != linked_event_ids.end());
89 E : if (!out_archive->Save(it->second))
90 i : return false;
91 E : }
92 E : }
93 :
94 E : return true;
95 E : }
96 :
97 E : bool Story::Load(core::InArchive* in_archive) {
98 E : std::vector<LinkedEvent*> linked_events_by_id;
99 :
100 E : size_t plot_line_count = 0;
101 E : if (!in_archive->Load(&plot_line_count))
102 i : return false;
103 :
104 : // Read the plot lines.
105 E : for (size_t i = 0; i < plot_line_count; ++i) {
106 E : std::unique_ptr<PlotLine> plot_line(new PlotLine());
107 :
108 : // Read the events.
109 E : size_t event_count = 0;
110 E : if (!in_archive->Load(&event_count))
111 i : return false;
112 E : for (size_t j = 0; j < event_count; ++j) {
113 E : std::unique_ptr<EventInterface> event = EventInterface::Load(in_archive);
114 E : if (!event.get())
115 i : return false;
116 :
117 E : if (event->type() == EventInterface::kLinkedEvent) {
118 E : LinkedEvent* linked_event = reinterpret_cast<LinkedEvent*>(event.get());
119 E : linked_events_by_id.push_back(linked_event);
120 : }
121 :
122 E : plot_line->push_back(event.release());
123 E : }
124 :
125 E : plot_lines_.push_back(plot_line.release());
126 E : }
127 :
128 : // Deserialize event dependencies.
129 E : for (size_t i = 0; i < linked_events_by_id.size(); ++i) {
130 E : size_t event_id = 0;
131 E : if (!in_archive->Load(&event_id))
132 i : return false;
133 E : DCHECK_GT(linked_events_by_id.size(), event_id);
134 E : LinkedEvent* event = linked_events_by_id[event_id];
135 :
136 E : size_t dep_count = 0;
137 E : if (!in_archive->Load(&dep_count))
138 i : return false;
139 :
140 : // Deserialize the dependencies and emit them.
141 E : for (size_t j = 0; j < dep_count; ++j) {
142 E : size_t dep_id = 0;
143 E : if (!in_archive->Load(&dep_id))
144 i : return false;
145 E : DCHECK_GT(linked_events_by_id.size(), dep_id);
146 E : LinkedEvent* dep = linked_events_by_id[dep_id];
147 E : event->AddDep(dep);
148 E : }
149 E : }
150 :
151 E : return true;
152 E : }
153 :
154 : namespace {
155 :
156 : struct RunnerInfo {
157 E : RunnerInfo() : cv(&lock), completed_count(0), failed(nullptr) {}
158 :
159 : base::Lock lock;
160 : base::ConditionVariable cv;
161 : size_t completed_count;
162 : Story::PlotLineRunner* failed;
163 : };
164 :
165 : // Callback used to keep track of which runners have finished.
166 E : void OnComplete(RunnerInfo* info, Story::PlotLineRunner* runner) {
167 E : DCHECK_NE(static_cast<RunnerInfo*>(nullptr), info);
168 E : DCHECK_NE(static_cast<Story::PlotLineRunner*>(nullptr), runner);
169 :
170 E : base::AutoLock auto_lock(info->lock);
171 E : ++info->completed_count;
172 E : if (runner->Failed())
173 E : info->failed = runner;
174 E : info->cv.Signal();
175 E : }
176 :
177 : } // namespace
178 :
179 E : bool Story::Play(void* backdrop) {
180 : // Set up the callback for each runner to invoke.
181 E : RunnerInfo info;
182 E : auto on_complete = base::Bind(&OnComplete, base::Unretained(&info));
183 :
184 : // Create all of the runners and threads for them.
185 E : ScopedVector<PlotLineRunner> runners;
186 E : for (auto plot_line : plot_lines_) {
187 E : auto runner = new PlotLineRunner(backdrop, plot_line);
188 E : runner->set_on_complete(on_complete);
189 E : runners.push_back(runner);
190 E : }
191 :
192 : // Start the threads.
193 E : for (auto runner : runners)
194 E : runner->Start();
195 :
196 : // Wait for all threads to finish successfully, or for one to fail.
197 E : bool success = true;
198 E : while (true) {
199 : // Wait for at least one runner to complete.
200 E : base::AutoLock auto_lock(info.lock);
201 E : info.cv.Wait();
202 :
203 E : if (info.failed) {
204 E : success = false;
205 E : break;
206 : }
207 :
208 E : if (info.completed_count == runners.size())
209 E : break;
210 E : }
211 :
212 E : return success;
213 E : }
214 :
215 E : bool Story::operator==(const Story& story) const {
216 E : if (plot_lines().size() != story.plot_lines().size())
217 i : return false;
218 E : for (size_t i = 0; i < plot_lines().size(); ++i) {
219 E : if (!(*plot_lines()[i] == *story.plot_lines()[i]))
220 i : return false;
221 E : }
222 E : return true;
223 E : }
224 :
225 : Story::PlotLineRunner::PlotLineRunner(void* backdrop, PlotLine* plot_line)
226 E : : backdrop_(backdrop),
227 E : plot_line_(plot_line),
228 E : failed_event_(nullptr) {
229 E : }
230 :
231 E : void Story::PlotLineRunner::ThreadMain() {
232 E : base::PlatformThread::SetName("PlotLineRunner");
233 E : RunImpl();
234 E : if (!on_complete_.is_null())
235 E : on_complete_.Run(this);
236 E : }
237 :
238 E : void Story::PlotLineRunner::Start() {
239 E : DCHECK(handle_.is_null());
240 E : CHECK(base::PlatformThread::Create(0, this, &handle_));
241 E : }
242 :
243 E : void Story::PlotLineRunner::Join() {
244 E : DCHECK(!handle_.is_null());
245 E : base::PlatformThread::Join(handle_);
246 E : }
247 :
248 E : void Story::PlotLineRunner::RunImpl() {
249 E : for (size_t i = 0; i < plot_line_->size(); ++i) {
250 E : auto evt = (*plot_line_)[i];
251 E : if (!evt->Play(backdrop_)) {
252 E : failed_event_ = evt;
253 E : return;
254 : }
255 E : }
256 E : }
257 :
258 : } // namespace bard
259 :
260 : bool operator==(const bard::Story::PlotLine& pl1,
261 E : const bard::Story::PlotLine& pl2) {
262 E : if (pl1.size() != pl2.size())
263 i : return false;
264 E : for (size_t i = 0; i < pl1.size(); ++i) {
265 E : if (!pl1[i]->Equals(pl2[i]))
266 i : return false;
267 E : }
268 E : return true;
269 E : }
|