• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "perfetto/tracing/platform.h"
18 
19 #include <atomic>
20 #include <cstdint>
21 #include <functional>
22 #include <memory>
23 #include <utility>
24 
25 #include "perfetto/base/logging.h"
26 #include "perfetto/base/task_runner.h"
27 #include "perfetto/ext/base/waitable_event.h"
28 #include "perfetto/protozero/message_handle.h"
29 #include "perfetto/tracing/internal/tracing_tls.h"
30 #include "perfetto/tracing/trace_writer_base.h"
31 #include "test/gtest_and_gmock.h"
32 
33 namespace perfetto {
34 namespace {
35 
GetTLS()36 internal::TracingTLS* GetTLS() {
37   return static_cast<internal::TracingTLS*>(
38       Platform::GetDefaultPlatform()->GetOrCreateThreadLocalObject());
39 }
40 
41 // We use this class only as a listener to detect thread-local destruction.
42 class FakeTraceWriter : public TraceWriterBase {
43  public:
44   std::atomic<bool>* destroyed_flag;
45 
~FakeTraceWriter()46   ~FakeTraceWriter() override { *destroyed_flag = true; }
NewTracePacket()47   protozero::MessageHandle<protos::pbzero::TracePacket> NewTracePacket()
48       override {
49     PERFETTO_CHECK(false);
50   }
FinishTracePacket()51   void FinishTracePacket() override { PERFETTO_CHECK(false); }
Flush(std::function<void ()>)52   void Flush(std::function<void()>) override {}
written() const53   uint64_t written() const override { return 0; }
drop_count() const54   uint64_t drop_count() const override { return 0; }
55 };
56 
57 // This test mainly checks that the thread at-exit logic works properly and
58 // destroys the TracingTLS when a thread exits.
TEST(PlatformUnittest,ThreadingAndTLSDtor)59 TEST(PlatformUnittest, ThreadingAndTLSDtor) {
60   auto* platform = Platform::GetDefaultPlatform();
61   if (!platform)
62     GTEST_SKIP() << "Platform::GetDefaultPlatform() not implemented";
63 
64   auto proc_name = platform->GetCurrentProcessName();
65   EXPECT_FALSE(proc_name.empty());
66 
67   // Create two threads.
68 
69   Platform::CreateTaskRunnerArgs tr_args{};
70   auto thread1 = platform->CreateTaskRunner(tr_args);
71   ASSERT_TRUE(thread1);
72 
73   auto thread2 = platform->CreateTaskRunner(tr_args);
74   ASSERT_TRUE(thread2);
75 
76   // Check that the TLS is actually thread-local.
77 
78   thread1->PostTask([] { GetTLS()->generation = 101; });
79   thread2->PostTask([] { GetTLS()->generation = 102; });
80   std::atomic<bool> thread1_destroyed{};
81   std::atomic<bool> thread2_destroyed{};
82 
83   // Now post another task on each thread. The task will:
84   // 1. Check that the generation matches what previously set.
85   // 2. Create a FakeTraceWriter and wire up a destruction event.
86   base::WaitableEvent evt1;
87   thread1->PostTask([&] {
88     EXPECT_EQ(GetTLS()->generation, 101u);
89     GetTLS()->data_sources_tls[0].per_instance[0].Reset();
90     std::unique_ptr<FakeTraceWriter> tw(new FakeTraceWriter());
91     tw->destroyed_flag = &thread1_destroyed;
92     GetTLS()->data_sources_tls[0].per_instance[0].trace_writer = std::move(tw);
93     evt1.Notify();
94   });
95   evt1.Wait();
96 
97   base::WaitableEvent evt2;
98   thread2->PostTask([&] {
99     EXPECT_EQ(GetTLS()->generation, 102u);
100     GetTLS()->data_sources_tls[0].per_instance[0].Reset();
101     std::unique_ptr<FakeTraceWriter> tw(new FakeTraceWriter());
102     tw->destroyed_flag = &thread2_destroyed;
103     GetTLS()->data_sources_tls[0].per_instance[0].trace_writer = std::move(tw);
104     evt2.Notify();
105   });
106   evt2.Wait();
107 
108   EXPECT_FALSE(thread1_destroyed);
109   EXPECT_FALSE(thread2_destroyed);
110 
111   thread1.reset();
112   EXPECT_TRUE(thread1_destroyed);
113   EXPECT_FALSE(thread2_destroyed);
114 
115   thread2.reset();
116   EXPECT_TRUE(thread2_destroyed);
117 }
118 
119 }  // namespace
120 }  // namespace perfetto
121