summaryrefslogtreecommitdiffstats
path: root/dbus
diff options
context:
space:
mode:
Diffstat (limited to 'dbus')
-rw-r--r--dbus/bus.cc33
-rw-r--r--dbus/bus.h34
-rw-r--r--dbus/bus_unittest.cc32
-rw-r--r--dbus/end_to_end_async_unittest.cc14
-rw-r--r--dbus/end_to_end_sync_unittest.cc3
-rw-r--r--dbus/mock_bus.h2
-rw-r--r--dbus/test_service.cc28
-rw-r--r--dbus/test_service.h16
8 files changed, 92 insertions, 70 deletions
diff --git a/dbus/bus.cc b/dbus/bus.cc
index 1b766acd..3651332 100644
--- a/dbus/bus.cc
+++ b/dbus/bus.cc
@@ -14,6 +14,7 @@
#include "base/stl_util.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
+#include "base/time.h"
#include "dbus/exported_object.h"
#include "dbus/object_proxy.h"
#include "dbus/scoped_dbus_error.h"
@@ -178,11 +179,13 @@ Bus::Bus(const Options& options)
: bus_type_(options.bus_type),
connection_type_(options.connection_type),
dbus_thread_(options.dbus_thread),
+ on_shutdown_(false /* manual_reset */, false /* initially_signaled */),
connection_(NULL),
origin_loop_(MessageLoop::current()),
origin_thread_id_(base::PlatformThread::CurrentId()),
dbus_thread_id_(base::kInvalidThreadId),
async_operations_set_up_(false),
+ shutdown_completed_(false),
num_pending_watches_(0),
num_pending_timeouts_(0) {
if (dbus_thread_) {
@@ -299,21 +302,31 @@ void Bus::ShutdownAndBlock() {
}
// Private connection should be closed.
- if (connection_ && connection_type_ == PRIVATE) {
- dbus_connection_close(connection_);
+ if (connection_) {
+ if (connection_type_ == PRIVATE)
+ dbus_connection_close(connection_);
+ // dbus_connection_close() won't unref.
+ dbus_connection_unref(connection_);
}
- // dbus_connection_close() won't unref.
- dbus_connection_unref(connection_);
connection_ = NULL;
+ shutdown_completed_ = true;
}
-void Bus::Shutdown(OnShutdownCallback callback) {
+void Bus::ShutdownOnDBusThreadAndBlock() {
AssertOnOriginThread();
+ DCHECK(dbus_thread_);
- PostTaskToDBusThread(FROM_HERE, base::Bind(&Bus::ShutdownInternal,
- this,
- callback));
+ PostTaskToDBusThread(FROM_HERE, base::Bind(
+ &Bus::ShutdownOnDBusThreadAndBlockInternal,
+ this));
+
+ // Wait until the shutdown is complete on the D-Bus thread.
+ // The shutdown should not hang, but set timeout just in case.
+ const int kTimeoutSecs = 3;
+ const base::TimeDelta timeout(base::TimeDelta::FromSeconds(kTimeoutSecs));
+ const bool signaled = on_shutdown_.TimedWait(timeout);
+ LOG_IF(ERROR, !signaled) << "Failed to shutdown the bus";
}
bool Bus::RequestOwnership(const std::string& service_name) {
@@ -535,11 +548,11 @@ void Bus::UnregisterObjectPath(const std::string& object_path) {
registered_object_paths_.erase(object_path);
}
-void Bus::ShutdownInternal(OnShutdownCallback callback) {
+void Bus::ShutdownOnDBusThreadAndBlockInternal() {
AssertOnDBusThread();
ShutdownAndBlock();
- PostTaskToOriginThread(FROM_HERE, callback);
+ on_shutdown_.Signal();
}
void Bus::ProcessAllIncomingDataIfAny() {
diff --git a/dbus/bus.h b/dbus/bus.h
index 792eb83..5be6ddc 100644
--- a/dbus/bus.h
+++ b/dbus/bus.h
@@ -14,6 +14,7 @@
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
#include "base/tracked_objects.h"
@@ -61,9 +62,9 @@ class ObjectProxy;
//
// SHUTDOWN
//
-// The Bus object must be shut down manually by Shutdown() or
-// ShutdownAndBlock(). We require the manual shutdown as we should not
-// issue blocking calls in the destructor.
+// The Bus object must be shut down manually by ShutdownAndBlock() and
+// friends. We require the manual shutdown to make the operation explicit
+// rather than doing it silently in the destructor.
//
// EXAMPLE USAGE:
//
@@ -119,8 +120,8 @@ class ObjectProxy;
// WHY IS THIS A REF COUNTED OBJECT?
//
// Bus is a ref counted object, to ensure that |this| of the object is
-// alive when callbacks referencing |this| are called. However, after
-// Shutdown() is called, |connection_| can be NULL. Hence, callbacks should
+// alive when callbacks referencing |this| are called. However, after the
+// bus is shut down, |connection_| can be NULL. Hence, callbacks should
// not rely on that |connection_| is alive.
class Bus : public base::RefCountedThreadSafe<Bus> {
public:
@@ -163,9 +164,6 @@ class Bus : public base::RefCountedThreadSafe<Bus> {
base::Thread* dbus_thread; // NULL by default.
};
- // Called when shutdown is done. Used for Shutdown().
- typedef base::Callback<void ()> OnShutdownCallback;
-
// Creates a Bus object. The actual connection will be established when
// Connect() is called.
explicit Bus(const Options& options);
@@ -219,11 +217,17 @@ class Bus : public base::RefCountedThreadSafe<Bus> {
// BLOCKING CALL.
virtual void ShutdownAndBlock();
- // Shuts down the bus in the D-Bus thread. |callback| will be called in
- // the origin thread.
+ // Similar to ShutdownAndBlock(), but this function is used to
+ // synchronously shut down the bus that uses the D-Bus thread. This
+ // function is intended to be used at the very end of the browser
+ // shutdown, where it makes more sense to shut down the bus
+ // synchronously, than trying to make it asynchronous.
//
- // Must be called in the origin thread.
- virtual void Shutdown(OnShutdownCallback callback);
+ // BLOCKING CALL, but must be called in the origin thread.
+ virtual void ShutdownOnDBusThreadAndBlock();
+
+ // Returns true if the shutdown has been completed.
+ bool shutdown_completed() { return shutdown_completed_; }
//
// The public functions below are not intended to be used in client
@@ -381,8 +385,8 @@ class Bus : public base::RefCountedThreadSafe<Bus> {
private:
friend class base::RefCountedThreadSafe<Bus>;
- // Helper function used for Shutdown().
- void ShutdownInternal(OnShutdownCallback callback);
+ // Helper function used for ShutdownOnDBusThreadAndBlock().
+ void ShutdownOnDBusThreadAndBlockInternal();
// Processes the all incoming data to the connection, if any.
//
@@ -427,6 +431,7 @@ class Bus : public base::RefCountedThreadSafe<Bus> {
const BusType bus_type_;
const ConnectionType connection_type_;
base::Thread* dbus_thread_;
+ base::WaitableEvent on_shutdown_;
DBusConnection* connection_;
MessageLoop* origin_loop_;
@@ -455,6 +460,7 @@ class Bus : public base::RefCountedThreadSafe<Bus> {
ExportedObjectTable exported_object_table_;
bool async_operations_set_up_;
+ bool shutdown_completed_;
// Counters to make sure that OnAddWatch()/OnRemoveWatch() and
// OnAddTimeout()/OnRemoveTimeou() are balanced.
diff --git a/dbus/bus_unittest.cc b/dbus/bus_unittest.cc
index 5cd198d..7d477e2 100644
--- a/dbus/bus_unittest.cc
+++ b/dbus/bus_unittest.cc
@@ -4,7 +4,10 @@
#include "dbus/bus.h"
+#include "base/bind.h"
+#include "base/message_loop.h"
#include "base/memory/ref_counted.h"
+#include "base/threading/thread.h"
#include "dbus/exported_object.h"
#include "dbus/object_proxy.h"
@@ -57,3 +60,32 @@ TEST(BusTest, GetExportedObject) {
ASSERT_TRUE(object_proxy3);
EXPECT_NE(object_proxy1, object_proxy3);
}
+
+TEST(BusTest, ShutdownAndBlock) {
+ dbus::Bus::Options options;
+ scoped_refptr<dbus::Bus> bus = new dbus::Bus(options);
+ ASSERT_FALSE(bus->shutdown_completed());
+
+ // Shut down synchronously.
+ bus->ShutdownAndBlock();
+ EXPECT_TRUE(bus->shutdown_completed());
+}
+
+TEST(BusTest, ShutdownAndBlockWithDBusThread) {
+ // Start the D-Bus thread.
+ base::Thread::Options thread_options;
+ thread_options.message_loop_type = MessageLoop::TYPE_IO;
+ base::Thread dbus_thread("D-Bus thread");
+ dbus_thread.StartWithOptions(thread_options);
+
+ // Create the bus.
+ dbus::Bus::Options options;
+ options.dbus_thread = &dbus_thread;
+ scoped_refptr<dbus::Bus> bus = new dbus::Bus(options);
+ ASSERT_FALSE(bus->shutdown_completed());
+
+ // Shut down synchronously.
+ bus->ShutdownOnDBusThreadAndBlock();
+ EXPECT_TRUE(bus->shutdown_completed());
+ dbus_thread.Stop();
+}
diff --git a/dbus/end_to_end_async_unittest.cc b/dbus/end_to_end_async_unittest.cc
index 41b06b6..cea37a8 100644
--- a/dbus/end_to_end_async_unittest.cc
+++ b/dbus/end_to_end_async_unittest.cc
@@ -66,15 +66,10 @@ class EndToEndAsyncTest : public testing::Test {
}
virtual void TearDown() {
- bus_->Shutdown(base::Bind(&EndToEndAsyncTest::OnShutdown,
- base::Unretained(this)));
- // Wait until the bus is shutdown. OnShutdown() will be called in
- // message_loop_.
- message_loop_.Run();
+ bus_->ShutdownOnDBusThreadAndBlock();
// Shut down the service.
- test_service_->Shutdown();
- ASSERT_TRUE(test_service_->WaitUntilServiceIsShutdown());
+ test_service_->ShutdownAndBlock();
// Reset to the default.
base::ThreadRestrictions::SetIOAllowed(true);
@@ -117,11 +112,6 @@ class EndToEndAsyncTest : public testing::Test {
message_loop_.Quit();
};
- // Called when the shutdown is complete.
- void OnShutdown() {
- message_loop_.Quit();
- }
-
// Called when the "Test" signal is received, in the main thread.
// Copy the string payload to |test_signal_string_|.
void OnTestSignal(dbus::Signal* signal) {
diff --git a/dbus/end_to_end_sync_unittest.cc b/dbus/end_to_end_sync_unittest.cc
index 8968985..c338809 100644
--- a/dbus/end_to_end_sync_unittest.cc
+++ b/dbus/end_to_end_sync_unittest.cc
@@ -37,8 +37,7 @@ class EndToEndSyncTest : public testing::Test {
}
virtual void TearDown() {
- test_service_->Shutdown();
- ASSERT_TRUE(test_service_->WaitUntilServiceIsShutdown());
+ test_service_->ShutdownAndBlock();
test_service_->Stop();
client_bus_->ShutdownAndBlock();
}
diff --git a/dbus/mock_bus.h b/dbus/mock_bus.h
index f1c5b4e..7b949cb 100644
--- a/dbus/mock_bus.h
+++ b/dbus/mock_bus.h
@@ -25,7 +25,7 @@ class MockBus : public Bus {
const std::string& service_name,
const std::string& object_path));
MOCK_METHOD0(ShutdownAndBlock, void());
- MOCK_METHOD1(Shutdown, void(OnShutdownCallback callback));
+ MOCK_METHOD0(ShutdownOnDBusThreadAndBlock, void());
MOCK_METHOD0(Connect, bool());
MOCK_METHOD1(RequestOwnership, bool(const std::string& service_name));
MOCK_METHOD1(ReleaseOwnership, bool(const std::string& service_name));
diff --git a/dbus/test_service.cc b/dbus/test_service.cc
index acab607..1b8b9bf 100644
--- a/dbus/test_service.cc
+++ b/dbus/test_service.cc
@@ -26,7 +26,6 @@ TestService::Options::~Options() {
TestService::TestService(const Options& options)
: base::Thread("TestService"),
dbus_thread_(options.dbus_thread),
- on_shutdown_(false /* manual_reset */, false /* initially_signaled */),
on_all_methods_exported_(false, false),
num_exported_methods_(0) {
}
@@ -48,24 +47,24 @@ bool TestService::WaitUntilServiceIsStarted() {
return on_all_methods_exported_.TimedWait(timeout);
}
-void TestService::Shutdown() {
+void TestService::ShutdownAndBlock() {
message_loop()->PostTask(
FROM_HERE,
- base::Bind(&TestService::ShutdownInternal,
+ base::Bind(&TestService::ShutdownAndBlockInternal,
base::Unretained(this)));
}
-bool TestService::WaitUntilServiceIsShutdown() {
- const base::TimeDelta timeout(
- base::TimeDelta::FromMilliseconds(
- TestTimeouts::action_max_timeout_ms()));
- return on_shutdown_.TimedWait(timeout);
-}
-
bool TestService::HasDBusThread() {
return bus_->HasDBusThread();
}
+void TestService::ShutdownAndBlockInternal() {
+ if (HasDBusThread())
+ bus_->ShutdownOnDBusThreadAndBlock();
+ else
+ bus_->ShutdownAndBlock();
+}
+
void TestService::SendTestSignal(const std::string& message) {
message_loop()->PostTask(
FROM_HERE,
@@ -81,11 +80,6 @@ void TestService::SendTestSignalInternal(const std::string& message) {
exported_object_->SendSignal(&signal);
}
-void TestService::ShutdownInternal() {
- bus_->Shutdown(base::Bind(&TestService::OnShutdown,
- base::Unretained(this)));
-}
-
void TestService::OnExported(const std::string& interface_name,
const std::string& method_name,
bool success) {
@@ -102,10 +96,6 @@ void TestService::OnExported(const std::string& interface_name,
on_all_methods_exported_.Signal();
}
-void TestService::OnShutdown() {
- on_shutdown_.Signal();
-}
-
void TestService::Run(MessageLoop* message_loop) {
Bus::Options bus_options;
bus_options.bus_type = Bus::SESSION;
diff --git a/dbus/test_service.h b/dbus/test_service.h
index 0ed8462..348aa73 100644
--- a/dbus/test_service.h
+++ b/dbus/test_service.h
@@ -49,12 +49,8 @@ class TestService : public base::Thread {
// Returns true on success.
bool WaitUntilServiceIsStarted() WARN_UNUSED_RESULT;
- // Shuts down the service.
- void Shutdown();
-
- // Waits until the service is shut down.
- // Returns true on success.
- bool WaitUntilServiceIsShutdown() WARN_UNUSED_RESULT;
+ // Shuts down the service and blocks until it's done.
+ void ShutdownAndBlock();
// Returns true if the bus has the D-Bus thread.
bool HasDBusThread();
@@ -66,17 +62,14 @@ class TestService : public base::Thread {
// Helper function for SendTestSignal().
void SendTestSignalInternal(const std::string& message);
- // Helper function for Shutdown().
- void ShutdownInternal();
+ // Helper function for ShutdownAndBlock().
+ void ShutdownAndBlockInternal();
// Called when a method is exported.
void OnExported(const std::string& interface_name,
const std::string& method_name,
bool success);
- // Called when the bus is shut down.
- void OnShutdown();
-
// base::Thread override.
virtual void Run(MessageLoop* message_loop);
@@ -95,7 +88,6 @@ class TestService : public base::Thread {
Response* BrokenMethod(MethodCall* method_call);
base::Thread* dbus_thread_;
- base::WaitableEvent on_shutdown_;
base::WaitableEvent on_all_methods_exported_;
// The number of methods actually exported.
int num_exported_methods_;