VirtualBox

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

Last change on this file since 102335 was 101753, checked in by vboxsync, 13 months ago

added more detailed logging, tstRTSg.cpp testcase

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.2 KB
Line 
1/* $Id: tstRTSg.cpp 101753 2023-11-03 15:57:39Z 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
48
49/*********************************************************************************************************************************
50* Global Variables *
51*********************************************************************************************************************************/
52static RTTEST g_hTest;
53
54
55
56static void testEmpty(void)
57{
58 RTTestSub(g_hTest, "empty");
59
60 RTSGBUF SgBuf;
61 RTSgBufInit(&SgBuf, NULL, 0);
62 RTTESTI_CHECK(RTSgBufCalcTotalLength(&SgBuf) == 0);
63 RTTESTI_CHECK(RTSgBufCalcLengthLeft(&SgBuf) == 0);
64 RTTESTI_CHECK(RTSgBufIsAtStart(&SgBuf));
65 RTTESTI_CHECK(RTSgBufIsAtEnd(&SgBuf));
66 RTTESTI_CHECK(!RTSgBufIsAtStartOfSegment(&SgBuf));
67 size_t cbIgn;
68 RTTESTI_CHECK(RTSgBufGetCurrentSegment(&SgBuf, _1K, &cbIgn) == NULL);
69 RTTESTI_CHECK(RTSgBufGetCurrentSegment(&SgBuf, 0, &cbIgn) == NULL);
70
71 RTSgBufReset(&SgBuf);
72 RTTESTI_CHECK(RTSgBufCalcTotalLength(&SgBuf) == 0);
73 RTTESTI_CHECK(RTSgBufCalcLengthLeft(&SgBuf) == 0);
74 RTTESTI_CHECK(RTSgBufIsAtStart(&SgBuf));
75 RTTESTI_CHECK(RTSgBufIsAtEnd(&SgBuf));
76 RTTESTI_CHECK(!RTSgBufIsAtStartOfSegment(&SgBuf));
77
78 RTSgBufReset(&SgBuf);
79 RTTESTI_CHECK(RTSgBufAdvance(&SgBuf, _1K) == 0);
80 RTSgBufReset(&SgBuf);
81 RTTESTI_CHECK(RTSgBufAdvance(&SgBuf, 0) == 0);
82 RTSgBufReset(&SgBuf);
83 RTTESTI_CHECK(RTSgBufSet(&SgBuf, 0xf6, _1K) == 0);
84 RTSgBufReset(&SgBuf);
85 RTTESTI_CHECK(RTSgBufSet(&SgBuf, 0xf6, 0) == 0);
86 RTSgBufReset(&SgBuf);
87 RTTESTI_CHECK(RTSgBufGetNextSegment(&SgBuf, &cbIgn) == NULL);
88 RTSgBufReset(&SgBuf);
89 RTTESTI_CHECK(RTSgBufIsZero(&SgBuf, 0));
90 RTSgBufReset(&SgBuf);
91 RTTESTI_CHECK(RTSgBufIsZero(&SgBuf, _1K));
92 RTSgBufReset(&SgBuf);
93 RTTESTI_CHECK(RTSgBufIsZero(&SgBuf, ~(size_t)0));
94
95 RTSGBUF SgBuf2;
96 RTSgBufInit(&SgBuf2, NULL, 0);
97
98 RTTESTI_CHECK(RTSgBufCmp(&SgBuf, &SgBuf2, _1K) == 0);
99 RTTESTI_CHECK(RTSgBufCmp(&SgBuf, &SgBuf2, 64) == 0);
100 RTTESTI_CHECK(RTSgBufCmp(&SgBuf, &SgBuf2, 0) == 0);
101
102 uint8_t abTmp[64] = { 0xf7, };
103 RTSgBufReset(&SgBuf);
104 RTTESTI_CHECK(RTSgBufCopyToBuf(&SgBuf, abTmp, sizeof(abTmp)) == 0);
105 RTSgBufReset(&SgBuf);
106 RTTESTI_CHECK(RTSgBufCopyFromBuf(&SgBuf, abTmp, sizeof(abTmp)) == 0);
107}
108
109
110static PRTSGBUF createRandBuffer(unsigned cMaxSegs, size_t cbMin, size_t cbMax, bool fAllowZeroSegs, size_t *pcbTotal)
111{
112 unsigned const cSegs = RTRandU32Ex(1, cMaxSegs);
113 size_t const cbTotal = (size_t)RTRandU64Ex(RT_MAX(cbMin, fAllowZeroSegs ? 1 : cSegs), cbMax);
114 PRTSGBUF pSgBuf = (PRTSGBUF)RTMemAlloc(cSegs * sizeof(RTSGSEG) + sizeof(*pSgBuf) + cbTotal);
115 if (pSgBuf)
116 {
117 PRTSGSEG paSegs = (PRTSGSEG)(pSgBuf + 1);
118 uint8_t *pbBytes = (uint8_t *)&paSegs[cSegs];
119 RTRandBytes(pbBytes, cbTotal);
120
121 size_t cbLeft = cbTotal;
122 unsigned idxSeg;
123 for (idxSeg = 0; idxSeg < cSegs - 1; idxSeg++)
124 {
125 size_t const cbSeg = cbLeft ? (size_t)RTRandU64Ex(fAllowZeroSegs ? 0 : 1, cbLeft) : 0;
126 paSegs[idxSeg].cbSeg = cbSeg;
127 paSegs[idxSeg].pvSeg = pbBytes;
128 pbBytes += cbSeg;
129 cbLeft -= cbSeg;
130 }
131 paSegs[idxSeg].cbSeg = cbLeft;
132 paSegs[idxSeg].pvSeg = pbBytes;
133
134 RTSgBufInit(pSgBuf, paSegs, cSegs);
135 RTTESTI_CHECK(RTSgBufCalcTotalLength(pSgBuf) == cbTotal);
136
137 *pcbTotal = cbTotal;
138 return pSgBuf;
139 }
140 RTTestFailed(g_hTest, "RTMemAlloc failed: cSegs=%u cbTotal=%#zx", cSegs, cbTotal);
141 *pcbTotal = 0;
142 return NULL;
143}
144
145
146static void testBasic(void)
147{
148 RTTestSub(g_hTest, "basics");
149
150 for (unsigned iBufVar = 0; iBufVar < 64; iBufVar++)
151 {
152 size_t cbSgBuf1;
153 PRTSGBUF pSgBuf1 = createRandBuffer(16, 32, _1M, true, &cbSgBuf1);
154 RTTESTI_CHECK_RETV(pSgBuf1);
155
156 /* Do random advancing using RTSgBufAdvance. */
157 for (unsigned iRun = 0; iRun < _1K; iRun++)
158 {
159 RTTESTI_CHECK(RTSgBufIsAtStart(pSgBuf1));
160 RTTESTI_CHECK(RTSgBufIsAtStartOfSegment(pSgBuf1));
161 RTTESTI_CHECK(RTSgBufCalcLengthLeft(pSgBuf1) == cbSgBuf1);
162
163 size_t cbLeft = cbSgBuf1;
164 while (cbLeft > 0)
165 {
166 size_t cbToAdv = (size_t)RTRandU64Ex(0, iRun & 1 ? cbSgBuf1 * 2 : cbLeft);
167 size_t cbActual = RTSgBufAdvance(pSgBuf1, cbToAdv);
168 RTTESTI_CHECK(cbActual <= cbToAdv);
169 RTTESTI_CHECK(cbActual <= cbLeft);
170 cbLeft -= cbActual;
171 }
172
173 RTTESTI_CHECK(!RTSgBufIsAtStart(pSgBuf1));
174 if ( !RTSgBufIsAtEnd(pSgBuf1)
175 || RTSgBufCalcLengthLeft(pSgBuf1) != 0
176 || RTSgBufIsAtStartOfSegment(pSgBuf1))
177 {
178 RTTESTI_CHECK(RTSgBufIsAtEnd(pSgBuf1));
179 RTTESTI_CHECK(RTSgBufCalcLengthLeft(pSgBuf1) == 0);
180 RTTESTI_CHECK(!RTSgBufIsAtStartOfSegment(pSgBuf1));
181 RTTestIFailureDetails("iBufVar=%u iRun=%u cSegs=%u cbSgBuf1=%#zx - idxSeg=%u cbSegLeft=%#zx:\n",
182 iBufVar, iRun, pSgBuf1->cSegs, cbSgBuf1, pSgBuf1->idxSeg, pSgBuf1->cbSegLeft);
183 for (unsigned idxSeg = 0; idxSeg < pSgBuf1->cSegs; idxSeg++)
184 RTTestIFailureDetails(" paSegs[%u]: %p LB %#zx\n",
185 idxSeg, pSgBuf1->paSegs[idxSeg].pvSeg, pSgBuf1->paSegs[idxSeg].cbSeg);
186 break;
187 }
188
189 RTSgBufReset(pSgBuf1);
190 }
191
192 /* Use RTSgBufGetNextSegment with random starting point. */
193 for (unsigned iRun = 0; iRun < _1K; iRun++)
194 {
195 RTSgBufReset(pSgBuf1);
196 size_t cbLeft = cbSgBuf1;
197 if (iRun > 1)
198 {
199 size_t const cbInitial = (size_t)RTRandU64Ex(iRun, cbSgBuf1);
200 size_t cbAdvanced = RTSgBufAdvance(pSgBuf1, cbInitial);
201 RTTESTI_CHECK_MSG(cbAdvanced == cbInitial, ("cbAdvanced=%zu, cbInitial=%zu\n", cbAdvanced, cbInitial));
202 /* should probably print part of pSgBuf1 values... */
203 cbLeft -= cbInitial;
204 }
205 for (;;)
206 {
207 RTTESTI_CHECK_MSG(RTSgBufCalcLengthLeft(pSgBuf1) == cbLeft, ("pSgBuf1_calcLen=%zu, cbLeft=%zu\n",
208 RTSgBufCalcLengthLeft(pSgBuf1), cbLeft));
209 size_t cbThisSeg = 0;
210 void *pvThisSeg = RTSgBufGetNextSegment(pSgBuf1, &cbThisSeg);
211 if (!pvThisSeg)
212 break;
213 RTTESTI_CHECK(cbThisSeg > 0);
214 RTTESTI_CHECK(cbThisSeg <= cbLeft);
215 cbLeft -= cbThisSeg;
216 }
217 RTTESTI_CHECK_MSG(cbLeft == 0, ("cbLeft=%zu\n", cbLeft));
218 RTTESTI_CHECK(RTSgBufIsAtEnd(pSgBuf1));
219 RTTESTI_CHECK(RTSgBufCalcLengthLeft(pSgBuf1) == 0);
220 RTTESTI_CHECK(!RTSgBufIsAtStartOfSegment(pSgBuf1));
221 }
222
223 /* Copy out of the S/G buffer and into a flat buffer w/ electric guard page: */
224 bool const fHead = RTRandU32Ex(0, 1) == 0;
225 void *pvTmp = NULL;
226 int rc = RTTestGuardedAlloc(g_hTest, cbSgBuf1, 1, fHead, &pvTmp);
227 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
228 if (RT_SUCCESS(rc))
229 {
230 uint8_t const *pbSrc = (uint8_t const *)pSgBuf1->paSegs[0].pvSeg;
231 for (unsigned iRun = 0; iRun < _1K; iRun++)
232 {
233 RTSgBufReset(pSgBuf1);
234 size_t cbLeft = cbSgBuf1;
235 size_t cbInitial = 0;
236 if (iRun > 1)
237 {
238 cbInitial = (size_t)RTRandU64Ex(iRun, cbSgBuf1);
239 size_t cbAdvanced = RTSgBufAdvance(pSgBuf1, cbInitial);
240 RTTESTI_CHECK_MSG(cbAdvanced == cbInitial, ("cbAdvanced=%zu, cbInitial=%zu\n",
241 cbAdvanced, cbInitial));
242 cbLeft -= cbInitial;
243 }
244
245 size_t cbToCopy = cbLeft;
246 if (iRun > _1K / 4 * 3)
247 cbToCopy = (size_t)RTRandU64Ex(0, iRun & 1 ? cbToCopy : cbSgBuf1);
248
249 uint8_t *pbDst = (uint8_t *)pvTmp;
250 if (!fHead)
251 pbDst += cbSgBuf1 - RT_MIN(cbToCopy, cbLeft);
252 size_t cbCopied = RTSgBufCopyToBuf(pSgBuf1, pbDst, cbToCopy);
253
254 RTTESTI_CHECK(cbCopied <= cbLeft);
255 RTTESTI_CHECK(cbCopied <= cbToCopy);
256 RTTESTI_CHECK_MSG(cbCopied == RT_MIN(cbToCopy, cbLeft), ("cbCopied=%zu, cbToCopy=%zu, cbLeft=%zu\n",
257 cbCopied, cbToCopy, cbLeft));
258 RTTESTI_CHECK(memcmp(&pbSrc[cbInitial], pbDst, cbCopied) == 0);
259
260 RTTESTI_CHECK_MSG(RTSgBufCalcLengthLeft(pSgBuf1) == cbLeft - cbCopied,
261 ("pSgBuf1_calcLen=%zu cbLeft=%zu cbCopied=%zu\n",
262 RTSgBufCalcLengthLeft(pSgBuf1), cbLeft, cbCopied));
263 }
264
265 RTTestGuardedFree(g_hTest, pvTmp);
266 }
267
268 RTMemFree(pSgBuf1);
269 }
270}
271
272
273int main()
274{
275 RTEXITCODE rcExit = RTTestInitAndCreate("tstRTSg", &g_hTest);
276 if (rcExit != RTEXITCODE_SUCCESS)
277 return rcExit;
278 RTTestBanner(g_hTest);
279
280 testEmpty();
281 testBasic();
282
283 return RTTestSummaryAndDestroy(g_hTest);
284}
285
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