Merge lp:~mhr3/unity-scopes-api/always-join-threads into lp:unity-scopes-api/devel
- always-join-threads
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Michal Hruby |
Approved revision: | 303 |
Merged at revision: | 301 |
Proposed branch: | lp:~mhr3/unity-scopes-api/always-join-threads |
Merge into: | lp:unity-scopes-api/devel |
Diff against target: |
231 lines (+90/-55) 2 files modified
scoperegistry/scoperegistry.cpp (+59/-41) smartscopesproxy/smartscopesproxy.cpp (+31/-14) |
To merge this branch: | bzr merge lp:~mhr3/unity-scopes-api/always-join-threads |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Marcus Tomlinson (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email:
|
This proposal supersedes a proposal from 2014-04-08.
Commit message
Always join worker threads.
Description of the change
Always join worker threads. Otherwise if something throws an exception, the thread is destructed without being joined, and that's not a good thing to do.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Marcus Tomlinson (marcustomlinson) wrote : | # |
This is cool, although, why not encapsulate completely and make this an actual class with private members and public methods. You could just add a "core::
Then, while you're at it, could you please update scoperunner and smartscopesproxy with the same fix. Thanks :)
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michal Hruby (mhr3) wrote : | # |
> This is cool, although, why not encapsulate completely and make this an actual
> class with private members and public methods. You could just add a
> "core::
> the RegistryObject constructor.
It's not generic enough, that's why I didn't encapsulate it more - for example the sigchild trap + deathobserver is only applicable to scope registry, nothing else.
> Then, while you're at it, could you please update scoperunner and
> smartscopesproxy with the same fix. Thanks :)
scoperunner is setup differently and doesn't have the issue, added to smartscopesproxy though.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:302
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Marcus Tomlinson (marcustomlinson) wrote : | # |
Looks good. Thanks!
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michal Hruby (mhr3) wrote : | # |
Pulled the failure from s-jenskins (getting 404 from the public one):
29: Test command: /tmp/buildd/
29: Test timeout computed to be: 1500
29: scoperegistry [Registry test]: unity::
29: scoperegistry [Registry test]: could not open OEM installation directory, ignoring OEM scopes
29: scoperegistry [Registry test]: unity::
29: scoperegistry [Registry test]: could not open Click installation directory, ignoring Click scopes
29: scoperegistry [Registry test]: no remote registry configured, only local scopes will be available
29: RegistryObject:
29: [==========] Running 1 test from 1 test case.
29: [----------] Global test environment set-up.
29: [----------] 1 test from Registry
29: [ RUN ] Registry.metadata
29: unknown file: Failure
29: C++ exception with description "unity:
29: [ FAILED ] Registry.metadata (724 ms)
29: [----------] 1 test from Registry (724 ms total)
29:
29: [----------] Global test environment tear-down
29: [==========] 1 test from 1 test case ran. (724 ms total)
29: [ PASSED ] 0 tests.
29: [ FAILED ] 1 test, listed below:
29: [ FAILED ] Registry.metadata
I thought this was supposed to be fixed by that awful hack?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Marcus Tomlinson (marcustomlinson) wrote : | # |
Ah right. Could you please make the following change in this branch:
In scoperegistry we need to run:
"middleware-
BEFORE
"middleware-
This way we ensure that the state receiver is ready to process requests as soon as the registry appears on the middleware.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Marcus Tomlinson (marcustomlinson) wrote : | # |
Those lines (mentioned above) are already there, we just need then to be swapped.
Thanks!
- 303. By Marcus Tomlinson
-
Init state receiver first
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:303
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Marcus Tomlinson (marcustomlinson) wrote : | # |
That should do it.
Preview Diff
1 | === modified file 'scoperegistry/scoperegistry.cpp' |
2 | --- scoperegistry/scoperegistry.cpp 2014-04-04 09:40:40 +0000 |
3 | +++ scoperegistry/scoperegistry.cpp 2014-04-09 16:25:44 +0000 |
4 | @@ -70,6 +70,58 @@ |
5 | return path; |
6 | } |
7 | |
8 | +// throwing an exception without joining with a thread is a bad, bad thing to do, so let's RAII to avoid doing it |
9 | +struct SignalThreadWrapper |
10 | +{ |
11 | + std::shared_ptr<core::posix::SignalTrap> termination_trap; |
12 | + std::shared_ptr<core::posix::SignalTrap> child_trap; |
13 | + std::unique_ptr<core::posix::ChildProcess::DeathObserver> death_observer; |
14 | + std::thread termination_trap_worker; |
15 | + std::thread child_trap_worker; |
16 | + |
17 | + SignalThreadWrapper() : |
18 | + // We shutdown the runtime whenever these signals happen. |
19 | + termination_trap(core::posix::trap_signals_for_all_subsequent_threads( |
20 | + { |
21 | + core::posix::Signal::sig_int, |
22 | + core::posix::Signal::sig_hup, |
23 | + core::posix::Signal::sig_term |
24 | + })), |
25 | + // And we maintain our list of processes with the help of sig_chld. |
26 | + child_trap(core::posix::trap_signals_for_all_subsequent_threads( |
27 | + { |
28 | + core::posix::Signal::sig_chld |
29 | + })), |
30 | + // The death observer is required to make sure that we reap all child processes |
31 | + // whenever multiple sigchld's are compressed together. |
32 | + death_observer(core::posix::ChildProcess::DeathObserver::create_once_with_signal_trap(child_trap)), |
33 | + // Starting up both traps. |
34 | + termination_trap_worker([&]() { termination_trap->run(); }), |
35 | + child_trap_worker([&]() { child_trap->run(); }) |
36 | + { |
37 | + } |
38 | + |
39 | + core::Signal<core::posix::Signal>& signal_raised() |
40 | + { |
41 | + return termination_trap->signal_raised(); |
42 | + } |
43 | + |
44 | + ~SignalThreadWrapper() |
45 | + { |
46 | + // Stop termination_trap |
47 | + termination_trap->stop(); |
48 | + if (termination_trap_worker.joinable()) |
49 | + termination_trap_worker.join(); |
50 | + |
51 | + // Please note that the child_trap must only be stopped once the |
52 | + // termination_trap thread has been joined. We otherwise will encounter |
53 | + // a race between the middleware shutting down and not receiving sigchld anymore. |
54 | + child_trap->stop(); |
55 | + if (child_trap_worker.joinable()) |
56 | + child_trap_worker.join(); |
57 | + } |
58 | +}; |
59 | + |
60 | // Return a map of <scope, config_file> pairs for all scopes (Canonical and OEM scopes). |
61 | // If a Canonical scope is overrideable and the OEM has configured a scope with the |
62 | // same id, the OEM scope overrides the Canonical one. |
63 | @@ -310,29 +362,7 @@ |
64 | |
65 | try |
66 | { |
67 | - // We shutdown the runtime whenever these signals happen. |
68 | - auto termination_trap = core::posix::trap_signals_for_all_subsequent_threads( |
69 | - { |
70 | - core::posix::Signal::sig_int, |
71 | - core::posix::Signal::sig_hup, |
72 | - core::posix::Signal::sig_term |
73 | - }); |
74 | - |
75 | - // And we maintain our list of processes with the help of sig_chld. |
76 | - auto child_trap = core::posix::trap_signals_for_all_subsequent_threads( |
77 | - { |
78 | - core::posix::Signal::sig_chld |
79 | - }); |
80 | - |
81 | - // The death observer is required to make sure that we reap all child processes |
82 | - // whenever multiple sigchld's are compressed together. |
83 | - auto death_observer = |
84 | - core::posix::ChildProcess::DeathObserver::create_once_with_signal_trap( |
85 | - child_trap); |
86 | - |
87 | - // Starting up both traps. |
88 | - std::thread termination_trap_worker([termination_trap]() { termination_trap->run(); }); |
89 | - std::thread child_trap_worker([child_trap]() { child_trap->run(); }); |
90 | + SignalThreadWrapper signal_handler_wrapper; |
91 | |
92 | // And finally creating our runtime. |
93 | RuntimeConfig rt_config(config_file); |
94 | @@ -368,7 +398,7 @@ |
95 | |
96 | // Inform the signal thread that it should shutdown the middleware |
97 | // if we get a termination signal. |
98 | - termination_trap->signal_raised().connect([middleware](core::posix::Signal signal) |
99 | + signal_handler_wrapper.signal_raised().connect([middleware](core::posix::Signal signal) |
100 | { |
101 | switch(signal) |
102 | { |
103 | @@ -383,7 +413,7 @@ |
104 | }); |
105 | |
106 | // The registry object stores the local and remote scopes |
107 | - RegistryObject::SPtr registry(new RegistryObject(*death_observer)); |
108 | + RegistryObject::SPtr registry(new RegistryObject(*signal_handler_wrapper.death_observer)); |
109 | |
110 | // Add the metadata for each scope to the lookup table. |
111 | // We do this before starting any of the scopes, so aggregating scopes don't get a lookup failure if |
112 | @@ -414,14 +444,14 @@ |
113 | load_remote_scopes(registry, middleware, ss_reg_id, ss_reg_endpoint); |
114 | } |
115 | |
116 | + // Let's add the registry's state receiver to the middleware so that scopes can inform |
117 | + // the registry of state changes. |
118 | + middleware->add_state_receiver_object("StateReceiver", registry->state_receiver()); |
119 | + |
120 | // Now that the registry table is populated, we can add the registry to the middleware, so |
121 | // it starts processing incoming requests. |
122 | middleware->add_registry_object(runtime->registry_identity(), registry); |
123 | |
124 | - // We also add the registry's state receiver to the middleware so that scopes can inform |
125 | - // the registry of state changes. |
126 | - middleware->add_state_receiver_object("StateReceiver", registry->state_receiver()); |
127 | - |
128 | // FIXME, HACK HACK HACK HACK |
129 | // The middleware should spawn scope processes with lookup() on demand. |
130 | // Because it currently does not have the plumbing, we start every scope immediately. |
131 | @@ -452,18 +482,6 @@ |
132 | // Wait until we are done, which happens if we receive a termination signal. |
133 | middleware->wait_for_shutdown(); |
134 | |
135 | - // Stop termination_trap |
136 | - termination_trap->stop(); |
137 | - if (termination_trap_worker.joinable()) |
138 | - termination_trap_worker.join(); |
139 | - |
140 | - // Please note that the child_trap must only be stopped once the |
141 | - // termination_trap thread has been joined. We otherwise will encounter |
142 | - // a race between the middleware shutting down and not receiving sigchld anymore. |
143 | - child_trap->stop(); |
144 | - if (child_trap_worker.joinable()) |
145 | - child_trap_worker.join(); |
146 | - |
147 | exit_status = 0; |
148 | } |
149 | catch (std::exception const& e) |
150 | |
151 | === modified file 'smartscopesproxy/smartscopesproxy.cpp' |
152 | --- smartscopesproxy/smartscopesproxy.cpp 2014-03-24 10:19:35 +0000 |
153 | +++ smartscopesproxy/smartscopesproxy.cpp 2014-04-09 16:25:44 +0000 |
154 | @@ -41,6 +41,35 @@ |
155 | std::cerr << "smartscopesproxy: " << msg << std::endl; |
156 | } |
157 | |
158 | +struct SignalThreadWrapper |
159 | +{ |
160 | + std::shared_ptr<core::posix::SignalTrap> termination_trap; |
161 | + std::thread termination_trap_worker; |
162 | + |
163 | + SignalThreadWrapper() : |
164 | + termination_trap(core::posix::trap_signals_for_all_subsequent_threads( |
165 | + { |
166 | + core::posix::Signal::sig_int, |
167 | + core::posix::Signal::sig_hup, |
168 | + core::posix::Signal::sig_term |
169 | + })), |
170 | + termination_trap_worker([&]() { termination_trap->run(); }) |
171 | + { |
172 | + } |
173 | + |
174 | + core::Signal<core::posix::Signal>& signal_raised() |
175 | + { |
176 | + return termination_trap->signal_raised(); |
177 | + } |
178 | + |
179 | + ~SignalThreadWrapper() |
180 | + { |
181 | + termination_trap->stop(); |
182 | + if (termination_trap_worker.joinable()) |
183 | + termination_trap_worker.join(); |
184 | + } |
185 | +}; |
186 | + |
187 | int main(int argc, char* argv[]) |
188 | { |
189 | if (argc > 1 && (std::string("-h") == argv[1] || std::string("--help") == argv[1])) |
190 | @@ -76,12 +105,7 @@ |
191 | |
192 | try |
193 | { |
194 | - auto trap = core::posix::trap_signals_for_all_subsequent_threads( |
195 | - { |
196 | - core::posix::Signal::sig_int, |
197 | - core::posix::Signal::sig_hup, |
198 | - core::posix::Signal::sig_term |
199 | - }); |
200 | + SignalThreadWrapper signal_handler; |
201 | |
202 | ///! TODO: get these from config |
203 | std::string ss_reg_id = "SSRegistry"; |
204 | @@ -102,14 +126,12 @@ |
205 | MiddlewareBase::SPtr reg_mw = reg_rt->factory()->find(ss_reg_id, mw_kind); |
206 | MiddlewareBase::SPtr scope_mw = scope_rt->factory()->create(ss_scope_id, mw_kind, mw_configfile); |
207 | |
208 | - trap->signal_raised().connect([reg_mw, scope_mw](core::posix::Signal) |
209 | + signal_handler.signal_raised().connect([reg_mw, scope_mw](core::posix::Signal) |
210 | { |
211 | scope_mw->stop(); |
212 | reg_mw->stop(); |
213 | }); |
214 | |
215 | - std::thread trap_worker([trap]() { trap->run(); }); |
216 | - |
217 | // Instantiate a SS registry object |
218 | SSRegistryObject::SPtr reg(new SSRegistryObject(reg_mw, scope_mw->get_scope_endpoint(), |
219 | http_reply_timeout, ss_reg_refresh_rate)); |
220 | @@ -131,11 +153,6 @@ |
221 | scope_mw->wait_for_shutdown(); |
222 | reg_mw->wait_for_shutdown(); |
223 | |
224 | - trap->stop(); |
225 | - |
226 | - if (trap_worker.joinable()) |
227 | - trap_worker.join(); |
228 | - |
229 | exit_status = 0; |
230 | } |
231 | catch (std::exception const& e) |
PASSED: Continuous integration, rev:301 jenkins. qa.ubuntu. com/job/ unity-scopes- api-devel- ci/376/ jenkins. qa.ubuntu. com/job/ unity-scopes- api-devel- trusty- amd64-ci/ 377 jenkins. qa.ubuntu. com/job/ unity-scopes- api-devel- trusty- armhf-ci/ 376 jenkins. qa.ubuntu. com/job/ unity-scopes- api-devel- trusty- armhf-ci/ 376/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ unity-scopes- api-devel- trusty- i386-ci/ 376
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity- scopes- api-devel- ci/376/ rebuild
http://