VirtualBox

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

Last change on this file since 100108 was 99961, checked in by vboxsync, 19 months ago

IPRT/sg: Corrected RTSgBufIsAtEnd and made the code deal with (skip) empty segments. Added a testcase (incomplete). [scm]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.3 KB
Line 
1/* $Id: tstRTSg.cpp 99961 2023-05-24 21:57:27Z vboxsync $ */
2/** @file
3 * IPRT Testcase - S/G 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 RTTESTI_CHECK(RTSgBufAdvance(pSgBuf1, cbInitial) == cbInitial);
201 cbLeft -= cbInitial;
202 }
203 for (;;)
204 {
205 RTTESTI_CHECK(RTSgBufCalcLengthLeft(pSgBuf1) == cbLeft);
206 size_t cbThisSeg = 0;
207 void *pvThisSeg = RTSgBufGetNextSegment(pSgBuf1, &cbThisSeg);
208 if (!pvThisSeg)
209 break;
210 RTTESTI_CHECK(cbThisSeg > 0);
211 RTTESTI_CHECK(cbThisSeg <= cbLeft);
212 cbLeft -= cbThisSeg;
213 }
214 RTTESTI_CHECK(cbLeft == 0);
215 RTTESTI_CHECK(RTSgBufIsAtEnd(pSgBuf1));
216 RTTESTI_CHECK(RTSgBufCalcLengthLeft(pSgBuf1) == 0);
217 RTTESTI_CHECK(!RTSgBufIsAtStartOfSegment(pSgBuf1));
218 }
219
220 /* Copy out of the S/G buffer and into a flat buffer w/ electric guard page: */
221 bool const fHead = RTRandU32Ex(0, 1) == 0;
222 void *pvTmp = NULL;
223 int rc = RTTestGuardedAlloc(g_hTest, cbSgBuf1, 1, fHead, &pvTmp);
224 RTTESTI_CHECK_RC(rc, VINF_SUCCESS);
225 if (RT_SUCCESS(rc))
226 {
227 uint8_t const *pbSrc = (uint8_t const *)pSgBuf1->paSegs[0].pvSeg;
228 for (unsigned iRun = 0; iRun < _1K; iRun++)
229 {
230 RTSgBufReset(pSgBuf1);
231 size_t cbLeft = cbSgBuf1;
232 size_t cbInitial = 0;
233 if (iRun > 1)
234 {
235 cbInitial = (size_t)RTRandU64Ex(iRun, cbSgBuf1);
236 RTTESTI_CHECK(RTSgBufAdvance(pSgBuf1, cbInitial) == cbInitial);
237 cbLeft -= cbInitial;
238 }
239
240 size_t cbToCopy = cbLeft;
241 if (iRun > _1K / 4 * 3)
242 cbToCopy = (size_t)RTRandU64Ex(0, iRun & 1 ? cbToCopy : cbSgBuf1);
243
244 uint8_t *pbDst = (uint8_t *)pvTmp;
245 if (!fHead)
246 pbDst += cbSgBuf1 - RT_MIN(cbToCopy, cbLeft);
247 size_t cbCopied = RTSgBufCopyToBuf(pSgBuf1, pbDst, cbToCopy);
248
249 RTTESTI_CHECK(cbCopied <= cbLeft);
250 RTTESTI_CHECK(cbCopied <= cbToCopy);
251 RTTESTI_CHECK(cbCopied == RT_MIN(cbToCopy, cbLeft));
252 RTTESTI_CHECK(memcmp(&pbSrc[cbInitial], pbDst, cbCopied) == 0);
253
254 RTTESTI_CHECK(RTSgBufCalcLengthLeft(pSgBuf1) == cbLeft - cbCopied);
255 }
256
257 RTTestGuardedFree(g_hTest, pvTmp);
258 }
259
260 RTMemFree(pSgBuf1);
261 }
262}
263
264
265int main()
266{
267 RTEXITCODE rcExit = RTTestInitAndCreate("tstRTSg", &g_hTest);
268 if (rcExit != RTEXITCODE_SUCCESS)
269 return rcExit;
270 RTTestBanner(g_hTest);
271
272 testEmpty();
273 testBasic();
274
275 return RTTestSummaryAndDestroy(g_hTest);
276}
277
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