1 /*
2  * Copyright (C) 2015 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 <gtest/gtest.h>
18 
19 #include "Alloc.h"
20 #include "Pointers.h"
21 #include "Thread.h"
22 #include "Threads.h"
23 
TEST(ThreadsTest,single_thread)24 TEST(ThreadsTest, single_thread) {
25   Pointers pointers(2);
26 
27   Threads threads(&pointers, 1);
28   Thread* thread = threads.CreateThread(900);
29   ASSERT_TRUE(thread != nullptr);
30   ASSERT_EQ(1U, threads.num_threads());
31 
32   Thread* found_thread = threads.FindThread(900);
33   ASSERT_EQ(thread, found_thread);
34 
35   AllocEntry thread_done = {.type = THREAD_DONE};
36   thread->SetAllocEntry(&thread_done);
37 
38   thread->SetPending();
39 
40   threads.Finish(thread);
41 
42   ASSERT_EQ(0U, threads.num_threads());
43 }
44 
TEST(ThreadsTest,multiple_threads)45 TEST(ThreadsTest, multiple_threads) {
46   Pointers pointers(4);
47 
48   Threads threads(&pointers, 1);
49   Thread* thread1 = threads.CreateThread(900);
50   ASSERT_TRUE(thread1 != nullptr);
51   ASSERT_EQ(1U, threads.num_threads());
52 
53   Thread* thread2 = threads.CreateThread(901);
54   ASSERT_TRUE(thread2 != nullptr);
55   ASSERT_EQ(2U, threads.num_threads());
56 
57   Thread* thread3 = threads.CreateThread(902);
58   ASSERT_TRUE(thread3 != nullptr);
59   ASSERT_EQ(3U, threads.num_threads());
60 
61   Thread* found_thread1 = threads.FindThread(900);
62   ASSERT_EQ(thread1, found_thread1);
63 
64   Thread* found_thread2 = threads.FindThread(901);
65   ASSERT_EQ(thread2, found_thread2);
66 
67   Thread* found_thread3 = threads.FindThread(902);
68   ASSERT_EQ(thread3, found_thread3);
69 
70   AllocEntry thread_done = {.type = THREAD_DONE};
71   thread1->SetAllocEntry(&thread_done);
72   thread2->SetAllocEntry(&thread_done);
73   thread3->SetAllocEntry(&thread_done);
74 
75   thread1->SetPending();
76   threads.Finish(thread1);
77   ASSERT_EQ(2U, threads.num_threads());
78 
79   thread3->SetPending();
80   threads.Finish(thread3);
81   ASSERT_EQ(1U, threads.num_threads());
82 
83   thread2->SetPending();
84   threads.Finish(thread2);
85   ASSERT_EQ(0U, threads.num_threads());
86 }
87 
TEST(ThreadsTest,verify_quiesce)88 TEST(ThreadsTest, verify_quiesce) {
89   Pointers pointers(4);
90 
91   Threads threads(&pointers, 1);
92   Thread* thread = threads.CreateThread(900);
93   ASSERT_TRUE(thread != nullptr);
94   ASSERT_EQ(1U, threads.num_threads());
95 
96   // If WaitForAllToQuiesce is not correct, then this should provoke an error
97   // since we are overwriting the action data while it's being used.
98   constexpr size_t kAllocEntries = 512;
99   std::vector<AllocEntry> mallocs(kAllocEntries);
100   std::vector<AllocEntry> frees(kAllocEntries);
101   for (size_t i = 0; i < kAllocEntries; i++) {
102     mallocs[i].type = MALLOC;
103     mallocs[i].ptr = 0x1234 + i;
104     mallocs[i].size = 100;
105     thread->SetAllocEntry(&mallocs[i]);
106     thread->SetPending();
107     threads.WaitForAllToQuiesce();
108 
109     frees[i].type = FREE;
110     frees[i].ptr = 0x1234 + i;
111     thread->SetAllocEntry(&frees[i]);
112     thread->SetPending();
113     threads.WaitForAllToQuiesce();
114   }
115 
116   AllocEntry thread_done = {.type = THREAD_DONE};
117   thread->SetAllocEntry(&thread_done);
118   thread->SetPending();
119   threads.Finish(thread);
120   ASSERT_EQ(0U, threads.num_threads());
121 }
122 
TestTooManyThreads()123 static void TestTooManyThreads() {
124   Pointers pointers(4);
125 
126   Threads threads(&pointers, 1);
127   for (size_t i = 0; i <= threads.max_threads(); i++) {
128     Thread* thread = threads.CreateThread(900+i);
129     ASSERT_EQ(thread, threads.FindThread(900+i));
130   }
131 }
132 
TEST(ThreadsTest,too_many_threads)133 TEST(ThreadsTest, too_many_threads) {
134   ASSERT_EXIT(TestTooManyThreads(), ::testing::ExitedWithCode(1), "");
135 }
136