1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "tools/android/forwarder2/forwarders_manager.h"
7 #include <sys/select.h>
12 #include "base/basictypes.h"
13 #include "base/bind.h"
14 #include "base/callback_helpers.h"
15 #include "base/location.h"
16 #include "base/logging.h"
17 #include "base/message_loop/message_loop_proxy.h"
18 #include "base/posix/eintr_wrapper.h"
19 #include "tools/android/forwarder2/forwarder.h"
20 #include "tools/android/forwarder2/socket.h"
22 namespace forwarder2
{
24 ForwardersManager::ForwardersManager() : thread_("ForwardersManagerThread") {
26 WaitForEventsOnInternalThreadSoon();
30 ForwardersManager::~ForwardersManager() {
31 deletion_notifier_
.Notify();
34 void ForwardersManager::CreateAndStartNewForwarder(scoped_ptr
<Socket
> socket1
,
35 scoped_ptr
<Socket
> socket2
) {
36 // Note that the internal Forwarder vector is populated on the internal thread
37 // which is the only thread from which it's accessed.
38 thread_
.message_loop_proxy()->PostTask(
40 base::Bind(&ForwardersManager::CreateNewForwarderOnInternalThread
,
41 base::Unretained(this), base::Passed(&socket1
),
42 base::Passed(&socket2
)));
44 // Guarantees that the CreateNewForwarderOnInternalThread callback posted to
45 // the internal thread gets executed immediately.
46 wakeup_notifier_
.Notify();
49 void ForwardersManager::CreateNewForwarderOnInternalThread(
50 scoped_ptr
<Socket
> socket1
,
51 scoped_ptr
<Socket
> socket2
) {
52 DCHECK(thread_
.message_loop_proxy()->RunsTasksOnCurrentThread());
53 forwarders_
.push_back(new Forwarder(socket1
.Pass(), socket2
.Pass()));
56 void ForwardersManager::WaitForEventsOnInternalThreadSoon() {
57 thread_
.message_loop_proxy()->PostTask(
59 base::Bind(&ForwardersManager::WaitForEventsOnInternalThread
,
60 base::Unretained(this)));
63 void ForwardersManager::WaitForEventsOnInternalThread() {
64 DCHECK(thread_
.message_loop_proxy()->RunsTasksOnCurrentThread());
71 // Populate the file descriptor sets.
73 for (ScopedVector
<Forwarder
>::iterator it
= forwarders_
.begin();
74 it
!= forwarders_
.end(); ++it
) {
75 Forwarder
* const forwarder
= *it
;
76 forwarder
->RegisterFDs(&read_fds
, &write_fds
, &max_fd
);
79 const int notifier_fds
[] = {
80 wakeup_notifier_
.receiver_fd(),
81 deletion_notifier_
.receiver_fd(),
84 for (int i
= 0; i
< arraysize(notifier_fds
); ++i
) {
85 const int notifier_fd
= notifier_fds
[i
];
86 DCHECK_GT(notifier_fd
, -1);
87 FD_SET(notifier_fd
, &read_fds
);
88 max_fd
= std::max(max_fd
, notifier_fd
);
91 const int ret
= HANDLE_EINTR(
92 select(max_fd
+ 1, &read_fds
, &write_fds
, NULL
, NULL
));
94 PLOG(ERROR
) << "select";
98 const bool must_shutdown
= FD_ISSET(
99 deletion_notifier_
.receiver_fd(), &read_fds
);
100 if (must_shutdown
&& forwarders_
.empty())
103 base::ScopedClosureRunner
wait_for_events_soon(
104 base::Bind(&ForwardersManager::WaitForEventsOnInternalThreadSoon
,
105 base::Unretained(this)));
107 if (FD_ISSET(wakeup_notifier_
.receiver_fd(), &read_fds
)) {
108 // Note that the events on FDs other than the wakeup notifier one, if any,
109 // will be processed upon the next select().
110 wakeup_notifier_
.Reset();
114 // Notify the Forwarder instances and remove the ones that are closed.
115 for (size_t i
= 0; i
< forwarders_
.size(); ) {
116 Forwarder
* const forwarder
= forwarders_
[i
];
117 forwarder
->ProcessEvents(read_fds
, write_fds
);
120 forwarder
->Shutdown();
122 if (!forwarder
->IsClosed()) {
127 std::swap(forwarders_
[i
], forwarders_
.back());
128 forwarders_
.pop_back();
132 } // namespace forwarder2