Index: tools/android/forwarder2/forwarders_manager.cc |
diff --git a/tools/android/forwarder2/forwarders_manager.cc b/tools/android/forwarder2/forwarders_manager.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1b3cd2c46ef1ecfc84449683afce233c585f702d |
--- /dev/null |
+++ b/tools/android/forwarder2/forwarders_manager.cc |
@@ -0,0 +1,91 @@ |
+// Copyright 2013 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. |
+ |
+#include "tools/android/forwarder2/forwarders_manager.h" |
+ |
+#include <algorithm> |
+ |
+#include "base/basictypes.h" |
+#include "base/bind.h" |
+#include "base/location.h" |
+#include "base/logging.h" |
+#include "base/message_loop/message_loop_proxy.h" |
+#include "tools/android/forwarder2/forwarder.h" |
+#include "tools/android/forwarder2/socket.h" |
+ |
+namespace forwarder2 { |
+ |
+ForwardersManager::ForwardersManager() : delegate_(new Delegate()) {} |
+ |
+ForwardersManager::~ForwardersManager() { |
+ delegate_->Clear(); |
+} |
+ |
+void ForwardersManager::CreateAndStartNewForwarder(scoped_ptr<Socket> socket1, |
+ scoped_ptr<Socket> socket2) { |
+ delegate_->CreateAndStartNewForwarder(socket1.Pass(), socket2.Pass()); |
+} |
+ |
+ForwardersManager::Delegate::Delegate() {} |
+ |
+ForwardersManager::Delegate::~Delegate() { |
+ // The forwarder instances should already have been deleted on their |
+ // construction thread. Deleting them here would be unsafe since we don't know |
+ // which thread this destructor is called on. |
+ DCHECK(forwarders_.empty()); |
+} |
+ |
+void ForwardersManager::Delegate::Clear() { |
+ if (!forwarders_constructor_runner_) { |
+ DCHECK(forwarders_.empty()); |
+ return; |
+ } |
+ if (forwarders_constructor_runner_->RunsTasksOnCurrentThread()) { |
+ ClearOnForwarderConstructorThread(); |
+ return; |
+ } |
+ forwarders_constructor_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind( |
+ &ForwardersManager::Delegate::ClearOnForwarderConstructorThread, |
+ this)); |
+} |
+ |
+void ForwardersManager::Delegate::CreateAndStartNewForwarder( |
+ scoped_ptr<Socket> socket1, |
+ scoped_ptr<Socket> socket2) { |
+ const scoped_refptr<base::SingleThreadTaskRunner> current_task_runner( |
+ base::MessageLoopProxy::current()); |
+ DCHECK(current_task_runner); |
+ if (forwarders_constructor_runner_) { |
+ DCHECK_EQ(current_task_runner, forwarders_constructor_runner_); |
+ } else { |
+ forwarders_constructor_runner_ = current_task_runner; |
+ } |
+ forwarders_.push_back( |
+ new Forwarder(socket1.Pass(), socket2.Pass(), |
+ &deletion_notifier_, |
+ base::Bind(&ForwardersManager::Delegate::OnForwarderError, |
+ this))); |
+ forwarders_.back()->Start(); |
+} |
+ |
+void ForwardersManager::Delegate::OnForwarderError( |
+ scoped_ptr<Forwarder> forwarder) { |
+ DCHECK(forwarders_constructor_runner_->RunsTasksOnCurrentThread()); |
+ const ScopedVector<Forwarder>::iterator it = std::find( |
+ forwarders_.begin(), forwarders_.end(), forwarder.get()); |
+ DCHECK(it != forwarders_.end()); |
+ std::swap(*it, forwarders_.back()); |
+ forwarders_.pop_back(); |
+ ignore_result(forwarder.release()); // Deleted by the pop_back() above. |
+} |
+ |
+void ForwardersManager::Delegate::ClearOnForwarderConstructorThread() { |
+ DCHECK(forwarders_constructor_runner_->RunsTasksOnCurrentThread()); |
+ deletion_notifier_.Notify(); |
+ forwarders_.clear(); |
+} |
+ |
+} // namespace forwarder2 |