1 /* 2 * Copyright 2022 Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Leorize, leorize+oss@disroot.org 7 */ 8 9 10 #include "MemoryRingIOTest.h" 11 12 #include <stdio.h> 13 #include <string.h> 14 15 #include <OS.h> 16 17 #include <cppunit/Test.h> 18 #include <cppunit/TestCaller.h> 19 #include <cppunit/TestSuite.h> 20 #include <TestUtils.h> 21 #include <ThreadedTestCaller.h> 22 23 24 #define BIG_PAYLOAD \ 25 "a really long string that can fill the buffer multiple times" 26 #define FULL_PAYLOAD "16 characters x" 27 #define SMALL_PAYLOAD "shorter" 28 29 30 static void 31 ReadCheck(BMemoryRingIO& ring, const void* cmp, size_t size) 32 { 33 char* buffer = new char[size]; 34 memset(buffer, 0, size); 35 size_t read; 36 CHK(ring.ReadExactly(buffer, size, &read) == B_OK); 37 CHK(read == size); 38 CHK(memcmp(buffer, cmp, size) == 0); 39 } 40 41 42 void 43 MemoryRingIOTest::WriteTest() 44 { 45 CHK(fRing.InitCheck() == B_OK); 46 47 CHK(fRing.WriteExactly(SMALL_PAYLOAD, sizeof(SMALL_PAYLOAD), NULL) == B_OK); 48 CHK(fRing.WriteExactly(FULL_PAYLOAD, sizeof(FULL_PAYLOAD), NULL) == B_OK); 49 CHK(fRing.WriteExactly(BIG_PAYLOAD, sizeof(BIG_PAYLOAD), NULL) == B_OK); 50 } 51 52 53 void 54 MemoryRingIOTest::ReadTest() 55 { 56 CHK(fRing.InitCheck() == B_OK); 57 58 ReadCheck(fRing, SMALL_PAYLOAD, sizeof(SMALL_PAYLOAD)); 59 ReadCheck(fRing, FULL_PAYLOAD, sizeof(FULL_PAYLOAD)); 60 ReadCheck(fRing, BIG_PAYLOAD, sizeof(BIG_PAYLOAD)); 61 } 62 63 64 void 65 MemoryRingIOTest::BusyWriterTest() 66 { 67 CHK(fRing.InitCheck() == B_OK); 68 CHK(fRing.BufferSize() < sizeof(BIG_PAYLOAD)); 69 70 CHK(fRing.WriteExactly(BIG_PAYLOAD, sizeof(BIG_PAYLOAD), NULL) 71 == B_DEVICE_FULL); 72 } 73 74 75 void 76 MemoryRingIOTest::BusyReaderTest() 77 { 78 CHK(fRing.InitCheck() == B_OK); 79 80 char buffer[100]; 81 CHK(fRing.Read(buffer, sizeof(buffer)) == 0); 82 } 83 84 85 void 86 MemoryRingIOTest::ReadWriteSingleTest() 87 { 88 CHK(fRing.SetSize(sizeof(BIG_PAYLOAD)) == B_OK); 89 CHK(fRing.WriteExactly(BIG_PAYLOAD, sizeof(BIG_PAYLOAD)) == B_OK); 90 ReadCheck(fRing, BIG_PAYLOAD, sizeof(BIG_PAYLOAD)); 91 92 CHK(fRing.SetSize(sizeof(FULL_PAYLOAD)) == B_OK); 93 // the size of FULL_PAYLOAD is a power of two, so our ring 94 // should be using the exact size. 95 CHK(fRing.BufferSize() == sizeof(FULL_PAYLOAD)); 96 CHK(fRing.WriteExactly(FULL_PAYLOAD, sizeof(FULL_PAYLOAD)) == B_OK); 97 ReadCheck(fRing, FULL_PAYLOAD, sizeof(FULL_PAYLOAD)); 98 99 CHK(fRing.SetSize(sizeof(SMALL_PAYLOAD)) == B_OK); 100 CHK(fRing.WriteExactly(SMALL_PAYLOAD, sizeof(SMALL_PAYLOAD)) == B_OK); 101 ReadCheck(fRing, SMALL_PAYLOAD, sizeof(SMALL_PAYLOAD)); 102 } 103 104 105 void 106 MemoryRingIOTest::InvalidResizeTest() 107 { 108 CHK(fRing.SetSize(sizeof(FULL_PAYLOAD)) == B_OK); 109 CHK(fRing.WriteExactly(FULL_PAYLOAD, sizeof(FULL_PAYLOAD)) == B_OK); 110 CHK(fRing.SetSize(0) == B_BAD_VALUE); 111 } 112 113 114 void 115 MemoryRingIOTest::TimeoutTest() 116 { 117 fRing.Clear(); 118 CHK(fRing.SetSize(0) == B_OK); 119 bigtime_t start = system_time(); 120 const bigtime_t timeout = 100; 121 122 CHK(fRing.WaitForRead(timeout) == B_TIMED_OUT); 123 CHK(system_time() - start <= timeout + 10); 124 125 start = system_time(); 126 CHK(fRing.WaitForWrite(timeout) == B_TIMED_OUT); 127 CHK(system_time() - start <= timeout + 10); 128 } 129 130 131 void 132 MemoryRingIOTest::_DisableWriteOnFullBuffer() 133 { 134 CHK(fRing.InitCheck() == B_OK); 135 136 while (fRing.SpaceAvailable() > 0) 137 fRing.WaitForRead(); 138 139 /* snooze for sometime to ensure that the other thread entered 140 * WaitForWrite(). 141 */ 142 snooze(1000); 143 /* this should unblock the other thread */ 144 fRing.SetWriteDisabled(true); 145 } 146 147 148 void 149 MemoryRingIOTest::_DisableWriteOnEmptyBuffer() 150 { 151 CHK(fRing.InitCheck() == B_OK); 152 153 while (fRing.BytesAvailable() > 0) 154 fRing.WaitForWrite(); 155 156 /* snooze for sometime to ensure that the other thread entered 157 * WaitForRead(). 158 */ 159 snooze(1000); 160 /* this should unblock the other thread */ 161 fRing.SetWriteDisabled(true); 162 } 163 164 165 /* static */ void 166 MemoryRingIOTest::AddTests(BTestSuite& parent) { 167 CppUnit::TestSuite* suite = new CppUnit::TestSuite("MemoryRingIOTest"); 168 BThreadedTestCaller<MemoryRingIOTest>* caller; 169 170 MemoryRingIOTest* big = new MemoryRingIOTest(sizeof(BIG_PAYLOAD)); 171 caller = new BThreadedTestCaller<MemoryRingIOTest>( 172 "MemoryRingIOTest: RW threaded, big buffer", big); 173 caller->addThread("WR", &MemoryRingIOTest::WriteTest); 174 caller->addThread("RD", &MemoryRingIOTest::ReadTest); 175 suite->addTest(caller); 176 177 MemoryRingIOTest* full = new MemoryRingIOTest(sizeof(FULL_PAYLOAD)); 178 caller = new BThreadedTestCaller<MemoryRingIOTest>( 179 "MemoryRingIOTest: RW threaded, medium buffer", full); 180 caller->addThread("WR", &MemoryRingIOTest::WriteTest); 181 caller->addThread("RD", &MemoryRingIOTest::ReadTest); 182 suite->addTest(caller); 183 184 MemoryRingIOTest* small = new MemoryRingIOTest(sizeof(SMALL_PAYLOAD)); 185 caller = new BThreadedTestCaller<MemoryRingIOTest>( 186 "MemoryRingIOTest: RW threaded, small buffer", small); 187 caller->addThread("WR", &MemoryRingIOTest::WriteTest); 188 caller->addThread("RD", &MemoryRingIOTest::ReadTest); 189 suite->addTest(caller); 190 191 MemoryRingIOTest* endWrite = new MemoryRingIOTest(sizeof(FULL_PAYLOAD)); 192 caller = new BThreadedTestCaller<MemoryRingIOTest>( 193 "MemoryRingIOTest: RW threaded, reader set end reached on writer wait", 194 endWrite); 195 caller->addThread("WR #1", &MemoryRingIOTest::BusyWriterTest); 196 caller->addThread("WR #2", &MemoryRingIOTest::BusyWriterTest); 197 caller->addThread("WR #3", &MemoryRingIOTest::BusyWriterTest); 198 caller->addThread("RD", &MemoryRingIOTest::_DisableWriteOnFullBuffer); 199 suite->addTest(caller); 200 201 MemoryRingIOTest* endRead = new MemoryRingIOTest(sizeof(FULL_PAYLOAD)); 202 caller = new BThreadedTestCaller<MemoryRingIOTest>( 203 "MemoryRingIOTest: RW threaded, writer set end reached on reader wait", 204 endRead); 205 caller->addThread("RD #1", &MemoryRingIOTest::BusyReaderTest); 206 caller->addThread("RD #2", &MemoryRingIOTest::BusyReaderTest); 207 caller->addThread("RD #3", &MemoryRingIOTest::BusyReaderTest); 208 caller->addThread("WR", &MemoryRingIOTest::_DisableWriteOnEmptyBuffer); 209 suite->addTest(caller); 210 211 MemoryRingIOTest* single = new MemoryRingIOTest(0); 212 suite->addTest(new CppUnit::TestCaller<MemoryRingIOTest>( 213 "MemoryRingIOTest: RW single threaded with resizing", 214 &MemoryRingIOTest::ReadWriteSingleTest, single)); 215 suite->addTest(new CppUnit::TestCaller<MemoryRingIOTest>( 216 "MemoryRingIOTest: Attempt to truncate buffer", 217 &MemoryRingIOTest::InvalidResizeTest, single)); 218 suite->addTest(new CppUnit::TestCaller<MemoryRingIOTest>( 219 "MemoryRingIOTest: Wait timeout", 220 &MemoryRingIOTest::TimeoutTest, single)); 221 222 parent.addTest("MemoryRingIOTest", suite); 223 } 224