Index: dbus/exported_object.cc |
diff --git a/dbus/exported_object.cc b/dbus/exported_object.cc |
index d20702407c4a3e282834a0149c2fedd73a381f01..e4a1641fa6e5ee67692bd383da896237e07a139c 100644 |
--- a/dbus/exported_object.cc |
+++ b/dbus/exported_object.cc |
@@ -39,10 +39,7 @@ ExportedObject::ExportedObject(Bus* bus, |
: bus_(bus), |
service_name_(service_name), |
object_path_(object_path), |
- object_is_registered_(false), |
- response_from_method_(NULL), |
- on_method_is_called_(false /* manual_reset */, |
- false /* initially_signaled */) { |
+ object_is_registered_(false) { |
} |
ExportedObject::~ExportedObject() { |
@@ -218,67 +215,76 @@ DBusHandlerResult ExportedObject::HandleMessage( |
} |
const base::TimeTicks start_time = base::TimeTicks::Now(); |
- Response* response = NULL; |
if (bus_->HasDBusThread()) { |
- response_from_method_ = NULL; |
// Post a task to run the method in the origin thread. |
bus_->PostTaskToOriginThread(FROM_HERE, |
base::Bind(&ExportedObject::RunMethod, |
this, |
iter->second, |
- method_call.get())); |
- // Wait until the method call is done. Blocking is not desirable but we |
- // should return the response to the dbus-daemon in the function, so we |
- // don't have a choice. We wait in the D-Bus thread, so it should be ok. |
- { |
- // We need a timeout here in case the method gets stuck. |
- const int kTimeoutSecs = 10; |
- const base::TimeDelta timeout( |
- base::TimeDelta::FromSeconds(kTimeoutSecs)); |
- |
- const bool signaled = on_method_is_called_.TimedWait(timeout); |
- // Method not called is a fatal error. The method is likely stuck |
- // infinitely in the origin thread. No way to stop it from here. |
- CHECK(signaled) << "Method " << absolute_method_name << " not called"; |
- } |
- response = response_from_method_; |
+ method_call.release(), |
+ start_time)); |
} else { |
// If the D-Bus thread is not used, just call the method directly. We |
// don't need the complicated logic to wait for the method call to be |
// complete. |
- response = iter->second.Run(method_call.get()); |
+ // |response| will be deleted in OnMethodCompleted(). |
+ Response* response = iter->second.Run(method_call.get()); |
+ OnMethodCompleted(method_call.release(), response, start_time); |
} |
+ |
+ // It's valid to say HANDLED here, and send a method response at a later |
+ // time from OnMethodCompleted() asynchronously. |
+ return DBUS_HANDLER_RESULT_HANDLED; |
+} |
+ |
+void ExportedObject::RunMethod(MethodCallCallback method_call_callback, |
+ MethodCall* method_call, |
+ base::TimeTicks start_time) { |
+ bus_->AssertOnOriginThread(); |
+ |
+ Response* response = method_call_callback.Run(method_call); |
+ bus_->PostTaskToDBusThread(FROM_HERE, |
+ base::Bind(&ExportedObject::OnMethodCompleted, |
+ this, |
+ method_call, |
+ response, |
+ start_time)); |
+} |
+ |
+void ExportedObject::OnMethodCompleted(MethodCall* method_call, |
+ Response* response, |
+ base::TimeTicks start_time) { |
+ bus_->AssertOnDBusThread(); |
+ scoped_ptr<MethodCall> method_call_deleter(method_call); |
+ scoped_ptr<Response> response_deleter(response); |
+ |
// Record if the method call is successful, or not. 1 if successful. |
UMA_HISTOGRAM_ENUMERATION("DBus.ExportedMethodHandleSuccess", |
response ? 1 : 0, |
kSuccessRatioHistogramMaxValue); |
+ // Check if the bus is still connected. If the method takes long to |
+ // complete, the bus may be shut down meanwhile. |
+ if (!bus_->is_connected()) |
+ return; |
+ |
if (!response) { |
// Something bad happened in the method call. |
scoped_ptr<dbus::ErrorResponse> error_response( |
- ErrorResponse::FromMethodCall(method_call.get(), |
- DBUS_ERROR_FAILED, |
- "error occurred in " + member)); |
- dbus_connection_send(connection, error_response->raw_message(), NULL); |
- return DBUS_HANDLER_RESULT_HANDLED; |
+ ErrorResponse::FromMethodCall( |
+ method_call, |
+ DBUS_ERROR_FAILED, |
+ "error occurred in " + method_call->GetMember())); |
+ bus_->Send(error_response->raw_message(), NULL); |
+ return; |
} |
// The method call was successful. |
- dbus_connection_send(connection, response->raw_message(), NULL); |
- delete response; |
+ bus_->Send(response->raw_message(), NULL); |
+ |
// Record time spent to handle the the method call. Don't include failures. |
UMA_HISTOGRAM_TIMES("DBus.ExportedMethodHandleTime", |
base::TimeTicks::Now() - start_time); |
- |
- return DBUS_HANDLER_RESULT_HANDLED; |
-} |
- |
-void ExportedObject::RunMethod(MethodCallCallback method_call_callback, |
- MethodCall* method_call) { |
- bus_->AssertOnOriginThread(); |
- |
- response_from_method_ = method_call_callback.Run(method_call); |
- on_method_is_called_.Signal(); |
} |
void ExportedObject::OnUnregistered(DBusConnection* connection) { |