Merge lp:~michihenning/unity-scopes-api/signal-before-unlock into lp:unity-scopes-api

Proposed by Michi Henning
Status: Merged
Approved by: Michi Henning
Approved revision: 41
Merged at revision: 41
Proposed branch: lp:~michihenning/unity-scopes-api/signal-before-unlock
Merge into: lp:unity-scopes-api
Diff against target: 321 lines (+44/-77)
8 files modified
demo/client.cpp (+2/-4)
demo/scope-C.cpp (+5/-10)
demo/scope-D.cpp (+5/-10)
src/unity/api/scopes/internal/Reaper.cpp (+5/-7)
src/unity/api/scopes/internal/ReplyObject.cpp (+0/-1)
src/unity/api/scopes/internal/ScopeLoader.cpp (+27/-41)
src/unity/api/scopes/internal/zmq_middleware/ObjectAdapter.cpp (+0/-2)
src/unity/api/scopes/internal/zmq_middleware/ZmqMiddleware.cpp (+0/-2)
To merge this branch: bzr merge lp:~michihenning/unity-scopes-api/signal-before-unlock
Reviewer Review Type Date Requested Status
Marcus Tomlinson (community) Approve
Review via email: mp+192634@code.launchpad.net

Commit message

Changed code to signal condvar while still holding the lock. No correctness issue here. The change is mainly to stop warnings from helgrind, which doesn't like signals outside a lock.

Description of the change

Changed code to signal condvar while still holding the lock. No correctness issue here. The change is mainly to stop warnings from helgrind, which doesn't like signals outside a lock.

To post a comment you must log in.
Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

I believe we should always attempt to have mutexes lock and unlock at their most efficient points in code (Its one of those optimisations you can foresee while coding). I see RAII mutexes as great safety nets when making a mistake, or when a scope is exited unexpectedly. My point is, perhaps we should not remove those lock.unlock() lines completely, but instead move them a line below the notify. This not only gives the thread a few more clock ticks now, but later allows for code to be added to these methods without causing the mutex to be held any longer than it needs to.

review: Needs Information
Revision history for this message
Michi Henning (michihenning) wrote :

Hmmm... Pretty much all the places where there is a notify or notify_all, that is immediately followed by a close of hte scope, a break, or a return, which all do the unlock.

Which unlock() calls would you restore and put after the notify?

Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

Ok sure, apart from the one removed from ScopeLoader.cpp, all mutexes are unlocked implicitly almost immediately. This is fine provided that the methods stay this way. If one of these methods were extended further, or a complex temporary were added and required clean up, we could cause the mutex to be held longer unintentionally in the future. Its your call really, just putting it out there :) The fix is correct and working.

Revision history for this message
Marcus Tomlinson (marcustomlinson) :
review: Approve
Revision history for this message
Michi Henning (michihenning) wrote :

Well, if I add code later that depends on holding a lock, I need to examine the lock scopes anyway, just as I do if I add code later that shouldn't hold a lock. It's just something we need to think about when changing threaded code, no matter what convention we use to unlock.

The unlock() in ScopeLoader.cpp could stay and would release the mutex a little earlier. But then we end up with noise from helgrind again when the notify happens further down if we took the code path where the unlock() call was.

I think, on balance, it's probably better to leave it as is. At least until we find that it's broken :-)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'demo/client.cpp'
2--- demo/client.cpp 2013-09-23 06:13:06 +0000
3+++ demo/client.cpp 2013-10-25 04:17:24 +0000
4@@ -41,10 +41,8 @@
5 virtual void finished() override
6 {
7 cout << "query complete" << endl;
8- {
9- unique_lock<decltype(mutex_)> lock(mutex_);
10- query_complete_ = true;
11- }
12+ unique_lock<decltype(mutex_)> lock(mutex_);
13+ query_complete_ = true;
14 condvar_.notify_one();
15 }
16
17
18=== modified file 'demo/scope-C.cpp'
19--- demo/scope-C.cpp 2013-08-28 06:26:46 +0000
20+++ demo/scope-C.cpp 2013-10-25 04:17:24 +0000
21@@ -44,10 +44,8 @@
22 public:
23 void put(MyQuery const* query, string const& query_string, ReplyProxy const& reply_proxy)
24 {
25- {
26- std::lock_guard<std::mutex> lock(mutex_);
27- queries_.push_back(QueryData { query, query_string, reply_proxy });
28- }
29+ std::lock_guard<std::mutex> lock(mutex_);
30+ queries_.push_back(QueryData { query, query_string, reply_proxy });
31 condvar_.notify_one();
32 }
33
34@@ -57,7 +55,6 @@
35 condvar_.wait(lock, [this] { return !queries_.empty() || done_; });
36 if (done_)
37 {
38- lock.unlock();
39 condvar_.notify_all();
40 }
41 else
42@@ -88,11 +85,9 @@
43
44 void finish()
45 {
46- {
47- std::unique_lock<std::mutex> lock(mutex_);
48- queries_.clear();
49- done_ = true;
50- }
51+ std::unique_lock<std::mutex> lock(mutex_);
52+ queries_.clear();
53+ done_ = true;
54 condvar_.notify_all();
55 }
56
57
58=== modified file 'demo/scope-D.cpp'
59--- demo/scope-D.cpp 2013-08-28 06:26:46 +0000
60+++ demo/scope-D.cpp 2013-10-25 04:17:24 +0000
61@@ -47,10 +47,8 @@
62 public:
63 void put(MyQuery const* query, string const& query_string, ReplyProxy const& reply_proxy)
64 {
65- {
66- std::lock_guard<std::mutex> lock(mutex_);
67- queries_.push_back(QueryData { query, query_string, reply_proxy });
68- }
69+ std::lock_guard<std::mutex> lock(mutex_);
70+ queries_.push_back(QueryData { query, query_string, reply_proxy });
71 condvar_.notify_one();
72 }
73
74@@ -60,7 +58,6 @@
75 condvar_.wait(lock, [this] { return !queries_.empty() || done_; });
76 if (done_)
77 {
78- lock.unlock();
79 condvar_.notify_all();
80 }
81 else
82@@ -91,11 +88,9 @@
83
84 void finish()
85 {
86- {
87- std::unique_lock<std::mutex> lock(mutex_);
88- queries_.clear();
89- done_ = true;
90- }
91+ std::unique_lock<std::mutex> lock(mutex_);
92+ queries_.clear();
93+ done_ = true;
94 condvar_.notify_all();
95 }
96
97
98=== modified file 'src/unity/api/scopes/internal/Reaper.cpp'
99--- src/unity/api/scopes/internal/Reaper.cpp 2013-08-27 06:28:14 +0000
100+++ src/unity/api/scopes/internal/Reaper.cpp 2013-10-25 04:17:24 +0000
101@@ -126,8 +126,8 @@
102 {
103 lock_guard<mutex> lock(mutex_);
104 finish_ = true;
105+ do_work_.notify_one();
106 }
107- do_work_.notify_one();
108 reap_thread_.join();
109 }
110
111@@ -161,17 +161,15 @@
112
113 // Put new Item at the head of the list.
114 reaper_private::Reaplist::iterator ri;
115- size_t list_size;
116 {
117 lock_guard<mutex> lock(mutex_);
118 Item item(cb);
119 list_.push_front(item); // LRU order
120 ri = list_.begin();
121- list_size = list_.size();
122- }
123- if (list_size == 1) // List just became non-empty
124- {
125- do_work_.notify_one(); // Wake up reaper thread
126+ if (list_.size() == 1) // List just became non-empty
127+ {
128+ do_work_.notify_one(); // Wake up reaper thread
129+ }
130 }
131
132 // Make a new ReapItem.
133
134=== modified file 'src/unity/api/scopes/internal/ReplyObject.cpp'
135--- src/unity/api/scopes/internal/ReplyObject.cpp 2013-08-27 06:28:14 +0000
136+++ src/unity/api/scopes/internal/ReplyObject.cpp 2013-10-25 04:17:24 +0000
137@@ -117,7 +117,6 @@
138 lock.lock();
139 if (--num_push_ == 0)
140 {
141- lock.unlock();
142 idle_.notify_one();
143 }
144 }
145
146=== modified file 'src/unity/api/scopes/internal/ScopeLoader.cpp'
147--- src/unity/api/scopes/internal/ScopeLoader.cpp 2013-08-20 05:25:28 +0000
148+++ src/unity/api/scopes/internal/ScopeLoader.cpp 2013-10-25 04:17:24 +0000
149@@ -145,8 +145,8 @@
150 // FALLTHROUGH
151 case ScopeState::Finished:
152 {
153+ cmd_changed_.notify_all();
154 lock.unlock();
155- cmd_changed_.notify_all();
156 if (run_thread_.joinable()) // If unload is called more than once, don't join a second time.
157 {
158 run_thread_.join();
159@@ -183,11 +183,9 @@
160 {
161 case ScopeState::Stopped:
162 {
163- {
164- // cppcheck-suppress unreadVariable
165- lock_guard<mutex> lock(cmd_mutex_);
166- cmd_ = ScopeCmd::Start;
167- }
168+ // cppcheck-suppress unreadVariable
169+ lock_guard<mutex> lock(cmd_mutex_);
170+ cmd_ = ScopeCmd::Start;
171 cmd_changed_.notify_all();
172 break;
173 }
174@@ -225,12 +223,11 @@
175 {
176 case ScopeState::Started:
177 {
178- {
179- // cppcheck-suppress unreadVariable
180- lock_guard<mutex> lock(cmd_mutex_);
181- cmd_ = ScopeCmd::Stop;
182- }
183+ // cppcheck-suppress unreadVariable
184+ lock_guard<mutex> lock(cmd_mutex_);
185+ cmd_ = ScopeCmd::Stop;
186 cmd_changed_.notify_all();
187+ break;
188 }
189 case ScopeState::Stopped:
190 case ScopeState::Finished:
191@@ -286,26 +283,22 @@
192 unity::util::ResourcePtr<ScopeBase*, decltype(destroy_func)> scope_base(create_func(), destroy_func);
193 if (scope_base.get() == nullptr)
194 {
195- {
196- // cppcheck-suppress unreadVariable
197- unique_lock<mutex> lock(state_mutex_);
198- scope_state_ = ScopeState::Failed;
199- exception_ = make_exception_ptr(
200- unity::ResourceException("Scope " + scope_name_ +
201- " returned nullptr from " + UNITY_API_SCOPE_CREATE_SYMSTR));
202- }
203+ // cppcheck-suppress unreadVariable
204+ unique_lock<mutex> lock(state_mutex_);
205+ scope_state_ = ScopeState::Failed;
206+ exception_ = make_exception_ptr(
207+ unity::ResourceException("Scope " + scope_name_ +
208+ " returned nullptr from " + UNITY_API_SCOPE_CREATE_SYMSTR));
209 state_changed_.notify_all();
210 return;
211 }
212
213 // Notify the parent thread that we are ready to go.
214 {
215- {
216- // cppcheck-suppress unreadVariable
217- unique_lock<mutex> lock(state_mutex_);
218- scope_state_ = ScopeState::Stopped;
219- scope_base_ = scope_base.get();
220- }
221+ // cppcheck-suppress unreadVariable
222+ unique_lock<mutex> lock(state_mutex_);
223+ scope_state_ = ScopeState::Stopped;
224+ scope_base_ = scope_base.get();
225 state_changed_.notify_all();
226 }
227
228@@ -397,7 +390,6 @@
229 unity::ResourceException("scope " + scope_name_ + ": unknown exception in stop()"));
230 throw;
231 }
232- lock.unlock();
233 if (run_thread_.joinable())
234 {
235 run_thread_.join();
236@@ -436,11 +428,9 @@
237
238 void ScopeLoader::handle_thread_exception()
239 {
240- {
241- // cppcheck-suppress unreadVariable
242- lock_guard<mutex> lock(state_mutex_);
243- scope_state_ = ScopeState::Failed;
244- }
245+ // cppcheck-suppress unreadVariable
246+ lock_guard<mutex> lock(state_mutex_);
247+ scope_state_ = ScopeState::Failed;
248 state_changed_.notify_all();
249 }
250
251@@ -465,24 +455,20 @@
252 exception_ = make_exception_ptr(
253 unity::ResourceException("Scope " + scope_name_ + ": exception in run()"));
254 scope_state_ = ScopeState::Failed;
255+ state_changed_.notify_all();
256 }
257- state_changed_.notify_all();
258
259- {
260- // cppcheck-suppress unreadVariable
261- lock_guard<mutex> lock(cmd_mutex_);
262- cmd_ = ScopeCmd::Stop;
263- }
264+ // cppcheck-suppress unreadVariable
265+ lock_guard<mutex> lock(cmd_mutex_);
266+ cmd_ = ScopeCmd::Stop;
267 cmd_changed_.notify_all();
268 }
269 }
270
271 void ScopeLoader::notify_app_thread_started()
272 {
273- {
274- unique_lock<mutex> lock(run_thread_mutex_);
275- run_thread_state_ = AppState::Started;
276- }
277+ unique_lock<mutex> lock(run_thread_mutex_);
278+ run_thread_state_ = AppState::Started;
279 run_thread_changed_.notify_all();
280 }
281
282
283=== modified file 'src/unity/api/scopes/internal/zmq_middleware/ObjectAdapter.cpp'
284--- src/unity/api/scopes/internal/zmq_middleware/ObjectAdapter.cpp 2013-10-16 15:04:14 +0000
285+++ src/unity/api/scopes/internal/zmq_middleware/ObjectAdapter.cpp 2013-10-25 04:17:24 +0000
286@@ -152,7 +152,6 @@
287 {
288 run_workers();
289 state_ = Active;
290- lock.unlock();
291 state_changed_.notify_all();
292 break;
293 }
294@@ -200,7 +199,6 @@
295 ServantMap().swap(servants_); // Not need for a try block. The ServantBase destructor is noexcept.
296 lock.lock();
297 state_ = Inactive;
298- lock.unlock();
299 state_changed_.notify_all();
300 break;
301 }
302
303=== modified file 'src/unity/api/scopes/internal/zmq_middleware/ZmqMiddleware.cpp'
304--- src/unity/api/scopes/internal/zmq_middleware/ZmqMiddleware.cpp 2013-10-16 15:04:14 +0000
305+++ src/unity/api/scopes/internal/zmq_middleware/ZmqMiddleware.cpp 2013-10-25 04:17:24 +0000
306@@ -109,7 +109,6 @@
307 // TODO: get pool size from config
308 invokers_.reset(new ThreadPool(1));
309 state_ = Started;
310- lock.unlock();
311 state_changed_.notify_all();
312 break;
313 }
314@@ -149,7 +148,6 @@
315 pair.second->wait_for_shutdown();
316 }
317 state_ = Stopped;
318- lock.unlock();
319 state_changed_.notify_all();
320 break;
321 }

Subscribers

People subscribed via source and target branches

to all changes: