profiling: Add SocketPool.
Change-Id: I3bda8969ee71df2d47eb6e7f306a530bc388af27
diff --git a/Android.bp b/Android.bp
index 9ab67fd..0915ccf 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3693,6 +3693,10 @@
"src/perfetto_cmd/perfetto_cmd.cc",
"src/perfetto_cmd/rate_limiter.cc",
"src/perfetto_cmd/rate_limiter_unittest.cc",
+ "src/profiling/memory/bookkeeping.cc",
+ "src/profiling/memory/bookkeeping_unittest.cc",
+ "src/profiling/memory/client.cc",
+ "src/profiling/memory/client_unittest.cc",
"src/profiling/memory/record_reader.cc",
"src/profiling/memory/record_reader_unittest.cc",
"src/profiling/memory/socket_listener.cc",
diff --git a/src/profiling/memory/BUILD.gn b/src/profiling/memory/BUILD.gn
index e70f7a7..0ccc573 100644
--- a/src/profiling/memory/BUILD.gn
+++ b/src/profiling/memory/BUILD.gn
@@ -86,6 +86,22 @@
]
}
+source_set("client") {
+ public_configs = [
+ "../../../gn:default_config",
+ "../../../buildtools:libunwindstack_config",
+ ]
+ deps = [
+ "../../../buildtools:libunwindstack",
+ "../../../gn:default_deps",
+ "../../base",
+ ]
+ sources = [
+ "client.cc",
+ "client.h",
+ ]
+}
+
source_set("unittests") {
public_configs = [
"../../../gn:default_config",
@@ -94,6 +110,7 @@
testonly = true
deps = [
":bookkeeping",
+ ":client",
":record_reader",
":socket_listener",
":string_interner",
@@ -104,6 +121,7 @@
]
sources = [
"bookkeeping_unittest.cc",
+ "client_unittest.cc",
"record_reader_unittest.cc",
"socket_listener_unittest.cc",
"string_interner_unittest.cc",
diff --git a/src/profiling/memory/client.cc b/src/profiling/memory/client.cc
new file mode 100644
index 0000000..d0e8f61
--- /dev/null
+++ b/src/profiling/memory/client.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/profiling/memory/client.h"
+
+#include <inttypes.h>
+#include <sys/socket.h>
+
+#include <atomic>
+
+#include "perfetto/base/logging.h"
+#include "perfetto/base/utils.h"
+#include "src/profiling/memory/transport_data.h"
+
+namespace perfetto {
+
+BorrowedSocket::BorrowedSocket(base::ScopedFile fd, SocketPool* socket_pool)
+ : fd_(std::move(fd)), socket_pool_(socket_pool) {}
+
+int BorrowedSocket::operator*() {
+ return get();
+}
+
+int BorrowedSocket::get() {
+ return *fd_;
+}
+
+void BorrowedSocket::Close() {
+ fd_.reset();
+}
+
+BorrowedSocket::~BorrowedSocket() {
+ if (socket_pool_ != nullptr)
+ socket_pool_->Return(std::move(fd_));
+}
+
+SocketPool::SocketPool(std::vector<base::ScopedFile> sockets)
+ : sockets_(std::move(sockets)), available_sockets_(sockets_.size()) {}
+
+BorrowedSocket SocketPool::Borrow() {
+ std::unique_lock<std::mutex> lck_(mtx_);
+ if (available_sockets_ == 0)
+ cv_.wait(lck_, [this] { return available_sockets_ > 0; });
+ PERFETTO_CHECK(available_sockets_ > 0);
+ return {std::move(sockets_[--available_sockets_]), this};
+}
+
+void SocketPool::Return(base::ScopedFile sock) {
+ std::unique_lock<std::mutex> lck_(mtx_);
+ PERFETTO_CHECK(available_sockets_ < sockets_.size());
+ sockets_[available_sockets_++] = std::move(sock);
+ if (available_sockets_ == 1) {
+ lck_.unlock();
+ cv_.notify_one();
+ }
+}
+
+} // namespace perfetto
diff --git a/src/profiling/memory/client.h b/src/profiling/memory/client.h
new file mode 100644
index 0000000..a3aa5c6
--- /dev/null
+++ b/src/profiling/memory/client.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_PROFILING_MEMORY_CLIENT_H_
+#define SRC_PROFILING_MEMORY_CLIENT_H_
+
+#include <stddef.h>
+#include <mutex>
+#include <vector>
+
+#include "perfetto/base/scoped_file.h"
+
+namespace perfetto {
+
+class SocketPool;
+
+class BorrowedSocket {
+ public:
+ BorrowedSocket(const BorrowedSocket&) = delete;
+ BorrowedSocket& operator=(const BorrowedSocket&) = delete;
+ BorrowedSocket(BorrowedSocket&& other) {
+ fd_ = std::move(other.fd_);
+ socket_pool_ = other.socket_pool_;
+ other.socket_pool_ = nullptr;
+ }
+
+ BorrowedSocket(base::ScopedFile fd, SocketPool* socket_pool);
+ int operator*();
+ int get();
+ void Close();
+ ~BorrowedSocket();
+
+ private:
+ base::ScopedFile fd_;
+ SocketPool* socket_pool_ = nullptr;
+};
+
+class SocketPool {
+ public:
+ friend class BorrowedSocket;
+ SocketPool(std::vector<base::ScopedFile> sockets);
+
+ BorrowedSocket Borrow();
+
+ private:
+ void Return(base::ScopedFile fd);
+ std::mutex mtx_;
+ std::condition_variable cv_;
+ std::vector<base::ScopedFile> sockets_;
+ size_t available_sockets_;
+};
+
+} // namespace perfetto
+
+#endif // SRC_PROFILING_MEMORY_CLIENT_H_
diff --git a/src/profiling/memory/client_unittest.cc b/src/profiling/memory/client_unittest.cc
new file mode 100644
index 0000000..a69bae3
--- /dev/null
+++ b/src/profiling/memory/client_unittest.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/profiling/memory/client.h"
+
+#include "gtest/gtest.h"
+
+#include <thread>
+
+namespace perfetto {
+namespace {
+
+TEST(SocketPoolTest, Basic) {
+ std::vector<base::ScopedFile> files;
+ files.emplace_back(open("/dev/null", O_RDONLY));
+ SocketPool pool(std::move(files));
+ BorrowedSocket sock = pool.Borrow();
+}
+
+TEST(SocketPoolTest, Multiple) {
+ std::vector<base::ScopedFile> files;
+ files.emplace_back(open("/dev/null", O_RDONLY));
+ files.emplace_back(open("/dev/null", O_RDONLY));
+ SocketPool pool(std::move(files));
+ BorrowedSocket sock = pool.Borrow();
+ BorrowedSocket sock_2 = pool.Borrow();
+}
+
+TEST(SocketPoolTest, Blocked) {
+ std::vector<base::ScopedFile> files;
+ files.emplace_back(open("/dev/null", O_RDONLY));
+ SocketPool pool(std::move(files));
+ BorrowedSocket sock = pool.Borrow();
+ std::thread t([&pool] { pool.Borrow(); });
+ {
+ // Return fd to unblock thread.
+ BorrowedSocket temp = std::move(sock);
+ }
+ t.join();
+}
+
+TEST(SocketPoolTest, MultipleBlocked) {
+ std::vector<base::ScopedFile> files;
+ files.emplace_back(open("/dev/null", O_RDONLY));
+ SocketPool pool(std::move(files));
+ BorrowedSocket sock = pool.Borrow();
+ std::thread t([&pool] { pool.Borrow(); });
+ std::thread t2([&pool] { pool.Borrow(); });
+ {
+ // Return fd to unblock thread.
+ BorrowedSocket temp = std::move(sock);
+ }
+ t.join();
+ t2.join();
+}
+
+} // namespace
+} // namespace perfetto