VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/sg.cpp

Last change on this file was 106061, checked in by vboxsync, 8 weeks ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.9 KB
Line 
1/* $Id: sg.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - Scatter / Gather buffer handling.
4 */
5
6/*
7 * Copyright (C) 2010-2024 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#include <iprt/string.h>
43#include <iprt/assert.h>
44#include <iprt/asm-mem.h>
45
46
47/**
48 * Gets the next continuous block of buffer data (up to @a *pcbData bytes) and
49 * advances the buffer position past it.
50 */
51static void *rtSgBufGet(PRTSGBUF pSgBuf, size_t *pcbData)
52{
53 /*
54 * Check that the S/G buffer has memory left (!RTSgIsEnd(pSgBuf)).
55 */
56 unsigned const idxSeg = pSgBuf->idxSeg;
57 unsigned const cSegs = pSgBuf->cSegs;
58 if (RT_LIKELY( idxSeg < cSegs
59 && ( pSgBuf->cbSegLeft > 0 /* paranoia, this condition shouldn't occur. */
60 || idxSeg + 1 < cSegs)))
61 {
62 /*
63 * Grab the requested segment chunk.
64 */
65 void * const pvBuf = pSgBuf->pvSegCur;
66 size_t const cbSegLeft = pSgBuf->cbSegLeft;
67 size_t const cbData = RT_MIN(*pcbData, cbSegLeft);
68
69#ifndef RDESKTOP
70 AssertMsg( pSgBuf->cbSegLeft <= 128 * _1M
71 && (uintptr_t)pSgBuf->pvSegCur >= (uintptr_t)pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg
72 && (uintptr_t)pSgBuf->pvSegCur + cbSegLeft <= (uintptr_t)pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg + pSgBuf->paSegs[pSgBuf->idxSeg].cbSeg,
73 ("pSgBuf->idxSeg=%d pSgBuf->cSegs=%d pSgBuf->pvSegCur=%p cbSegLeft=%zd pSgBuf->paSegs[%d].pvSeg=%p pSgBuf->paSegs[%d].cbSeg=%zd\n",
74 pSgBuf->idxSeg, pSgBuf->cSegs, pSgBuf->pvSegCur, cbSegLeft, pSgBuf->idxSeg, pSgBuf->paSegs[pSgBuf->idxSeg].pvSeg, pSgBuf->idxSeg,
75 pSgBuf->paSegs[pSgBuf->idxSeg].cbSeg));
76#endif
77
78 /*
79 * Advance ...
80 */
81 if (cbSegLeft == cbData)
82 {
83 *pcbData = cbData;
84
85 /* ... to the next segment. */
86 unsigned idxSegNew = idxSeg + 1;
87 if (idxSegNew < pSgBuf->cSegs)
88 {
89 do
90 {
91 PCRTSGSEG const pNewSeg = &pSgBuf->paSegs[idxSegNew];
92 if (pNewSeg->cbSeg > 0)
93 {
94 pSgBuf->idxSeg = idxSegNew;
95 pSgBuf->cbSegLeft = pNewSeg->cbSeg;
96 pSgBuf->pvSegCur = pNewSeg->pvSeg;
97 return pvBuf;
98 }
99 /* Empty segment, skip it. */
100 idxSegNew++;
101 } while (idxSegNew < pSgBuf->cSegs);
102 }
103 pSgBuf->idxSeg = idxSegNew;
104 pSgBuf->cbSegLeft = 0;
105 pSgBuf->pvSegCur = NULL;
106 }
107 else
108 {
109 /* ... within the current segment. */
110 Assert(*pcbData == cbData);
111 pSgBuf->cbSegLeft = cbSegLeft - cbData;
112 pSgBuf->pvSegCur = (uint8_t *)pvBuf + cbData;
113 }
114
115 return pvBuf;
116 }
117
118 Assert(pSgBuf->cbSegLeft == 0);
119 *pcbData = 0;
120 return NULL;
121}
122
123
124RTDECL(void) RTSgBufInit(PRTSGBUF pSgBuf, PCRTSGSEG paSegs, size_t cSegs)
125{
126 AssertPtr(pSgBuf);
127 Assert( (cSegs > 0 && RT_VALID_PTR(paSegs))
128 || (!cSegs && !paSegs));
129 Assert(cSegs < (~(unsigned)0 >> 1));
130
131 pSgBuf->paSegs = paSegs;
132 pSgBuf->cSegs = (unsigned)cSegs;
133 pSgBuf->idxSeg = 0;
134 if (cSegs && paSegs)
135 {
136 pSgBuf->pvSegCur = paSegs[0].pvSeg;
137 pSgBuf->cbSegLeft = paSegs[0].cbSeg;
138 }
139 else
140 {
141 pSgBuf->pvSegCur = NULL;
142 pSgBuf->cbSegLeft = 0;
143 }
144}
145
146
147RTDECL(void) RTSgBufReset(PRTSGBUF pSgBuf)
148{
149 AssertPtrReturnVoid(pSgBuf);
150
151 pSgBuf->idxSeg = 0;
152 if (pSgBuf->cSegs)
153 {
154 pSgBuf->pvSegCur = pSgBuf->paSegs[0].pvSeg;
155 pSgBuf->cbSegLeft = pSgBuf->paSegs[0].cbSeg;
156 }
157 else
158 {
159 pSgBuf->pvSegCur = NULL;
160 pSgBuf->cbSegLeft = 0;
161 }
162}
163
164
165RTDECL(void) RTSgBufClone(PRTSGBUF pSgBufTo, PCRTSGBUF pSgBufFrom)
166{
167 AssertPtr(pSgBufTo);
168 AssertPtr(pSgBufFrom);
169
170 pSgBufTo->paSegs = pSgBufFrom->paSegs;
171 pSgBufTo->cSegs = pSgBufFrom->cSegs;
172 pSgBufTo->idxSeg = pSgBufFrom->idxSeg;
173 pSgBufTo->pvSegCur = pSgBufFrom->pvSegCur;
174 pSgBufTo->cbSegLeft = pSgBufFrom->cbSegLeft;
175}
176
177
178RTDECL(void *) RTSgBufGetNextSegment(PRTSGBUF pSgBuf, size_t *pcbSeg)
179{
180 AssertPtrReturn(pSgBuf, NULL);
181 AssertPtrReturn(pcbSeg, NULL);
182
183 if (!*pcbSeg)
184 *pcbSeg = pSgBuf->cbSegLeft;
185
186 return rtSgBufGet(pSgBuf, pcbSeg);
187}
188
189
190RTDECL(size_t) RTSgBufCopy(PRTSGBUF pSgBufDst, PRTSGBUF pSgBufSrc, size_t cbCopy)
191{
192 AssertPtrReturn(pSgBufDst, 0);
193 AssertPtrReturn(pSgBufSrc, 0);
194
195 size_t cbLeft = cbCopy;
196 while (cbLeft)
197 {
198 size_t cbThisCopy = RT_MIN(RT_MIN(pSgBufDst->cbSegLeft, cbLeft), pSgBufSrc->cbSegLeft);
199 if (!cbThisCopy)
200 break;
201
202 size_t cbTmp = cbThisCopy;
203 void *pvBufDst = rtSgBufGet(pSgBufDst, &cbTmp);
204 Assert(cbTmp == cbThisCopy);
205 void *pvBufSrc = rtSgBufGet(pSgBufSrc, &cbTmp);
206 Assert(cbTmp == cbThisCopy);
207
208 memcpy(pvBufDst, pvBufSrc, cbThisCopy);
209
210 cbLeft -= cbThisCopy;
211 }
212
213 return cbCopy - cbLeft;
214}
215
216
217RTDECL(int) RTSgBufCmp(PCRTSGBUF pSgBuf1, PCRTSGBUF pSgBuf2, size_t cbCmp)
218{
219 AssertPtrReturn(pSgBuf1, 0);
220 AssertPtrReturn(pSgBuf2, 0);
221
222 /* Set up the temporary buffers */
223 RTSGBUF SgBuf1;
224 RTSgBufClone(&SgBuf1, pSgBuf1);
225 RTSGBUF SgBuf2;
226 RTSgBufClone(&SgBuf2, pSgBuf2);
227
228 size_t cbLeft = cbCmp;
229 while (cbLeft)
230 {
231 size_t cbThisCmp = RT_MIN(RT_MIN(SgBuf1.cbSegLeft, cbLeft), SgBuf2.cbSegLeft);
232 if (!cbThisCmp)
233 break;
234
235 size_t cbTmp = cbThisCmp;
236 void *pvBuf1 = rtSgBufGet(&SgBuf1, &cbTmp);
237 Assert(cbTmp == cbThisCmp);
238 void *pvBuf2 = rtSgBufGet(&SgBuf2, &cbTmp);
239 Assert(cbTmp == cbThisCmp);
240
241 int iDiff = memcmp(pvBuf1, pvBuf2, cbThisCmp);
242 if (iDiff)
243 return iDiff;
244
245 cbLeft -= cbThisCmp;
246 }
247
248 return 0;
249}
250
251
252RTDECL(int) RTSgBufCmpEx(PRTSGBUF pSgBuf1, PRTSGBUF pSgBuf2, size_t cbCmp, size_t *poffDiff, bool fAdvance)
253{
254 AssertPtrReturn(pSgBuf1, 0);
255 AssertPtrReturn(pSgBuf2, 0);
256
257 RTSGBUF SgBuf1Tmp;
258 RTSGBUF SgBuf2Tmp;
259 PRTSGBUF pSgBuf1Tmp;
260 PRTSGBUF pSgBuf2Tmp;
261
262 if (!fAdvance)
263 {
264 /* Set up the temporary buffers */
265 RTSgBufClone(&SgBuf1Tmp, pSgBuf1);
266 RTSgBufClone(&SgBuf2Tmp, pSgBuf2);
267 pSgBuf1Tmp = &SgBuf1Tmp;
268 pSgBuf2Tmp = &SgBuf2Tmp;
269 }
270 else
271 {
272 pSgBuf1Tmp = pSgBuf1;
273 pSgBuf2Tmp = pSgBuf2;
274 }
275
276 size_t cbLeft = cbCmp;
277 size_t off = 0;
278 while (cbLeft)
279 {
280 size_t cbThisCmp = RT_MIN(RT_MIN(pSgBuf1Tmp->cbSegLeft, cbLeft), pSgBuf2Tmp->cbSegLeft);
281 if (!cbThisCmp)
282 break;
283
284 size_t cbTmp = cbThisCmp;
285 uint8_t *pbBuf1 = (uint8_t *)rtSgBufGet(pSgBuf1Tmp, &cbTmp);
286 Assert(cbTmp == cbThisCmp);
287 uint8_t *pbBuf2 = (uint8_t *)rtSgBufGet(pSgBuf2Tmp, &cbTmp);
288 Assert(cbTmp == cbThisCmp);
289
290 int iDiff = memcmp(pbBuf1, pbBuf2, cbThisCmp);
291 if (iDiff)
292 {
293 /* Locate the first byte that differs if the caller requested this. */
294 if (poffDiff)
295 {
296 while ( cbThisCmp-- > 0
297 && *pbBuf1 == *pbBuf2)
298 {
299 pbBuf1++;
300 pbBuf2++;
301 off++;
302 }
303
304 *poffDiff = off;
305 }
306 return iDiff;
307 }
308
309 cbLeft -= cbThisCmp;
310 off += cbThisCmp;
311 }
312
313 return 0;
314}
315
316
317RTDECL(size_t) RTSgBufSet(PRTSGBUF pSgBuf, uint8_t bFill, size_t cbToSet)
318{
319 AssertPtrReturn(pSgBuf, 0);
320
321 size_t cbLeft = cbToSet;
322
323 while (cbLeft)
324 {
325 size_t cbThisSet = cbLeft;
326 void *pvBuf = rtSgBufGet(pSgBuf, &cbThisSet);
327 if (!pvBuf)
328 break;
329
330 memset(pvBuf, bFill, cbThisSet);
331
332 cbLeft -= cbThisSet;
333 }
334
335 return cbToSet - cbLeft;
336}
337
338
339RTDECL(size_t) RTSgBufCopyToBuf(PRTSGBUF pSgBuf, void *pvBuf, size_t cbCopy)
340{
341 AssertPtrReturn(pSgBuf, 0);
342 AssertPtrReturn(pvBuf, 0);
343
344 size_t cbLeft = cbCopy;
345
346 while (cbLeft)
347 {
348 size_t cbThisCopy = cbLeft;
349 void * const pvSrc = rtSgBufGet(pSgBuf, &cbThisCopy);
350 if (!pvSrc)
351 break;
352
353 memcpy(pvBuf, pvSrc, cbThisCopy);
354
355 pvBuf = (void *)((uintptr_t)pvBuf + cbThisCopy);
356 cbLeft -= cbThisCopy;
357 }
358
359 return cbCopy - cbLeft;
360}
361
362
363RTDECL(size_t) RTSgBufCopyFromBuf(PRTSGBUF pSgBuf, const void *pvBuf, size_t cbCopy)
364{
365 AssertPtrReturn(pSgBuf, 0);
366 AssertPtrReturn(pvBuf, 0);
367
368 size_t cbLeft = cbCopy;
369
370 while (cbLeft)
371 {
372 size_t cbThisCopy = cbLeft;
373 void * const pvDst = rtSgBufGet(pSgBuf, &cbThisCopy);
374 if (!pvDst)
375 break;
376
377 memcpy(pvDst, pvBuf, cbThisCopy);
378
379 pvBuf = (const void *)((uintptr_t)pvBuf + cbThisCopy);
380 cbLeft -= cbThisCopy;
381 }
382
383 return cbCopy - cbLeft;
384}
385
386
387RTDECL(size_t) RTSgBufCopyToFn(PRTSGBUF pSgBuf, size_t cbCopy, PFNRTSGBUFCOPYTO pfnCopyTo, void *pvUser)
388{
389 AssertPtrReturn(pSgBuf, 0);
390 AssertPtrReturn(pfnCopyTo, 0);
391
392 size_t cbLeft = cbCopy;
393
394 while (cbLeft)
395 {
396 size_t cbThisCopy = cbLeft;
397 void * const pvSrc = rtSgBufGet(pSgBuf, &cbThisCopy);
398 if (!pvSrc)
399 break;
400
401 size_t cbThisCopied = pfnCopyTo(pSgBuf, pvSrc, cbThisCopy, pvUser);
402 cbLeft -= cbThisCopied;
403 if (cbThisCopied < cbThisCopy)
404 break;
405 }
406
407 return cbCopy - cbLeft;
408}
409
410
411RTDECL(size_t) RTSgBufCopyFromFn(PRTSGBUF pSgBuf, size_t cbCopy, PFNRTSGBUFCOPYFROM pfnCopyFrom, void *pvUser)
412{
413 AssertPtrReturn(pSgBuf, 0);
414 AssertPtrReturn(pfnCopyFrom, 0);
415
416 size_t cbLeft = cbCopy;
417
418 while (cbLeft)
419 {
420 size_t cbThisCopy = cbLeft;
421 void * const pvDst = rtSgBufGet(pSgBuf, &cbThisCopy);
422 if (!pvDst)
423 break;
424
425 size_t cbThisCopied = pfnCopyFrom(pSgBuf, pvDst, cbThisCopy, pvUser);
426 cbLeft -= cbThisCopied;
427 if (cbThisCopied < cbThisCopy)
428 break;
429 }
430
431 return cbCopy - cbLeft;
432}
433
434
435RTDECL(size_t) RTSgBufAdvance(PRTSGBUF pSgBuf, size_t cbAdvance)
436{
437 AssertPtrReturn(pSgBuf, 0);
438
439 size_t cbLeft = cbAdvance;
440
441 while ( cbLeft
442 || ( pSgBuf->cbSegLeft == 0
443 && pSgBuf->idxSeg > pSgBuf->cSegs))
444 {
445 size_t cbThisAdvance = cbLeft;
446 if (!rtSgBufGet(pSgBuf, &cbThisAdvance))
447 break;
448
449 cbLeft -= cbThisAdvance;
450 }
451
452 return cbAdvance - cbLeft;
453}
454
455
456RTDECL(size_t) RTSgBufSegArrayCreate(PRTSGBUF pSgBuf, PRTSGSEG paSeg, unsigned *pcSegs, size_t cbData)
457{
458 AssertPtrReturn(pSgBuf, 0);
459 AssertPtrReturn(pcSegs, 0);
460
461 unsigned cSegs = 0;
462 size_t cbRet = 0;
463
464 if (!paSeg)
465 {
466 if (pSgBuf->cbSegLeft > 0)
467 {
468 size_t idx = pSgBuf->idxSeg;
469
470 cbRet = RT_MIN(pSgBuf->cbSegLeft, cbData);
471 cSegs = cbRet != 0;
472 cbData -= cbRet;
473
474 while ( cbData
475 && idx < pSgBuf->cSegs - 1)
476 {
477 idx++;
478 size_t cbThisSeg = RT_MIN(pSgBuf->paSegs[idx].cbSeg, cbData);
479 if (cbThisSeg)
480 {
481 cbRet += cbThisSeg;
482 cbData -= cbThisSeg;
483 cSegs++;
484 }
485 }
486 }
487 }
488 else
489 {
490 while ( cbData
491 && cSegs < *pcSegs)
492 {
493 size_t cbThisSeg = cbData;
494 void * const pvSeg = rtSgBufGet(pSgBuf, &cbThisSeg);
495 if (!pvSeg)
496 break;
497
498 AssertMsg(cbThisSeg <= cbData, ("Impossible!\n"));
499
500 paSeg[cSegs].cbSeg = cbThisSeg;
501 paSeg[cSegs].pvSeg = pvSeg;
502 cSegs++;
503 cbData -= cbThisSeg;
504 cbRet += cbThisSeg;
505 }
506 }
507
508 *pcSegs = cSegs;
509
510 return cbRet;
511}
512
513
514RTDECL(bool) RTSgBufIsZero(PRTSGBUF pSgBuf, size_t cbCheck)
515{
516 RTSGBUF SgBufTmp;
517 RTSgBufClone(&SgBufTmp, pSgBuf);
518
519 bool fIsZero = true;
520 size_t cbLeft = cbCheck;
521 while (cbLeft)
522 {
523 size_t cbThisCheck = cbLeft;
524 void * const pvBuf = rtSgBufGet(&SgBufTmp, &cbThisCheck);
525 if (!pvBuf)
526 break;
527 if (cbThisCheck > 0)
528 {
529 fIsZero = ASMMemIsZero(pvBuf, cbThisCheck);
530 if (!fIsZero)
531 break;
532 cbLeft -= cbThisCheck;
533 }
534 }
535
536 return fIsZero;
537}
538
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