1 /*
2 * Copyright (C) 2023 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 <array>
20 #include <thread>
21
22 #include "berberis/runtime_primitives/signal_queue.h"
23
24 namespace berberis {
25
26 namespace {
27
TEST(SignalQueue,EnqueueDequeue)28 TEST(SignalQueue, EnqueueDequeue) {
29 SignalQueue q;
30 siginfo_t* p;
31
32 EXPECT_EQ(nullptr, q.DequeueSignalUnsafe());
33
34 p = q.AllocSignal();
35 p->si_signo = 11;
36 p->si_value.sival_int = 1;
37 q.EnqueueSignal(p);
38
39 p = q.DequeueSignalUnsafe();
40 ASSERT_TRUE(p);
41 EXPECT_EQ(11, p->si_signo);
42 EXPECT_EQ(1, p->si_value.sival_int);
43 q.FreeSignal(p);
44
45 EXPECT_EQ(nullptr, q.DequeueSignalUnsafe());
46 }
47
TEST(SignalQueue,FIFO)48 TEST(SignalQueue, FIFO) {
49 SignalQueue q;
50 siginfo_t* p;
51
52 p = q.AllocSignal();
53 p->si_signo = 11;
54 p->si_value.sival_int = 1;
55 q.EnqueueSignal(p);
56
57 p = q.AllocSignal();
58 p->si_signo = 11;
59 p->si_value.sival_int = 2;
60 q.EnqueueSignal(p);
61
62 p = q.AllocSignal();
63 p->si_signo = 11;
64 p->si_value.sival_int = 3;
65 q.EnqueueSignal(p);
66
67 p = q.DequeueSignalUnsafe();
68 ASSERT_TRUE(p);
69 EXPECT_EQ(11, p->si_signo);
70 EXPECT_EQ(1, p->si_value.sival_int);
71 q.FreeSignal(p);
72
73 p = q.DequeueSignalUnsafe();
74 ASSERT_TRUE(p);
75 EXPECT_EQ(11, p->si_signo);
76 EXPECT_EQ(2, p->si_value.sival_int);
77 q.FreeSignal(p);
78
79 p = q.DequeueSignalUnsafe();
80 ASSERT_TRUE(p);
81 EXPECT_EQ(11, p->si_signo);
82 EXPECT_EQ(3, p->si_value.sival_int);
83 q.FreeSignal(p);
84 }
85
TEST(SignalQueue,Priority)86 TEST(SignalQueue, Priority) {
87 SignalQueue q;
88 siginfo_t* p;
89
90 p = q.AllocSignal();
91 p->si_signo = 11;
92 p->si_value.sival_int = 1;
93 q.EnqueueSignal(p);
94
95 p = q.AllocSignal();
96 p->si_signo = 6;
97 p->si_value.sival_int = 2;
98 q.EnqueueSignal(p);
99
100 p = q.AllocSignal();
101 p->si_signo = 11;
102 p->si_value.sival_int = 3;
103 q.EnqueueSignal(p);
104
105 p = q.DequeueSignalUnsafe();
106 ASSERT_TRUE(p);
107 EXPECT_EQ(6, p->si_signo);
108 EXPECT_EQ(2, p->si_value.sival_int);
109 q.FreeSignal(p);
110
111 p = q.DequeueSignalUnsafe();
112 ASSERT_TRUE(p);
113 EXPECT_EQ(11, p->si_signo);
114 EXPECT_EQ(1, p->si_value.sival_int);
115 q.FreeSignal(p);
116
117 p = q.AllocSignal();
118 p->si_signo = 6;
119 p->si_value.sival_int = 4;
120 q.EnqueueSignal(p);
121
122 p = q.DequeueSignalUnsafe();
123 ASSERT_TRUE(p);
124 EXPECT_EQ(6, p->si_signo);
125 EXPECT_EQ(4, p->si_value.sival_int);
126 q.FreeSignal(p);
127
128 p = q.DequeueSignalUnsafe();
129 ASSERT_TRUE(p);
130 EXPECT_EQ(11, p->si_signo);
131 EXPECT_EQ(3, p->si_value.sival_int);
132 q.FreeSignal(p);
133 }
134
135 const int kStressThreads = 40;
136 const int kStressIters = 40;
137 const int kStressPri = 10;
138
StressEnqueueFunc(SignalQueue * q)139 void* StressEnqueueFunc(SignalQueue* q) {
140 for (int i = 0; i < kStressIters; ++i) {
141 for (int j = 0; j < kStressPri; ++j) {
142 siginfo_t* p = q->AllocSignal();
143 // Don't pass signo = 0, let's reserve it for special uses.
144 p->si_signo = j + 1;
145 q->EnqueueSignal(p);
146 }
147 }
148
149 return nullptr;
150 }
151
TEST(SignalQueue,Stress)152 TEST(SignalQueue, Stress) {
153 SignalQueue q;
154 std::array<std::thread, kStressThreads> threads;
155
156 for (int i = 0; i < kStressThreads; ++i) {
157 threads[i] = std::thread(StressEnqueueFunc, &q);
158 }
159
160 const int kEnqueueCount = kStressThreads * kStressIters * kStressPri;
161 int dequeue_count = 0;
162
163 // Dequeue some signals.
164 // As they are added while consumed, we can't really check dequeue order.
165 while (dequeue_count < kEnqueueCount / 2) {
166 siginfo_t* p = q.DequeueSignalUnsafe();
167 // We can consume faster than signals are added, though very unlikely :)
168 if (p) {
169 q.FreeSignal(p);
170 ++dequeue_count;
171 }
172 }
173
174 for (int i = 0; i < kStressThreads; ++i) {
175 threads[i].join();
176 }
177
178 // Dequeue remaining signals.
179 // As we don't add signals any more, check dequeue order.
180 int pri = 0;
181 for (; dequeue_count < kEnqueueCount; ++dequeue_count) {
182 siginfo_t* p = q.DequeueSignalUnsafe();
183 ASSERT_TRUE(p);
184 EXPECT_LE(pri, p->si_signo);
185 pri = p->si_signo;
186 q.FreeSignal(p);
187 }
188 }
189
190 } // namespace
191
192 } // namespace berberis
193