VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTSg.cpp@ 105155

Last change on this file since 105155 was 102886, checked in by vboxsync, 12 months ago

Runtime/tstRTSg: Ensure that u64First <= u64Last when passed to RTRandAdvU64Ex() as it will return very large values otherwise breaking the testcase as the offset is not in the range to be expected, fixes spurious testcase failes [better fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.8 KB
Line 
1/* $Id: tstRTSg.cpp 102886 2024-01-16 08:59:26Z vboxsync $ */
2/** @file
3 * IPRT Testcase - Scatter / Gather Buffers.
4 */
5
6/*
7 * Copyright (C) 2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/sg.h>
42
43#include <iprt/mem.h>
44#include <iprt/rand.h>
45#include <iprt/string.h>
46#include <iprt/test.h>
47#include <iprt/time.h>
48
49
50/*********************************************************************************************************************************
51* Global Variables *
52*********************************************************************************************************************************/
53static RTTEST g_hTest;
54
55
56
57static void testEmpty(void)
58{
59 RTTestSub(g_hTest, "empty");
60
61 RTSGBUF SgBuf;
62 RTSgBufInit(&SgBuf, NULL, 0);
63 RTTESTI_CHECK(RTSgBufCalcTotalLength(&SgBuf) == 0);
64 RTTESTI_CHECK(RTSgBufCalcLengthLeft(&SgBuf) == 0);
65 RTTESTI_CHECK(RTSgBufIsAtStart(&SgBuf));
66 RTTESTI_CHECK(RTSgBufIsAtEnd(&SgBuf));
67 RTTESTI_CHECK(!RTSgBufIsAtStartOfSegment(&SgBuf));
68 size_t cbIgn;
69 RTTESTI_CHECK(RTSgBufGetCurrentSegment(&SgBuf, _1K, &cbIgn) == NULL);
70 RTTESTI_CHECK(RTSgBufGetCurrentSegment(&SgBuf, 0, &cbIgn) == NULL);
71
72 RTSgBufReset(&SgBuf);
73 RTTESTI_CHECK(RTSgBufCalcTotalLength(&SgBuf) == 0);
74 RTTESTI_CHECK(RTSgBufCalcLengthLeft(&SgBuf) == 0);
75 RTTESTI_CHECK(RTSgBufIsAtStart(&SgBuf));
76 RTTESTI_CHECK(RTSgBufIsAtEnd(&SgBuf));
77 RTTESTI_CHECK(!RTSgBufIsAtStartOfSegment(&SgBuf));
78
79 RTSgBufReset(&SgBuf);
80 RTTESTI_CHECK(RTSgBufAdvance(&SgBuf, _1K) == 0);
81 RTSgBufReset(&SgBuf);
82 RTTESTI_CHECK(RTSgBufAdvance(&SgBuf, 0) == 0);
83 RTSgBufReset(&SgBuf);
84 RTTESTI_CHECK(RTSgBufSet(&SgBuf, 0xf6, _1K) == 0);
85 RTSgBufReset(&SgBuf);
86 RTTESTI_CHECK(RTSgBufSet(&SgBuf, 0xf6, 0) == 0);
87 RTSgBufReset(&SgBuf);
88 RTTESTI_CHECK(RTSgBufGetNextSegment(&SgBuf, &cbIgn) == NULL);
89 RTSgBufReset(&SgBuf);
90 RTTESTI_CHECK(RTSgBufIsZero(&SgBuf, 0));
91 RTSgBufReset(&SgBuf);
92 RTTESTI_CHECK(RTSgBufIsZero(&SgBuf, _1K));
93 RTSgBufReset(&SgBuf);
94 RTTESTI_CHECK(RTSgBufIsZero(&SgBuf, ~(size_t)0));
95
96 RTSGBUF SgBuf2;
97 RTSgBufInit(&SgBuf2, NULL, 0);
98
99 RTTESTI_CHECK(RTSgBufCmp(&SgBuf, &SgBuf2, _1K) == 0);
100 RTTESTI_CHECK(RTSgBufCmp(&SgBuf, &SgBuf2, 64) == 0);
101 RTTESTI_CHECK(RTSgBufCmp(&SgBuf, &SgBuf2, 0) == 0);
102
103 uint8_t abTmp[64] = { 0xf7, };
104 RTSgBufReset(&SgBuf);
105 RTTESTI_CHECK(RTSgBufCopyToBuf(&SgBuf, abTmp, sizeof(abTmp)) == 0);
106 RTSgBufReset(&SgBuf);
107 RTTESTI_CHECK(RTSgBufCopyFromBuf(&SgBuf, abTmp, sizeof(abTmp)) == 0);
108}
109
110
111static PRTSGBUF createRandBuffer(RTRAND hRnd, unsigned cMaxSegs, size_t cbMin, size_t cbMax, bool fAllowZeroSegs, size_t *pcbTotal)
112{
113 unsigned const cSegs = RTRandAdvU32Ex(hRnd, 1, cMaxSegs);
114 size_t const cbTotal = (size_t)RTRandAdvU64Ex(hRnd, RT_MAX(cbMin, fAllowZeroSegs ? 1 : cSegs), cbMax);
115 PRTSGBUF pSgBuf = (PRTSGBUF)RTMemAlloc(cSegs * sizeof(RTSGSEG) + sizeof(*pSgBuf) + cbTotal);
116 if (pSgBuf)
117 {
118 PRTSGSEG paSegs = (PRTSGSEG)(pSgBuf + 1);
119 uint8_t *pbBytes = (uint8_t *)&paSegs[cSegs];
120 RTRandAdvBytes(hRnd, pbBytes, cbTotal);
121
122 size_t cbLeft = cbTotal;
123 unsigned idxSeg;
124 for (idxSeg = 0; idxSeg < cSegs - 1; idxSeg++)
125 {
126 size_t const cbSeg = cbLeft ? (size_t)RTRandAdvU64Ex(hRnd, fAllowZeroSegs ? 0 : 1, cbLeft) : 0;
127 paSegs[idxSeg].cbSeg = cbSeg;
128 paSegs[idxSeg].pvSeg = pbBytes;
129 pbBytes += cbSeg;
130 cbLeft -= cbSeg;
131 }
132 paSegs[idxSeg].cbSeg = cbLeft;
133 paSegs[idxSeg].pvSeg = pbBytes;
134
135 RTSgBufInit(pSgBuf, paSegs, cSegs);
136 RTTESTI_CHECK(RTSgBufCalcTotalLength(pSgBuf) == cbTotal);
137
138 *pcbTotal = cbTotal;
139 return pSgBuf;
140 }
141 RTTestFailed(g_hTest, "RTMemAlloc failed: cSegs=%u cbTotal=%#zx", cSegs, cbTotal);
142 *pcbTotal = 0;
143 return NULL;
144}
145
146
147static void testBasic(void)
148{
149 RTTestSub(g_hTest, "basics");
150
151 RTRAND hRnd;
152 int rc = RTRandAdvCreateParkMiller(&hRnd);
153 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
154 if (RT_FAILURE(rc))
155 return;
156
157 uint64_t u64Seed = RTTimeSystemNanoTS();
158 rc = RTRandAdvSeed(hRnd, u64Seed);
159 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
160 if (RT_FAILURE(rc))
161 {
162 RTRandAdvDestroy(hRnd);
163 return;
164 }
165 RTTestIPrintf(RTTESTLVL_ALWAYS, "Seed: %#RX64\n", u64Seed);
166
167 for (unsigned iBufVar = 0; iBufVar < 64; iBufVar++)
168 {
169 size_t cbSgBuf1;
170 PRTSGBUF pSgBuf1 = createRandBuffer(hRnd, 16, 32, _1M, true, &cbSgBuf1);
171 RTTESTI_CHECK_RETV(pSgBuf1);
172
173 /* Do random advancing using RTSgBufAdvance. */
174 for (unsigned iRun = 0; iRun < _1K; iRun++)
175 {
176 RTTESTI_CHECK(RTSgBufIsAtStart(pSgBuf1));
177 RTTESTI_CHECK(RTSgBufIsAtStartOfSegment(pSgBuf1));
178 RTTESTI_CHECK(RTSgBufCalcLengthLeft(pSgBuf1) == cbSgBuf1);
179
180 size_t cbLeft = cbSgBuf1;
181 while (cbLeft > 0)
182 {
183 size_t cbToAdv = (size_t)RTRandAdvU64Ex(hRnd, 0, iRun & 1 ? cbSgBuf1 * 2 : cbLeft);
184 size_t cbActual = RTSgBufAdvance(pSgBuf1, cbToAdv);
185 RTTESTI_CHECK(cbActual <= cbToAdv);
186 RTTESTI_CHECK(cbActual <= cbLeft);
187 cbLeft -= cbActual;
188 }
189
190 RTTESTI_CHECK(!RTSgBufIsAtStart(pSgBuf1));
191 if ( !RTSgBufIsAtEnd(pSgBuf1)
192 || RTSgBufCalcLengthLeft(pSgBuf1) != 0
193 || RTSgBufIsAtStartOfSegment(pSgBuf1))
194 {
195 RTTESTI_CHECK(RTSgBufIsAtEnd(pSgBuf1));
196 RTTESTI_CHECK(RTSgBufCalcLengthLeft(pSgBuf1) == 0);
197 RTTESTI_CHECK(!RTSgBufIsAtStartOfSegment(pSgBuf1));
198 RTTestIFailureDetails("iBufVar=%u iRun=%u cSegs=%u cbSgBuf1=%#zx - idxSeg=%u cbSegLeft=%#zx:\n",
199 iBufVar, iRun, pSgBuf1->cSegs, cbSgBuf1, pSgBuf1->idxSeg, pSgBuf1->cbSegLeft);
200 for (unsigned idxSeg = 0; idxSeg < pSgBuf1->cSegs; idxSeg++)
201 RTTestIFailureDetails(" paSegs[%u]: %p LB %#zx\n",
202 idxSeg, pSgBuf1->paSegs[idxSeg].pvSeg, pSgBuf1->paSegs[idxSeg].cbSeg);
203 break;
204 }
205
206 RTSgBufReset(pSgBuf1);
207 }
208
209 /* Use RTSgBufGetNextSegment with random starting point. */
210 for (unsigned iRun = 0; iRun < RT_MIN(_1K, cbSgBuf1); iRun++)
211 {
212 RTSgBufReset(pSgBuf1);
213 size_t cbLeft = cbSgBuf1;
214 if (iRun > 1)
215 {
216 size_t const cbInitial = (size_t)RTRandAdvU64Ex(hRnd, iRun, cbSgBuf1);
217 size_t cbAdvanced = RTSgBufAdvance(pSgBuf1, cbInitial);
218 RTTESTI_CHECK_MSG(cbAdvanced == cbInitial, ("iBufVar=%u iRun=%u cbAdvanced=%zu, cbInitial=%zu\n", iBufVar, iRun, cbAdvanced, cbInitial));
219 /* should probably print part of pSgBuf1 values... */
220 cbLeft -= cbInitial;
221 }
222 for (;;)
223 {
224 RTTESTI_CHECK_MSG(RTSgBufCalcLengthLeft(pSgBuf1) == cbLeft, ("pSgBuf1_calcLen=%zu, cbLeft=%zu\n",
225 RTSgBufCalcLengthLeft(pSgBuf1), cbLeft));
226 size_t cbThisSeg = 0;
227 void *pvThisSeg = RTSgBufGetNextSegment(pSgBuf1, &cbThisSeg);
228 if (!pvThisSeg)
229 break;
230 RTTESTI_CHECK(cbThisSeg > 0);
231 RTTESTI_CHECK(cbThisSeg <= cbLeft);
232 cbLeft -= cbThisSeg;
233 }
234 RTTESTI_CHECK_MSG(cbLeft == 0, ("cbLeft=%zu\n", cbLeft));
235 RTTESTI_CHECK(RTSgBufIsAtEnd(pSgBuf1));
236 RTTESTI_CHECK(RTSgBufCalcLengthLeft(pSgBuf1) == 0);
237 RTTESTI_CHECK(!RTSgBufIsAtStartOfSegment(pSgBuf1));
238 }
239
240 /* Copy out of the S/G buffer and into a flat buffer w/ electric guard page: */
241 bool const fHead = RTRandAdvU32Ex(hRnd, 0, 1) == 0;
242 void *pvTmp = NULL;
243 rc = RTTestGuardedAlloc(g_hTest, cbSgBuf1, 1, fHead, &pvTmp);
244 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
245 if (RT_SUCCESS(rc))
246 {
247 uint8_t const *pbSrc = (uint8_t const *)pSgBuf1->paSegs[0].pvSeg;
248 for (unsigned iRun = 0; iRun < RT_MIN(_1K, cbSgBuf1); iRun++)
249 {
250 RTSgBufReset(pSgBuf1);
251 size_t cbLeft = cbSgBuf1;
252 size_t cbInitial = 0;
253 if (iRun > 1)
254 {
255 cbInitial = (size_t)RTRandAdvU64Ex(hRnd, iRun, cbSgBuf1);
256 size_t cbAdvanced = RTSgBufAdvance(pSgBuf1, cbInitial);
257 RTTESTI_CHECK_MSG(cbAdvanced == cbInitial, ("cbAdvanced=%zu, cbInitial=%zu\n",
258 cbAdvanced, cbInitial));
259 cbLeft -= cbInitial;
260 }
261
262 size_t cbToCopy = cbLeft;
263 if (iRun > _1K / 4 * 3)
264 cbToCopy = (size_t)RTRandAdvU64Ex(hRnd, 0, iRun & 1 ? cbToCopy : cbSgBuf1);
265
266 uint8_t *pbDst = (uint8_t *)pvTmp;
267 if (!fHead)
268 pbDst += cbSgBuf1 - RT_MIN(cbToCopy, cbLeft);
269 size_t cbCopied = RTSgBufCopyToBuf(pSgBuf1, pbDst, cbToCopy);
270
271 RTTESTI_CHECK(cbCopied <= cbLeft);
272 RTTESTI_CHECK(cbCopied <= cbToCopy);
273 RTTESTI_CHECK_MSG(cbCopied == RT_MIN(cbToCopy, cbLeft), ("cbCopied=%zu, cbToCopy=%zu, cbLeft=%zu\n",
274 cbCopied, cbToCopy, cbLeft));
275 RTTESTI_CHECK(memcmp(&pbSrc[cbInitial], pbDst, cbCopied) == 0);
276
277 RTTESTI_CHECK_MSG(RTSgBufCalcLengthLeft(pSgBuf1) == cbLeft - cbCopied,
278 ("pSgBuf1_calcLen=%zu cbLeft=%zu cbCopied=%zu\n",
279 RTSgBufCalcLengthLeft(pSgBuf1), cbLeft, cbCopied));
280 }
281
282 RTTestGuardedFree(g_hTest, pvTmp);
283 }
284
285 RTMemFree(pSgBuf1);
286 }
287
288 rc = RTRandAdvDestroy(hRnd);
289 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
290}
291
292
293int main()
294{
295 RTEXITCODE rcExit = RTTestInitAndCreate("tstRTSg", &g_hTest);
296 if (rcExit != RTEXITCODE_SUCCESS)
297 return rcExit;
298 RTTestBanner(g_hTest);
299
300 testEmpty();
301 testBasic();
302
303 return RTTestSummaryAndDestroy(g_hTest);
304}
305
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette