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 : // Declares Story, a class encapsulating a collection of PlotLines. Each
16 : // PlotLine is an ordered sequence of events that will be played independently
17 : // (ie. on their own threads), with potential interactions between them via
18 : // the Backdrop and any causality constraints, themselves represented via
19 : // LinkedEvents.
20 : //
21 : // The serialized file is organized as follows:
22 : //
23 : // - PlotLines
24 : // - number of plot lines
25 : // - PlotLine0
26 : // - number of events in plot line
27 : // - Event0
28 : // - type of event 0
29 : // - serialization of event 0
30 : // - ... repeat for other events ...
31 : // - ... repeated for other plot lines ...
32 : // - causality constraints (the number of linked events is implicit)
33 : // - (linked event id) of event with input constraints
34 : // - number of input constraints
35 : // - (linked event id) of input constraint 0
36 : // - ... repeated for other constraints ...
37 :
38 : #ifndef SYZYGY_BARD_STORY_H_
39 : #define SYZYGY_BARD_STORY_H_
40 :
41 : #include "base/callback.h"
42 : #include "base/memory/scoped_vector.h"
43 : #include "base/threading/simple_thread.h"
44 : #include "syzygy/bard/event.h"
45 : #include "syzygy/core/serialization.h"
46 :
47 : namespace bard {
48 :
49 : // Container class for storing and serializing PlotLines.
50 : class Story {
51 : public:
52 : // A PlotLine is a simple ordered sequence of events. At some point we may
53 : // need additional functionality on this class but for now a vector does the
54 : // job.
55 : using PlotLine = ScopedVector<EventInterface>;
56 :
57 : // PlotLine playback thread runner.
58 : class PlotLineRunner;
59 :
60 : // Some constants used in serialization.
61 : static const uint32_t kBardMagic = 0xBA4D7355;
62 : static const uint32_t kBardVersion = 1;
63 :
64 E : Story() {}
65 :
66 : // Add a PlotLine to the Story. Story takes ownership of all the PlotLines
67 : // that it stores.
68 : // @param event a std::unique_ptr to the PlotLine to be added to the Story.
69 : // @returns a pointer to the stored PlotLine.
70 : PlotLine* AddPlotLine(std::unique_ptr<PlotLine> plot_line);
71 :
72 : // Creates a plotline, adding it to this story.
73 : // @returns a pointer to the created plotline.
74 : PlotLine* CreatePlotLine();
75 :
76 : // @name Serialization methods.
77 : // @{
78 : bool Save(core::OutArchive* out_archive) const;
79 : bool Load(core::InArchive* in_archive);
80 : // @}
81 :
82 : // Accessor for unittesting.
83 E : const ScopedVector<PlotLine>& plot_lines() const { return plot_lines_; }
84 :
85 : // Plays this story against the provided backdrop. Spins up a thread per
86 : // plot line and plays the events back as fast as possible on each thread.
87 : bool Play(void* backdrop);
88 :
89 : // For unittesting.
90 : bool operator==(const Story& story) const;
91 :
92 : private:
93 : ScopedVector<PlotLine> plot_lines_;
94 :
95 : DISALLOW_COPY_AND_ASSIGN(Story);
96 : };
97 :
98 : // Thread main body for playing back all events on a PlotLine. Since there is
99 : // lots of waiting/signaling between the various threads it is impossible for
100 : // one thread to exit with an error and the rest of them to hang. Thus each
101 : // thread communicates that it has completed via a callback.
102 : //
103 : // This uses a PlatformThread::Delegate rather than base::SimpleThread or other
104 : // implementations as those have the expectation that Join has been called for
105 : // each thread. The current implementation can't support this in the general
106 : // case as some thread's may hang if others exit with an error, meaning they
107 : // are not guaranteed to be joinable.
108 : class Story::PlotLineRunner : public base::PlatformThread::Delegate {
109 : public:
110 : // Invoked to indicate that this runner has completed.
111 : using OnCompleteCallback = base::Callback<void(PlotLineRunner*)>;
112 :
113 : PlotLineRunner(void* backdrop, PlotLine* plot_line);
114 E : ~PlotLineRunner() override {}
115 :
116 E : void set_on_complete(OnCompleteCallback on_complete) {
117 E : on_complete_ = on_complete;
118 E : }
119 :
120 : // @returns true if the playback failed.
121 E : bool Failed() const { return failed_event_ != nullptr; }
122 :
123 : // @returns the event that failed during playback, if an event failed.
124 E : EventInterface* failed_event() const { return failed_event_; }
125 :
126 : // Implementation of PlatformThread::Delegate.
127 : void ThreadMain() override;
128 :
129 : // For starting and stopping the thread.
130 : void Start();
131 : void Join();
132 :
133 : private:
134 : void RunImpl();
135 :
136 : void* backdrop_;
137 : PlotLine* plot_line_;
138 :
139 : OnCompleteCallback on_complete_;
140 :
141 : // If an error occurs, this is left pointing at the event that failed.
142 : // Useful for debugging.
143 : EventInterface* failed_event_;
144 :
145 : base::PlatformThreadHandle handle_;
146 :
147 : DISALLOW_COPY_AND_ASSIGN(PlotLineRunner);
148 : };
149 :
150 : } // namespace bard
151 :
152 : // Comparison operator for PlotLines.
153 : // @param pl1 The first plotline to compare.
154 : // @param pl2 The second plotline to compare.
155 : // @returns true if the two plotlines are equal, false otherwise.
156 : // @note This is in the root namespace so its found by test fixtures.
157 : bool operator==(const bard::Story::PlotLine& pl1,
158 : const bard::Story::PlotLine& pl2);
159 :
160 : #endif // SYZYGY_BARD_STORY_H_
|