1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 // Test of gpr thread support.
20
21 #include "src/core/util/thd.h"
22
23 #include <grpc/support/sync.h>
24 #include <grpc/support/time.h>
25
26 #include <atomic>
27
28 #include "gtest/gtest.h"
29 #include "test/core/test_util/test_config.h"
30
31 #define NUM_THREADS 100
32
33 struct test {
34 gpr_mu mu;
35 int n;
36 int is_done;
37 gpr_cv done_cv;
38 };
39
40 // A Thread body. Decrement t->n, and if is becomes zero, set t->done.
thd_body1(void * v)41 static void thd_body1(void* v) {
42 struct test* t = static_cast<struct test*>(v);
43 gpr_mu_lock(&t->mu);
44 t->n--;
45 if (t->n == 0) {
46 t->is_done = 1;
47 gpr_cv_signal(&t->done_cv);
48 }
49 gpr_mu_unlock(&t->mu);
50 }
51
52 // Test that we can create a number of threads, wait for them, and join them.
TEST(ThreadTest,CanCreateWaitAndJoin)53 TEST(ThreadTest, CanCreateWaitAndJoin) {
54 grpc_core::Thread thds[NUM_THREADS];
55 struct test t;
56 gpr_mu_init(&t.mu);
57 gpr_cv_init(&t.done_cv);
58 t.n = NUM_THREADS;
59 t.is_done = 0;
60 for (auto& th : thds) {
61 th = grpc_core::Thread("grpc_thread_body1_test", &thd_body1, &t);
62 th.Start();
63 }
64 gpr_mu_lock(&t.mu);
65 while (!t.is_done) {
66 gpr_cv_wait(&t.done_cv, &t.mu, gpr_inf_future(GPR_CLOCK_REALTIME));
67 }
68 gpr_mu_unlock(&t.mu);
69 for (auto& th : thds) {
70 th.Join();
71 }
72 ASSERT_EQ(t.n, 0);
73 gpr_mu_destroy(&t.mu);
74 gpr_cv_destroy(&t.done_cv);
75 }
76
thd_body2(void *)77 static void thd_body2(void* /*v*/) {}
78
79 // Test that we can create a number of threads and join them.
TEST(ThreadTest,CanCreateSomeAndJoinThem)80 TEST(ThreadTest, CanCreateSomeAndJoinThem) {
81 grpc_core::Thread thds[NUM_THREADS];
82 for (auto& th : thds) {
83 bool ok;
84 th = grpc_core::Thread("grpc_thread_body2_test", &thd_body2, nullptr, &ok);
85 ASSERT_TRUE(ok);
86 th.Start();
87 }
88 for (auto& th : thds) {
89 th.Join();
90 }
91 }
92
93 // Test that we can create a thread with an AnyInvocable.
TEST(ThreadTest,CanCreateWithAnyInvocable)94 TEST(ThreadTest, CanCreateWithAnyInvocable) {
95 grpc_core::Thread thds[NUM_THREADS];
96 std::atomic<int> count_run{0};
97 for (auto& th : thds) {
98 bool ok;
99 th = grpc_core::Thread(
100 "grpc_thread_body2_test",
101 [&count_run]() { count_run.fetch_add(1, std::memory_order_relaxed); },
102 &ok);
103 ASSERT_TRUE(ok);
104 th.Start();
105 }
106 for (auto& th : thds) {
107 th.Join();
108 }
109 EXPECT_EQ(count_run.load(std::memory_order_relaxed), NUM_THREADS);
110 }
111
main(int argc,char ** argv)112 int main(int argc, char** argv) {
113 grpc::testing::TestEnvironment env(&argc, argv);
114 ::testing::InitGoogleTest(&argc, argv);
115 return RUN_ALL_TESTS();
116 }
117