Introduce TraceWriter and SharedMemoryArbiter for Producer(s)

These classes allow a Producer to get writer instances to allow
writing from several threads sharing the same per-Producer
SharedMemoryBuffer.

Test: perfetto_tests --gtest_filter=*SharedMemoryArbiter*
Test: perfetto_tests --gtest_filter=*TraceWriterImpl*
Bug: 70284518
Bug: 68854243
Change-Id: I56c4c699d9722bd34a8c5b32f514c6faa9cb95c5
diff --git a/src/tracing/core/trace_writer_impl_unittest.cc b/src/tracing/core/trace_writer_impl_unittest.cc
new file mode 100644
index 0000000..15b46a8
--- /dev/null
+++ b/src/tracing/core/trace_writer_impl_unittest.cc
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 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/tracing/core/trace_writer_impl.h"
+
+#include "gtest/gtest.h"
+#include "perfetto/base/utils.h"
+#include "perfetto/tracing/core/trace_writer.h"
+#include "src/base/test/test_task_runner.h"
+#include "src/tracing/core/shared_memory_arbiter.h"
+#include "src/tracing/test/aligned_buffer_test.h"
+
+#include "protos/trace_packet.pbzero.h"
+
+namespace perfetto {
+namespace {
+
+class TraceWriterImplTest : public AlignedBufferTest {
+ public:
+  void SetUp() override {
+    SharedMemoryArbiter::set_default_layout_for_testing(
+        SharedMemoryABI::PageLayout::kPageDiv4);
+    AlignedBufferTest::SetUp();
+    auto callback = [](const std::vector<uint32_t>& arg) {};
+    task_runner_.reset(new base::TestTaskRunner());
+    arbiter_.reset(new SharedMemoryArbiter(buf(), buf_size(), page_size(),
+                                           callback, task_runner_.get()));
+  }
+
+  void TearDown() override {
+    arbiter_.reset();
+    task_runner_.reset();
+  }
+
+  std::unique_ptr<base::TestTaskRunner> task_runner_;
+  std::unique_ptr<SharedMemoryArbiter> arbiter_;
+  std::function<void(const std::vector<uint32_t>&)> on_page_complete_;
+};
+
+size_t const kPageSizes[] = {4096, 65536};
+INSTANTIATE_TEST_CASE_P(PageSize,
+                        TraceWriterImplTest,
+                        ::testing::ValuesIn(kPageSizes));
+
+TEST_P(TraceWriterImplTest, SingleWriter) {
+  const BufferID tgt_buf_id = 42;
+  std::unique_ptr<TraceWriter> writer = arbiter_->CreateTraceWriter(tgt_buf_id);
+  for (int i = 0; i < 32; i++) {
+    auto packet = writer->NewTracePacket();
+    char str[16];
+    sprintf(str, "foobar %d", i);
+    packet->set_test(str);
+  }
+  writer->NewTracePacket()->set_test("workaround for returing the last chunk");
+  writer.reset();
+
+  SharedMemoryABI* abi = arbiter_->shmem_abi_for_testing();
+  size_t packets_count = 0;
+  for (size_t page_idx = 0; page_idx < kNumPages; page_idx++) {
+    uint32_t page_layout = abi->page_layout_dbg(page_idx);
+    size_t num_chunks = SharedMemoryABI::GetNumChunksForLayout(page_layout);
+    for (size_t chunk_idx = 0; chunk_idx < num_chunks; chunk_idx++) {
+      auto chunk =
+          abi->TryAcquireChunkForReading(page_idx, chunk_idx, tgt_buf_id);
+      if (!chunk.is_valid())
+        continue;
+      packets_count += chunk.header()->packets_state.load().count;
+    }
+  }
+  EXPECT_EQ(32u, packets_count);
+  // TODO(primiano): check also the content of the packets decoding the protos.
+}
+
+// TODO(primiano): add multi-writer test.
+
+}  // namespace
+}  // namespace perfetto