diff options
-rw-r--r-- | bluetooth/1.0/default/async_fd_watcher.cc | 36 | ||||
-rw-r--r-- | bluetooth/1.0/default/async_fd_watcher.h | 6 | ||||
-rw-r--r-- | bluetooth/1.0/default/test/async_fd_watcher_unittest.cc | 66 | ||||
-rw-r--r-- | bluetooth/1.0/default/vendor_interface.cc | 2 |
4 files changed, 91 insertions, 19 deletions
diff --git a/bluetooth/1.0/default/async_fd_watcher.cc b/bluetooth/1.0/default/async_fd_watcher.cc index 287d007a..2f23a699 100644 --- a/bluetooth/1.0/default/async_fd_watcher.cc +++ b/bluetooth/1.0/default/async_fd_watcher.cc | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <algorithm> | 19 | #include <algorithm> |
20 | #include <atomic> | 20 | #include <atomic> |
21 | #include <condition_variable> | 21 | #include <condition_variable> |
22 | #include <map> | ||
22 | #include <mutex> | 23 | #include <mutex> |
23 | #include <thread> | 24 | #include <thread> |
24 | #include <vector> | 25 | #include <vector> |
@@ -26,6 +27,8 @@ | |||
26 | #include "sys/select.h" | 27 | #include "sys/select.h" |
27 | #include "unistd.h" | 28 | #include "unistd.h" |
28 | 29 | ||
30 | static const int INVALID_FD = -1; | ||
31 | |||
29 | namespace android { | 32 | namespace android { |
30 | namespace hardware { | 33 | namespace hardware { |
31 | namespace bluetooth { | 34 | namespace bluetooth { |
@@ -36,8 +39,7 @@ int AsyncFdWatcher::WatchFdForNonBlockingReads( | |||
36 | // Add file descriptor and callback | 39 | // Add file descriptor and callback |
37 | { | 40 | { |
38 | std::unique_lock<std::mutex> guard(internal_mutex_); | 41 | std::unique_lock<std::mutex> guard(internal_mutex_); |
39 | read_fd_ = file_descriptor; | 42 | watched_fds_[file_descriptor] = on_read_fd_ready_callback; |
40 | cb_ = on_read_fd_ready_callback; | ||
41 | } | 43 | } |
42 | 44 | ||
43 | // Start the thread if not started yet | 45 | // Start the thread if not started yet |
@@ -58,7 +60,7 @@ int AsyncFdWatcher::ConfigureTimeout( | |||
58 | return 0; | 60 | return 0; |
59 | } | 61 | } |
60 | 62 | ||
61 | void AsyncFdWatcher::StopWatchingFileDescriptor() { stopThread(); } | 63 | void AsyncFdWatcher::StopWatchingFileDescriptors() { stopThread(); } |
62 | 64 | ||
63 | AsyncFdWatcher::~AsyncFdWatcher() {} | 65 | AsyncFdWatcher::~AsyncFdWatcher() {} |
64 | 66 | ||
@@ -90,8 +92,7 @@ int AsyncFdWatcher::stopThread() { | |||
90 | 92 | ||
91 | { | 93 | { |
92 | std::unique_lock<std::mutex> guard(internal_mutex_); | 94 | std::unique_lock<std::mutex> guard(internal_mutex_); |
93 | cb_ = nullptr; | 95 | watched_fds_.clear(); |
94 | read_fd_ = -1; | ||
95 | } | 96 | } |
96 | 97 | ||
97 | { | 98 | { |
@@ -115,7 +116,11 @@ void AsyncFdWatcher::ThreadRoutine() { | |||
115 | fd_set read_fds; | 116 | fd_set read_fds; |
116 | FD_ZERO(&read_fds); | 117 | FD_ZERO(&read_fds); |
117 | FD_SET(notification_listen_fd_, &read_fds); | 118 | FD_SET(notification_listen_fd_, &read_fds); |
118 | FD_SET(read_fd_, &read_fds); | 119 | int max_read_fd = INVALID_FD; |
120 | for (auto& it : watched_fds_) { | ||
121 | FD_SET(it.first, &read_fds); | ||
122 | max_read_fd = std::max(max_read_fd, it.first); | ||
123 | } | ||
119 | 124 | ||
120 | struct timeval timeout; | 125 | struct timeval timeout; |
121 | struct timeval* timeout_ptr = NULL; | 126 | struct timeval* timeout_ptr = NULL; |
@@ -126,7 +131,7 @@ void AsyncFdWatcher::ThreadRoutine() { | |||
126 | } | 131 | } |
127 | 132 | ||
128 | // Wait until there is data available to read on some FD. | 133 | // Wait until there is data available to read on some FD. |
129 | int nfds = std::max(notification_listen_fd_, read_fd_); | 134 | int nfds = std::max(notification_listen_fd_, max_read_fd); |
130 | int retval = select(nfds + 1, &read_fds, NULL, NULL, timeout_ptr); | 135 | int retval = select(nfds + 1, &read_fds, NULL, NULL, timeout_ptr); |
131 | 136 | ||
132 | // There was some error. | 137 | // There was some error. |
@@ -153,10 +158,21 @@ void AsyncFdWatcher::ThreadRoutine() { | |||
153 | continue; | 158 | continue; |
154 | } | 159 | } |
155 | 160 | ||
156 | // Invoke the data ready callback if appropriate. | 161 | // Invoke the data ready callbacks if appropriate. |
157 | if (FD_ISSET(read_fd_, &read_fds)) { | 162 | std::vector<decltype(watched_fds_)::value_type> saved_callbacks; |
163 | { | ||
158 | std::unique_lock<std::mutex> guard(internal_mutex_); | 164 | std::unique_lock<std::mutex> guard(internal_mutex_); |
159 | if (cb_) cb_(read_fd_); | 165 | for (auto& it : watched_fds_) { |
166 | if (FD_ISSET(it.first, &read_fds)) { | ||
167 | saved_callbacks.push_back(it); | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | |||
172 | for (auto& it : saved_callbacks) { | ||
173 | if (it.second) { | ||
174 | it.second(it.first); | ||
175 | } | ||
160 | } | 176 | } |
161 | } | 177 | } |
162 | } | 178 | } |
diff --git a/bluetooth/1.0/default/async_fd_watcher.h b/bluetooth/1.0/default/async_fd_watcher.h index 3f7ff544..358cbc3d 100644 --- a/bluetooth/1.0/default/async_fd_watcher.h +++ b/bluetooth/1.0/default/async_fd_watcher.h | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | #pragma once | 17 | #pragma once |
18 | 18 | ||
19 | #include <map> | ||
19 | #include <mutex> | 20 | #include <mutex> |
20 | #include <thread> | 21 | #include <thread> |
21 | 22 | ||
@@ -36,7 +37,7 @@ class AsyncFdWatcher { | |||
36 | const ReadCallback& on_read_fd_ready_callback); | 37 | const ReadCallback& on_read_fd_ready_callback); |
37 | int ConfigureTimeout(const std::chrono::milliseconds timeout, | 38 | int ConfigureTimeout(const std::chrono::milliseconds timeout, |
38 | const TimeoutCallback& on_timeout_callback); | 39 | const TimeoutCallback& on_timeout_callback); |
39 | void StopWatchingFileDescriptor(); | 40 | void StopWatchingFileDescriptors(); |
40 | 41 | ||
41 | private: | 42 | private: |
42 | AsyncFdWatcher(const AsyncFdWatcher&) = delete; | 43 | AsyncFdWatcher(const AsyncFdWatcher&) = delete; |
@@ -52,10 +53,9 @@ class AsyncFdWatcher { | |||
52 | std::mutex internal_mutex_; | 53 | std::mutex internal_mutex_; |
53 | std::mutex timeout_mutex_; | 54 | std::mutex timeout_mutex_; |
54 | 55 | ||
55 | int read_fd_; | 56 | std::map<int, ReadCallback> watched_fds_; |
56 | int notification_listen_fd_; | 57 | int notification_listen_fd_; |
57 | int notification_write_fd_; | 58 | int notification_write_fd_; |
58 | ReadCallback cb_; | ||
59 | TimeoutCallback timeout_cb_; | 59 | TimeoutCallback timeout_cb_; |
60 | std::chrono::milliseconds timeout_ms_; | 60 | std::chrono::milliseconds timeout_ms_; |
61 | }; | 61 | }; |
diff --git a/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc b/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc index a7f5bdab..b0c533c9 100644 --- a/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc +++ b/bluetooth/1.0/default/test/async_fd_watcher_unittest.cc | |||
@@ -14,6 +14,8 @@ | |||
14 | // limitations under the License. | 14 | // limitations under the License. |
15 | // | 15 | // |
16 | 16 | ||
17 | #define LOG_TAG "async_fd_watcher_unittest" | ||
18 | |||
17 | #include "async_fd_watcher.h" | 19 | #include "async_fd_watcher.h" |
18 | #include <gtest/gtest.h> | 20 | #include <gtest/gtest.h> |
19 | #include <cstdint> | 21 | #include <cstdint> |
@@ -122,8 +124,8 @@ class AsyncFdWatcherSocketTest : public ::testing::Test { | |||
122 | } | 124 | } |
123 | 125 | ||
124 | void CleanUpServer() { | 126 | void CleanUpServer() { |
125 | async_fd_watcher_.StopWatchingFileDescriptor(); | 127 | async_fd_watcher_.StopWatchingFileDescriptors(); |
126 | conn_watcher_.StopWatchingFileDescriptor(); | 128 | conn_watcher_.StopWatchingFileDescriptors(); |
127 | close(socket_fd_); | 129 | close(socket_fd_); |
128 | } | 130 | } |
129 | 131 | ||
@@ -211,7 +213,7 @@ TEST_F(AsyncFdWatcherSocketTest, Connect) { | |||
211 | }); | 213 | }); |
212 | 214 | ||
213 | ConnectClient(); | 215 | ConnectClient(); |
214 | conn_watcher.StopWatchingFileDescriptor(); | 216 | conn_watcher.StopWatchingFileDescriptors(); |
215 | close(socket_fd); | 217 | close(socket_fd); |
216 | } | 218 | } |
217 | 219 | ||
@@ -233,7 +235,7 @@ TEST_F(AsyncFdWatcherSocketTest, TimedOutConnect) { | |||
233 | EXPECT_FALSE(timed_out); | 235 | EXPECT_FALSE(timed_out); |
234 | sleep(1); | 236 | sleep(1); |
235 | EXPECT_TRUE(timed_out); | 237 | EXPECT_TRUE(timed_out); |
236 | conn_watcher.StopWatchingFileDescriptor(); | 238 | conn_watcher.StopWatchingFileDescriptors(); |
237 | close(socket_fd); | 239 | close(socket_fd); |
238 | } | 240 | } |
239 | 241 | ||
@@ -265,10 +267,64 @@ TEST_F(AsyncFdWatcherSocketTest, TimedOutSchedulesTimeout) { | |||
265 | sleep(1); | 267 | sleep(1); |
266 | EXPECT_TRUE(timed_out); | 268 | EXPECT_TRUE(timed_out); |
267 | EXPECT_TRUE(timed_out2); | 269 | EXPECT_TRUE(timed_out2); |
268 | conn_watcher.StopWatchingFileDescriptor(); | 270 | conn_watcher.StopWatchingFileDescriptors(); |
269 | close(socket_fd); | 271 | close(socket_fd); |
270 | } | 272 | } |
271 | 273 | ||
274 | // Use a single AsyncFdWatcher to watch two file descriptors. | ||
275 | TEST_F(AsyncFdWatcherSocketTest, WatchTwoFileDescriptors) { | ||
276 | int sockfd[2]; | ||
277 | socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd); | ||
278 | bool cb1_called = false; | ||
279 | bool* cb1_called_ptr = &cb1_called; | ||
280 | bool cb2_called = false; | ||
281 | bool* cb2_called_ptr = &cb2_called; | ||
282 | |||
283 | AsyncFdWatcher watcher; | ||
284 | watcher.WatchFdForNonBlockingReads(sockfd[0], [cb1_called_ptr](int fd) { | ||
285 | char read_buf[1] = {0}; | ||
286 | int n = TEMP_FAILURE_RETRY(read(fd, read_buf, sizeof(read_buf))); | ||
287 | ASSERT_TRUE(n == sizeof(read_buf)); | ||
288 | ASSERT_TRUE(read_buf[0] == '1'); | ||
289 | *cb1_called_ptr = true; | ||
290 | }); | ||
291 | |||
292 | watcher.WatchFdForNonBlockingReads(sockfd[1], [cb2_called_ptr](int fd) { | ||
293 | char read_buf[1] = {0}; | ||
294 | int n = TEMP_FAILURE_RETRY(read(fd, read_buf, sizeof(read_buf))); | ||
295 | ASSERT_TRUE(n == sizeof(read_buf)); | ||
296 | ASSERT_TRUE(read_buf[0] == '2'); | ||
297 | *cb2_called_ptr = true; | ||
298 | }); | ||
299 | |||
300 | // Fail if the test doesn't pass within 3 seconds | ||
301 | watcher.ConfigureTimeout(std::chrono::seconds(3), [this]() { | ||
302 | bool connection_timeout = true; | ||
303 | ASSERT_FALSE(connection_timeout); | ||
304 | }); | ||
305 | |||
306 | EXPECT_FALSE(cb1_called); | ||
307 | EXPECT_FALSE(cb2_called); | ||
308 | |||
309 | char one_buf[1] = {'1'}; | ||
310 | TEMP_FAILURE_RETRY(write(sockfd[1], one_buf, sizeof(one_buf))); | ||
311 | |||
312 | sleep(1); | ||
313 | |||
314 | EXPECT_TRUE(cb1_called); | ||
315 | EXPECT_FALSE(cb2_called); | ||
316 | |||
317 | char two_buf[1] = {'2'}; | ||
318 | TEMP_FAILURE_RETRY(write(sockfd[0], two_buf, sizeof(two_buf))); | ||
319 | |||
320 | sleep(1); | ||
321 | |||
322 | EXPECT_TRUE(cb1_called); | ||
323 | EXPECT_TRUE(cb2_called); | ||
324 | |||
325 | watcher.StopWatchingFileDescriptors(); | ||
326 | } | ||
327 | |||
272 | // Use two AsyncFdWatchers to set up a server socket. | 328 | // Use two AsyncFdWatchers to set up a server socket. |
273 | TEST_F(AsyncFdWatcherSocketTest, ClientServer) { | 329 | TEST_F(AsyncFdWatcherSocketTest, ClientServer) { |
274 | ConfigureServer(); | 330 | ConfigureServer(); |
diff --git a/bluetooth/1.0/default/vendor_interface.cc b/bluetooth/1.0/default/vendor_interface.cc index 38781294..2c55d1ce 100644 --- a/bluetooth/1.0/default/vendor_interface.cc +++ b/bluetooth/1.0/default/vendor_interface.cc | |||
@@ -274,7 +274,7 @@ bool VendorInterface::Open(InitializeCompleteCallback initialize_complete_cb, | |||
274 | } | 274 | } |
275 | 275 | ||
276 | void VendorInterface::Close() { | 276 | void VendorInterface::Close() { |
277 | fd_watcher_.StopWatchingFileDescriptor(); | 277 | fd_watcher_.StopWatchingFileDescriptors(); |
278 | 278 | ||
279 | if (lib_interface_ != nullptr) { | 279 | if (lib_interface_ != nullptr) { |
280 | bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE; | 280 | bt_vendor_lpm_mode_t mode = BT_VND_LPM_DISABLE; |