Index: dbus/bus.cc |
diff --git a/dbus/bus.cc b/dbus/bus.cc |
index 4096049417884f76044a275adbadb5e060f59636..7d235aa4b115bbe11c96844f64e60121d2c2d136 100644 |
--- a/dbus/bus.cc |
+++ b/dbus/bus.cc |
@@ -24,6 +24,11 @@ namespace dbus { |
namespace { |
+const char kDisconnectedSignal[] = "Disconnected"; |
+const char kDisconnectedMatchRule[] = |
+ "type='signal', path='/org/freedesktop/DBus/Local'," |
+ "interface='org.freedesktop.DBus.Local', member='Disconnected'"; |
+ |
// The class is used for watching the file descriptor used for D-Bus |
// communication. |
class Watch : public base::MessagePumpLibevent::Watcher { |
@@ -364,6 +369,10 @@ bool Bus::Connect() { |
// We shouldn't exit on the disconnected signal. |
dbus_connection_set_exit_on_disconnect(connection_, false); |
+ // Watch Disconnected signal. |
+ AddFilterFunction(Bus::OnConnectionDisconnectedFilter, this); |
+ AddMatch(kDisconnectedMatchRule, error.get()); |
+ |
return true; |
} |
@@ -704,9 +713,12 @@ void Bus::ProcessAllIncomingDataIfAny() { |
AssertOnDBusThread(); |
// As mentioned at the class comment in .h file, connection_ can be NULL. |
- if (!connection_ || !dbus_connection_get_is_connected(connection_)) |
+ if (!connection_) |
return; |
+ // It is safe and necessary to call dbus_connection_get_dispatch_status even |
+ // if the connection is lost. Otherwise we will miss "Disconnected" signal. |
+ // (crbug.com/174431) |
if (dbus_connection_get_dispatch_status(connection_) == |
DBUS_DISPATCH_DATA_REMAINS) { |
while (dbus_connection_dispatch(connection_) == |
@@ -842,9 +854,6 @@ void Bus::OnDispatchStatusChanged(DBusConnection* connection, |
DCHECK_EQ(connection, connection_); |
AssertOnDBusThread(); |
- if (!dbus_connection_get_is_connected(connection)) |
- return; |
- |
// We cannot call ProcessAllIncomingDataIfAny() here, as calling |
// dbus_connection_dispatch() inside DBusDispatchStatusFunction is |
// prohibited by the D-Bus library. Hence, we post a task here instead. |
@@ -854,6 +863,16 @@ void Bus::OnDispatchStatusChanged(DBusConnection* connection, |
this)); |
} |
+void Bus::OnConnectionDisconnected(DBusConnection* connection) { |
satorux1
2013/02/06 03:15:39
on what thread this function is called? Please ann
Seigo Nonaka
2013/02/06 04:57:22
Done.
|
+ if (!connection) |
+ return; |
+ |
+ DCHECK_EQ(connection, connection_); |
+ DCHECK(!dbus_connection_get_is_connected(connection)); |
+ |
+ ShutdownAndBlock(); |
+} |
+ |
dbus_bool_t Bus::OnAddWatchThunk(DBusWatch* raw_watch, void* data) { |
Bus* self = static_cast<Bus*>(data); |
return self->OnAddWatch(raw_watch); |
@@ -891,4 +910,18 @@ void Bus::OnDispatchStatusChangedThunk(DBusConnection* connection, |
self->OnDispatchStatusChanged(connection, status); |
} |
+DBusHandlerResult Bus::OnConnectionDisconnectedFilter( |
+ DBusConnection *connection, |
+ DBusMessage *message, |
+ void *data) { |
satorux1
2013/02/06 03:15:39
ditto. please annotate the thread.
Seigo Nonaka
2013/02/06 04:57:22
Done.
|
+ if (dbus_message_is_signal(message, |
+ DBUS_INTERFACE_LOCAL, |
+ kDisconnectedSignal)) { |
+ Bus* self = static_cast<Bus*>(data); |
+ self->OnConnectionDisconnected(connection); |
+ return DBUS_HANDLER_RESULT_HANDLED; |
+ } |
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
+} |
+ |
} // namespace dbus |