Mir

Merge lp:~alan-griffiths/mir/fix-1201436 into lp:mir

Proposed by Alan Griffiths
Status: Merged
Approved by: kevin gunn
Approved revision: no longer in the source branch.
Merged at revision: 1099
Proposed branch: lp:~alan-griffiths/mir/fix-1201436
Merge into: lp:mir
Prerequisite: lp:~alan-griffiths/mir/client-dies-without-server
Diff against target: 162 lines (+39/-9)
6 files modified
src/client/mir_client_library.cpp (+4/-3)
src/client/mir_connection.cpp (+10/-2)
src/client/mir_wait_handle.cpp (+13/-0)
src/client/mir_wait_handle.h (+2/-0)
src/client/rpc/mir_socket_rpc_channel.cpp (+9/-4)
src/client/rpc/mir_socket_rpc_channel.h (+1/-0)
To merge this branch: bzr merge lp:~alan-griffiths/mir/fix-1201436
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Daniel van Vugt Needs Fixing
Kevin DuBois (community) Approve
Review via email: mp+188535@code.launchpad.net

Commit message

client: Fix race in connection failures

Description of the change

client: Fix race in connection failures

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

nit:
+ // We don't die while if are pending callbacks (as they touch this).

lgtm otherwise

review: Approve
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

You need to retest your conditions after a wait returns. So:
    if (received < expecting)
        wait_condition.wait_for(lock, limit);
should be:
    while (received < expecting)
        wait_condition.wait_for(lock, limit);

This is for two reasons:
  1. Some other thread could be waiting too, and racing against you. So you need to recheck the condition via a while loop after the wait returns (and when you have regained the lock) to verify the condition is really met, and you didn't lose a race.
  2. Historically OS wait functions could return prematurely (eg signals interrupting) so needed sanity checking. But I don't think this would still be true in the C++11 implementation... ?

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/client/mir_client_library.cpp'
--- src/client/mir_client_library.cpp 2013-09-11 21:20:15 +0000
+++ src/client/mir_client_library.cpp 2013-10-02 08:59:32 +0000
@@ -97,9 +97,10 @@
9797
98 mcl::DefaultConnectionConfiguration conf{sock};98 mcl::DefaultConnectionConfiguration conf{sock};
9999
100 MirConnection* connection = new MirConnection(conf);100 std::unique_ptr<MirConnection> connection{new MirConnection(conf)};
101101 auto const result = connection->connect(name, callback, context);
102 return connection->connect(name, callback, context);102 connection.release();
103 return result;
103 }104 }
104 catch (std::exception const& x)105 catch (std::exception const& x)
105 {106 {
106107
=== modified file 'src/client/mir_connection.cpp'
--- src/client/mir_connection.cpp 2013-09-27 13:40:30 +0000
+++ src/client/mir_connection.cpp 2013-10-02 08:59:32 +0000
@@ -63,7 +63,6 @@
6363
64}64}
6565
66
67MirConnection::MirConnection() :66MirConnection::MirConnection() :
68 channel(),67 channel(),
69 server(0),68 server(0),
@@ -91,6 +90,10 @@
9190
92MirConnection::~MirConnection() noexcept91MirConnection::~MirConnection() noexcept
93{92{
93 // We don't die while if are pending callbacks (as they touch this).
94 // But, if after 500ms we don't get a call, assume it won't happen.
95 connect_wait_handle.wait_for_pending(std::chrono::milliseconds(500));
96
94 std::lock_guard<std::mutex> lock(connection_guard);97 std::lock_guard<std::mutex> lock(connection_guard);
95 valid_connections.erase(this);98 valid_connections.erase(this);
9699
@@ -200,6 +203,7 @@
200203
201void MirConnection::connected(mir_connected_callback callback, void * context)204void MirConnection::connected(mir_connected_callback callback, void * context)
202{205{
206 bool safe_to_callback = true;
203 {207 {
204 std::lock_guard<std::recursive_mutex> lock(mutex);208 std::lock_guard<std::recursive_mutex> lock(mutex);
205209
@@ -207,6 +211,9 @@
207 {211 {
208 if (!connect_result.has_error())212 if (!connect_result.has_error())
209 {213 {
214 // We're handling an error scenario that means we're not sync'd
215 // with the client code - a callback isn't safe (or needed)
216 safe_to_callback = false;
210 set_error_message("Connect failed");217 set_error_message("Connect failed");
211 }218 }
212 }219 }
@@ -220,7 +227,7 @@
220 display_configuration->set_configuration(connect_result.display_configuration());227 display_configuration->set_configuration(connect_result.display_configuration());
221 }228 }
222229
223 callback(this, context);230 if (safe_to_callback) callback(this, context);
224 connect_wait_handle.result_received();231 connect_wait_handle.result_received();
225}232}
226233
@@ -232,6 +239,7 @@
232 std::lock_guard<std::recursive_mutex> lock(mutex);239 std::lock_guard<std::recursive_mutex> lock(mutex);
233240
234 connect_parameters.set_application_name(app_name);241 connect_parameters.set_application_name(app_name);
242 connect_wait_handle.expect_result();
235 server.connect(243 server.connect(
236 0,244 0,
237 &connect_parameters,245 &connect_parameters,
238246
=== modified file 'src/client/mir_wait_handle.cpp'
--- src/client/mir_wait_handle.cpp 2013-08-28 03:41:48 +0000
+++ src/client/mir_wait_handle.cpp 2013-10-02 08:59:32 +0000
@@ -57,6 +57,19 @@
57 expecting = 0;57 expecting = 0;
58}58}
5959
60void MirWaitHandle::wait_for_pending(std::chrono::milliseconds limit)
61{
62 using std::chrono::steady_clock;
63
64 std::unique_lock<std::mutex> lock(guard);
65
66 auto time_limit = steady_clock::now() + limit;
67
68 while (received < expecting && steady_clock::now() < time_limit)
69 wait_condition.wait_until(lock, time_limit);
70}
71
72
60void MirWaitHandle::wait_for_one() // wait for any single result73void MirWaitHandle::wait_for_one() // wait for any single result
61{74{
62 std::unique_lock<std::mutex> lock(guard);75 std::unique_lock<std::mutex> lock(guard);
6376
=== modified file 'src/client/mir_wait_handle.h'
--- src/client/mir_wait_handle.h 2013-08-28 03:41:48 +0000
+++ src/client/mir_wait_handle.h 2013-10-02 08:59:32 +0000
@@ -20,6 +20,7 @@
20#ifndef MIR_CLIENT_MIR_WAIT_HANDLE_H_20#ifndef MIR_CLIENT_MIR_WAIT_HANDLE_H_
21#define MIR_CLIENT_MIR_WAIT_HANDLE_H_21#define MIR_CLIENT_MIR_WAIT_HANDLE_H_
2222
23#include <chrono>
23#include <condition_variable>24#include <condition_variable>
24#include <mutex>25#include <mutex>
2526
@@ -37,6 +38,7 @@
37 void result_received();38 void result_received();
38 void wait_for_all();39 void wait_for_all();
39 void wait_for_one();40 void wait_for_one();
41 void wait_for_pending(std::chrono::milliseconds limit);
4042
41private:43private:
42 std::mutex guard;44 std::mutex guard;
4345
=== modified file 'src/client/rpc/mir_socket_rpc_channel.cpp'
--- src/client/rpc/mir_socket_rpc_channel.cpp 2013-09-30 09:20:06 +0000
+++ src/client/rpc/mir_socket_rpc_channel.cpp 2013-10-02 08:59:32 +0000
@@ -82,6 +82,14 @@
82 init();82 init();
83}83}
8484
85void mclr::MirSocketRpcChannel::notify_disconnected()
86{
87 // TODO enable configuring the kill mechanism
88 io_service.stop();
89 raise (SIGTERM);
90 pending_calls.force_completion();
91}
92
85void mclr::MirSocketRpcChannel::init()93void mclr::MirSocketRpcChannel::init()
86{94{
87 io_service_thread = std::thread([&]95 io_service_thread = std::thread([&]
@@ -110,10 +118,7 @@
110 {118 {
111 rpc_report->connection_failure(x);119 rpc_report->connection_failure(x);
112120
113 // TODO enable configuring the kill mechanism121 notify_disconnected();
114 io_service.stop();
115 raise(SIGTERM);
116 pending_calls.force_completion();
117 }122 }
118 });123 });
119}124}
120125
=== modified file 'src/client/rpc/mir_socket_rpc_channel.h'
--- src/client/rpc/mir_socket_rpc_channel.h 2013-09-20 18:42:07 +0000
+++ src/client/rpc/mir_socket_rpc_channel.h 2013-10-02 08:59:32 +0000
@@ -93,6 +93,7 @@
93 size_t read_message_header();93 size_t read_message_header();
9494
95 mir::protobuf::wire::Result read_message_body(const size_t body_size);95 mir::protobuf::wire::Result read_message_body(const size_t body_size);
96 void notify_disconnected();
9697
97 std::shared_ptr<SurfaceMap> surface_map;98 std::shared_ptr<SurfaceMap> surface_map;
98 std::shared_ptr<DisplayConfiguration> display_configuration;99 std::shared_ptr<DisplayConfiguration> display_configuration;

Subscribers

People subscribed via source and target branches