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/posix/eintr_wrapper.h"
18 #include "tools/android/forwarder2/forwarder.h"
19 #include "tools/android/forwarder2/socket.h"
21 namespace forwarder2
{
23 ForwardersManager::ForwardersManager() : thread_("ForwardersManagerThread") {
25 WaitForEventsOnInternalThreadSoon();
29 ForwardersManager::~ForwardersManager() {
30 deletion_notifier_
.Notify();
33 void ForwardersManager::CreateAndStartNewForwarder(scoped_ptr
<Socket
> socket1
,
34 scoped_ptr
<Socket
> socket2
) {
35 // Note that the internal Forwarder vector is populated on the internal thread
36 // which is the only thread from which it's accessed.
37 thread_
.task_runner()->PostTask(
39 base::Bind(&ForwardersManager::CreateNewForwarderOnInternalThread
,
40 base::Unretained(this), base::Passed(&socket1
),
41 base::Passed(&socket2
)));
43 // Guarantees that the CreateNewForwarderOnInternalThread callback posted to
44 // the internal thread gets executed immediately.
45 wakeup_notifier_
.Notify();
48 void ForwardersManager::CreateNewForwarderOnInternalThread(
49 scoped_ptr
<Socket
> socket1
,
50 scoped_ptr
<Socket
> socket2
) {
51 DCHECK(thread_
.task_runner()->RunsTasksOnCurrentThread());
52 forwarders_
.push_back(new Forwarder(socket1
.Pass(), socket2
.Pass()));
55 void ForwardersManager::WaitForEventsOnInternalThreadSoon() {
56 thread_
.task_runner()->PostTask(
58 base::Bind(&ForwardersManager::WaitForEventsOnInternalThread
,
59 base::Unretained(this)));
62 void ForwardersManager::WaitForEventsOnInternalThread() {
63 DCHECK(thread_
.task_runner()->RunsTasksOnCurrentThread());
70 // Populate the file descriptor sets.
72 for (ScopedVector
<Forwarder
>::iterator it
= forwarders_
.begin();
73 it
!= forwarders_
.end(); ++it
) {
74 Forwarder
* const forwarder
= *it
;
75 forwarder
->RegisterFDs(&read_fds
, &write_fds
, &max_fd
);
78 const int notifier_fds
[] = {
79 wakeup_notifier_
.receiver_fd(),
80 deletion_notifier_
.receiver_fd(),
83 for (size_t i
= 0; i
< arraysize(notifier_fds
); ++i
) {
84 const int notifier_fd
= notifier_fds
[i
];
85 DCHECK_GT(notifier_fd
, -1);
86 FD_SET(notifier_fd
, &read_fds
);
87 max_fd
= std::max(max_fd
, notifier_fd
);
90 const int ret
= HANDLE_EINTR(
91 select(max_fd
+ 1, &read_fds
, &write_fds
, NULL
, NULL
));
93 PLOG(ERROR
) << "select";
97 const bool must_shutdown
= FD_ISSET(
98 deletion_notifier_
.receiver_fd(), &read_fds
);
99 if (must_shutdown
&& forwarders_
.empty())
102 base::ScopedClosureRunner
wait_for_events_soon(
103 base::Bind(&ForwardersManager::WaitForEventsOnInternalThreadSoon
,
104 base::Unretained(this)));
106 if (FD_ISSET(wakeup_notifier_
.receiver_fd(), &read_fds
)) {
107 // Note that the events on FDs other than the wakeup notifier one, if any,
108 // will be processed upon the next select().
109 wakeup_notifier_
.Reset();
113 // Notify the Forwarder instances and remove the ones that are closed.
114 for (size_t i
= 0; i
< forwarders_
.size(); ) {
115 Forwarder
* const forwarder
= forwarders_
[i
];
116 forwarder
->ProcessEvents(read_fds
, write_fds
);
119 forwarder
->Shutdown();
121 if (!forwarder
->IsClosed()) {
126 std::swap(forwarders_
[i
], forwarders_
.back());
127 forwarders_
.pop_back();
131 } // namespace forwarder2