xref: /aosp_15_r20/external/oboe/samples/RhythmGame/test/testLockFreeQueue.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1*05767d91SRobert Wu /*
2*05767d91SRobert Wu  * Copyright 2018 The Android Open Source Project
3*05767d91SRobert Wu  *
4*05767d91SRobert Wu  * Licensed under the Apache License, Version 2.0 (the "License");
5*05767d91SRobert Wu  * you may not use this file except in compliance with the License.
6*05767d91SRobert Wu  * You may obtain a copy of the License at
7*05767d91SRobert Wu  *
8*05767d91SRobert Wu  *      http://www.apache.org/licenses/LICENSE-2.0
9*05767d91SRobert Wu  *
10*05767d91SRobert Wu  * Unless required by applicable law or agreed to in writing, software
11*05767d91SRobert Wu  * distributed under the License is distributed on an "AS IS" BASIS,
12*05767d91SRobert Wu  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*05767d91SRobert Wu  * See the License for the specific language governing permissions and
14*05767d91SRobert Wu  * limitations under the License.
15*05767d91SRobert Wu  */
16*05767d91SRobert Wu 
17*05767d91SRobert Wu #include <thread>
18*05767d91SRobert Wu #include <iostream>
19*05767d91SRobert Wu 
20*05767d91SRobert Wu #include <gtest/gtest.h>
21*05767d91SRobert Wu #include "utils/LockFreeQueue.h"
22*05767d91SRobert Wu 
23*05767d91SRobert Wu /**
24*05767d91SRobert Wu  * Tests
25*05767d91SRobert Wu  * =====
26*05767d91SRobert Wu  *
27*05767d91SRobert Wu  * READ/POP:
28*05767d91SRobert Wu  *  - if queue is empty return false
29*05767d91SRobert Wu  *  - if queue has elements return true
30*05767d91SRobert Wu  *  - returns correct value once
31*05767d91SRobert Wu  *  - returns correct value more than once
32*05767d91SRobert Wu  *
33*05767d91SRobert Wu  * WRITE/PUSH:
34*05767d91SRobert Wu  *  - if queue is full return false
35*05767d91SRobert Wu  *  - if queue has space return true
36*05767d91SRobert Wu  *
37*05767d91SRobert Wu  * WRAP:
38*05767d91SRobert Wu  *  - read from full queue, then write one more element, then correct read
39*05767d91SRobert Wu  *
40*05767d91SRobert Wu  * PEEK:
41*05767d91SRobert Wu  *  - peek once
42*05767d91SRobert Wu  *  - peek twice
43*05767d91SRobert Wu  *
44*05767d91SRobert Wu  * SIZE:
45*05767d91SRobert Wu  *  - correct zero
46*05767d91SRobert Wu  *  - correct once
47*05767d91SRobert Wu  *  - correct many
48*05767d91SRobert Wu  *
49*05767d91SRobert Wu  * MULTI-THREADED:
50*05767d91SRobert Wu  *  - write and read concurrently, queue is empty at end and item order is maintained
51*05767d91SRobert Wu  *
52*05767d91SRobert Wu  * CANNOT TEST:
53*05767d91SRobert Wu  *  - read/writes correct after wraparound (takes too long to run)
54*05767d91SRobert Wu  *  - Constructing queue with non power of 2 capacity results in assert failure (needs death test)
55*05767d91SRobert Wu  *  - Constructing queue with signed type results in assert failure (needs death test)
56*05767d91SRobert Wu  *
57*05767d91SRobert Wu  */
58*05767d91SRobert Wu 
59*05767d91SRobert Wu constexpr int kQueueCapacity = 2;
60*05767d91SRobert Wu 
61*05767d91SRobert Wu class TestLockFreeQueue : public ::testing::Test {
62*05767d91SRobert Wu 
63*05767d91SRobert Wu public:
64*05767d91SRobert Wu 
65*05767d91SRobert Wu     int result1;
66*05767d91SRobert Wu     int result2;
67*05767d91SRobert Wu     int result3;
68*05767d91SRobert Wu     LockFreeQueue<int, kQueueCapacity> q;
69*05767d91SRobert Wu };
70*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,PopReturnsFalseWhenEmpty)71*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PopReturnsFalseWhenEmpty){
72*05767d91SRobert Wu     bool result = q.pop(result1);
73*05767d91SRobert Wu     ASSERT_EQ(result, false);
74*05767d91SRobert Wu }
75*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,PopReturnsTrueWhenNotEmpty)76*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PopReturnsTrueWhenNotEmpty){
77*05767d91SRobert Wu     q.push(123);
78*05767d91SRobert Wu     bool result = q.pop(result1);
79*05767d91SRobert Wu     ASSERT_EQ(result, true);
80*05767d91SRobert Wu }
81*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,PopReturnsOneCorrectValue)82*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PopReturnsOneCorrectValue){
83*05767d91SRobert Wu     q.push(123);
84*05767d91SRobert Wu     q.pop(result1);
85*05767d91SRobert Wu     ASSERT_EQ(result1, 123);
86*05767d91SRobert Wu }
87*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,PopReturnsManyCorrectValues)88*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PopReturnsManyCorrectValues){
89*05767d91SRobert Wu     q.push(123);
90*05767d91SRobert Wu     q.push(456);
91*05767d91SRobert Wu     q.pop(result1);
92*05767d91SRobert Wu     q.pop(result2);
93*05767d91SRobert Wu     ASSERT_EQ(result1, 123);
94*05767d91SRobert Wu     ASSERT_EQ(result2, 456);
95*05767d91SRobert Wu }
96*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,PushWhenFullReturnsFalse)97*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PushWhenFullReturnsFalse){
98*05767d91SRobert Wu     q.push(123);
99*05767d91SRobert Wu     q.push(123);
100*05767d91SRobert Wu     ASSERT_EQ(q.push(123), false);
101*05767d91SRobert Wu }
102*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,PushWhenSpaceAvailableReturnsTrue)103*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PushWhenSpaceAvailableReturnsTrue){
104*05767d91SRobert Wu     ASSERT_EQ(q.push(123), true);
105*05767d91SRobert Wu }
106*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,PushHandlesWrapCorrectly)107*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PushHandlesWrapCorrectly){
108*05767d91SRobert Wu     q.push(123);
109*05767d91SRobert Wu     q.push(234);
110*05767d91SRobert Wu     q.pop(result1);
111*05767d91SRobert Wu     q.push(999);
112*05767d91SRobert Wu     q.pop(result2);
113*05767d91SRobert Wu     ASSERT_EQ(result2, 234);
114*05767d91SRobert Wu     q.pop(result3);
115*05767d91SRobert Wu     ASSERT_EQ(result3, 999);
116*05767d91SRobert Wu }
117*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,PeekWhenEmptyReturnsFalse)118*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PeekWhenEmptyReturnsFalse){
119*05767d91SRobert Wu     ASSERT_EQ(q.peek(result1), false);
120*05767d91SRobert Wu }
121*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,PeekWhenNotEmptyReturnsTrue)122*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PeekWhenNotEmptyReturnsTrue){
123*05767d91SRobert Wu     q.push(123);
124*05767d91SRobert Wu     ASSERT_EQ(q.peek(result1), true);
125*05767d91SRobert Wu }
126*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,PeekReturnsCorrectValueOnce)127*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PeekReturnsCorrectValueOnce){
128*05767d91SRobert Wu     q.push(456);
129*05767d91SRobert Wu     q.peek(result1);
130*05767d91SRobert Wu     ASSERT_EQ(result1, 456);
131*05767d91SRobert Wu }
132*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,PeekReturnsCorrectValueTwice)133*05767d91SRobert Wu TEST_F(TestLockFreeQueue, PeekReturnsCorrectValueTwice){
134*05767d91SRobert Wu     q.push(456);
135*05767d91SRobert Wu     q.peek(result1);
136*05767d91SRobert Wu     q.peek(result2);
137*05767d91SRobert Wu     ASSERT_EQ(result2, 456);
138*05767d91SRobert Wu }
139*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,SizeReturnsZeroAfterInit)140*05767d91SRobert Wu TEST_F(TestLockFreeQueue, SizeReturnsZeroAfterInit){
141*05767d91SRobert Wu     ASSERT_EQ(q.size(), 0);
142*05767d91SRobert Wu }
143*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,SizeIsOneAfterPushOnce)144*05767d91SRobert Wu TEST_F(TestLockFreeQueue, SizeIsOneAfterPushOnce){
145*05767d91SRobert Wu     q.push(321);
146*05767d91SRobert Wu     ASSERT_EQ(q.size(), 1);
147*05767d91SRobert Wu }
148*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,SizeIsCorrectAfterPushingMaxItems)149*05767d91SRobert Wu TEST_F(TestLockFreeQueue, SizeIsCorrectAfterPushingMaxItems){
150*05767d91SRobert Wu     for (int i = 0; i < kQueueCapacity; ++i) { q.push(i); }
151*05767d91SRobert Wu     ASSERT_EQ(q.size(), kQueueCapacity);
152*05767d91SRobert Wu }
153*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,SizeCorrectAfterWriteCounterWraps)154*05767d91SRobert Wu TEST_F(TestLockFreeQueue, SizeCorrectAfterWriteCounterWraps){
155*05767d91SRobert Wu 
156*05767d91SRobert Wu     const uint32_t kCapacity = (uint32_t) 1 << 7;
157*05767d91SRobert Wu     LockFreeQueue<int, kCapacity, uint8_t> myQ;
158*05767d91SRobert Wu 
159*05767d91SRobert Wu     for (int i = 0; i < UINT8_MAX; ++i) {
160*05767d91SRobert Wu         myQ.push(i);
161*05767d91SRobert Wu         myQ.pop(result1);
162*05767d91SRobert Wu     }
163*05767d91SRobert Wu 
164*05767d91SRobert Wu     myQ.push(1);
165*05767d91SRobert Wu     ASSERT_EQ(myQ.size(), 1);
166*05767d91SRobert Wu }
167*05767d91SRobert Wu 
TEST_F(TestLockFreeQueue,MultiThreadedTest)168*05767d91SRobert Wu TEST_F(TestLockFreeQueue, MultiThreadedTest){
169*05767d91SRobert Wu 
170*05767d91SRobert Wu     // Push and pop from the queue concurrently
171*05767d91SRobert Wu     // Check that the queue is empty
172*05767d91SRobert Wu     // Check that the order of the read values matches the order of the written values
173*05767d91SRobert Wu 
174*05767d91SRobert Wu     constexpr int kQueueCapacity = 2048;
175*05767d91SRobert Wu     LockFreeQueue<int, kQueueCapacity> myQ;
176*05767d91SRobert Wu     std::array<int, kQueueCapacity> sourceData;
177*05767d91SRobert Wu     std::array<int, kQueueCapacity> targetData { 0 };
178*05767d91SRobert Wu 
179*05767d91SRobert Wu     // Populate the source data
180*05767d91SRobert Wu     for (int i = 0; i < kQueueCapacity; i++){
181*05767d91SRobert Wu         sourceData[i] = i;
182*05767d91SRobert Wu     }
183*05767d91SRobert Wu 
184*05767d91SRobert Wu     std::thread writer([&myQ, &sourceData](){
185*05767d91SRobert Wu         for (int i = 0; i < kQueueCapacity; i++){
186*05767d91SRobert Wu             myQ.push(sourceData[i]);
187*05767d91SRobert Wu         }
188*05767d91SRobert Wu     });
189*05767d91SRobert Wu 
190*05767d91SRobert Wu     std::thread reader([&myQ, &targetData](){
191*05767d91SRobert Wu         for (int i = 0; i < kQueueCapacity; i++){
192*05767d91SRobert Wu             // pop the latest element, or wait for it to become available
193*05767d91SRobert Wu             while (!myQ.pop(targetData[i])){
194*05767d91SRobert Wu                 std::cout << "Waiting for element at index " << i << " to be written" << std::endl;
195*05767d91SRobert Wu                 usleep(500);
196*05767d91SRobert Wu             }
197*05767d91SRobert Wu         }
198*05767d91SRobert Wu     });
199*05767d91SRobert Wu 
200*05767d91SRobert Wu     writer.join();
201*05767d91SRobert Wu     reader.join();
202*05767d91SRobert Wu 
203*05767d91SRobert Wu     int v;
204*05767d91SRobert Wu     ASSERT_FALSE(myQ.pop(v));
205*05767d91SRobert Wu 
206*05767d91SRobert Wu     // Check that the target matches the source
207*05767d91SRobert Wu     for (int i = 0; i < kQueueCapacity; i++){
208*05767d91SRobert Wu         ASSERT_EQ(sourceData[i], targetData[i]) << "Elements at index " << i << " did not match";
209*05767d91SRobert Wu     }
210*05767d91SRobert Wu }
211