Chromium Code Reviews| Index: dbus/bus.cc |
| diff --git a/dbus/bus.cc b/dbus/bus.cc |
| index 4096049417884f76044a275adbadb5e060f59636..6bd404c96622bc67c0ddbd0254f33cfa86694fa2 100644 |
| --- a/dbus/bus.cc |
| +++ b/dbus/bus.cc |
| @@ -1,9 +1,6 @@ |
| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -// |
| -// TODO(satorux): |
| -// - Handle "disconnected" signal. |
| #include "dbus/bus.h" |
| @@ -24,6 +21,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,12 +366,19 @@ 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; |
| } |
| void Bus::ShutdownAndBlock() { |
| AssertOnDBusThread(); |
| + if (shutdown_completed_) |
| + return; // Already shutdowned, just return. |
|
satorux1
2013/02/08 13:39:06
Do we need this? Looks unnecessary.
|
| + |
| // Unregister the exported objects. |
| for (ExportedObjectTable::iterator iter = exported_object_table_.begin(); |
| iter != exported_object_table_.end(); ++iter) { |
| @@ -403,6 +412,11 @@ void Bus::ShutdownAndBlock() { |
| // Private connection should be closed. |
| if (connection_) { |
| + // Remove Disconnected watcher. |
| + ScopedDBusError error; |
| + RemoveFilterFunction(Bus::OnConnectionDisconnectedFilter, this); |
| + RemoveMatch(kDisconnectedMatchRule, error.get()); |
| + |
| if (connection_type_ == PRIVATE) |
| dbus_connection_close(connection_); |
| // dbus_connection_close() won't unref. |
| @@ -704,9 +718,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 +859,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 +868,21 @@ void Bus::OnDispatchStatusChanged(DBusConnection* connection, |
| this)); |
| } |
| +void Bus::OnConnectionDisconnected(DBusConnection* connection) { |
| + AssertOnDBusThread(); |
| + |
| + if (!connection) |
| + return; |
| + DCHECK(!dbus_connection_get_is_connected(connection)); |
| + |
| + if (shutdown_completed_) |
| + return; // Do nothing if the shutdown is already completed. |
| + |
| + // Unexpected disconnection, maybe the peer closes the connection. |
| + DCHECK_EQ(connection, 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 +920,19 @@ void Bus::OnDispatchStatusChangedThunk(DBusConnection* connection, |
| self->OnDispatchStatusChanged(connection, status); |
| } |
| +DBusHandlerResult Bus::OnConnectionDisconnectedFilter( |
| + DBusConnection *connection, |
| + DBusMessage *message, |
| + void *data) { |
| + if (dbus_message_is_signal(message, |
| + DBUS_INTERFACE_LOCAL, |
| + kDisconnectedSignal)) { |
| + Bus* self = static_cast<Bus*>(data); |
| + self->AssertOnDBusThread(); |
| + self->OnConnectionDisconnected(connection); |
| + return DBUS_HANDLER_RESULT_HANDLED; |
| + } |
| + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
| +} |
| + |
| } // namespace dbus |