VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/fileio-sg-at-posix.cpp@ 77635

Last change on this file since 77635 was 77635, checked in by vboxsync, 6 years ago

IPRT: Adding RTFileSgRead and RTFileSgWrite (for FsPerf). [build fixes] bugref:9172

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.0 KB
Line 
1/* $Id: fileio-sg-at-posix.cpp 77635 2019-03-10 14:51:26Z vboxsync $ */
2/** @file
3 * IPRT - File I/O, RTFileSgReadAt & RTFileSgWriteAt, posixy.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31/*
32 * Determin whether we've got preadv and pwritev.
33 */
34#include <iprt/cdefs.h>
35#ifdef RT_OS_LINUX
36/* Linux has these since glibc 2.10 and Linux 2.6.30: */
37# include <features.h>
38# ifdef __GLIBC_PREREQ
39# if __GLIBC_PREREQ(2,10)
40# define HAVE_PREADV_AND_PWRITEV 1
41#else
42# endif
43# endif
44
45#elif defined(RT_OS_FREEBSD)
46/* FreeBSD has these since 6.0: */
47# include <osreldate.h>
48# ifdef __FreeBSD_version
49# if __FreeBSD_version >= 600000
50# define HAVE_PREADV_AND_PWRITEV 1
51# endif
52# endif
53
54#endif
55
56#ifndef HAVE_PREADV_AND_PWRITEV
57
58# include "../../generic/fileio-sg-at-generic.cpp"
59
60#else /* HAVE_PREADV_AND_PWRITEV - rest of the file */
61
62# include <errno.h>
63# include <sys/types.h>
64# include <sys/uio.h>
65# include <unistd.h>
66# include <limits.h>
67# if defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD) || defined(RT_OS_NETBSD) || defined(RT_OS_OPENBSD)
68# include <sys/syslimits.h>
69# endif
70
71# include "internal/iprt.h"
72# include <iprt/file.h>
73
74# include <iprt/assert.h>
75# include <iprt/err.h>
76# include <iprt/log.h>
77
78# ifndef UIO_MAXIOV
79# ifdef IOV_MAX
80# define UIO_MAXIOV IOV_MAX
81# else
82# error "UIO_MAXIOV and IOV_MAX are undefined"
83# endif
84# endif
85
86
87/* These assumptions simplifies things a lot here. */
88AssertCompileMembersSameSizeAndOffset(struct iovec, iov_base, RTSGSEG, pvSeg);
89AssertCompileMembersSameSizeAndOffset(struct iovec, iov_len, RTSGSEG, cbSeg);
90
91
92RTDECL(int) RTFileSgReadAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToRead, size_t *pcbRead)
93{
94 /*
95 * Make sure we set pcbRead.
96 */
97 if (pcbRead)
98 *pcbRead = 0;
99
100 /*
101 * Special case: Zero read == seek.
102 */
103 if (cbToRead == 0)
104 return RTFileSeek(hFile, off, RTFILE_SEEK_BEGIN, NULL);
105
106 /*
107 * We can use the segment array directly if we're at the start of the
108 * current S/G segment and cbToRead matches the remainder exactly.
109 */
110 size_t cbTotalRead = 0;
111
112 size_t const cbSgBufLeft = RTSgBufCalcLengthLeft(pSgBuf);
113 AssertMsgReturn(cbSgBufLeft >= cbToRead, ("%#zx vs %#zx\n", cbSgBufLeft, cbToRead), VERR_INVALID_PARAMETER);
114
115 if (cbToRead == cbSgBufLeft)
116 while (RTSgBufIsAtStartOfSegment(pSgBuf))
117 {
118 size_t const cSegsLeft = pSgBuf->cSegs - pSgBuf->idxSeg;
119 ssize_t cbThisRead = preadv(RTFileToNative(hFile), (const struct iovec *)&pSgBuf->paSegs[pSgBuf->idxSeg],
120 RT_MIN(cSegsLeft, UIO_MAXIOV), off);
121 if (cbThisRead >= 0)
122 {
123 AssertStmt((size_t)cbThisRead <= cbToRead, cbThisRead = cbToRead);
124
125 RTSgBufAdvance(pSgBuf, cbThisRead);
126 cbTotalRead += cbThisRead;
127 cbToRead -= cbThisRead;
128 if (cbToRead == 0)
129 {
130 if (pcbRead)
131 *pcbRead = cbTotalRead;
132 return VINF_SUCCESS;
133 }
134
135 if ( pcbRead
136 && ( cSegsLeft <= UIO_MAXIOV
137 || cbThisRead == 0 /* typically EOF */ ))
138 {
139 *pcbRead = cbTotalRead;
140 return VINF_SUCCESS;
141 }
142 if (cbThisRead == 0)
143 return VERR_EOF;
144
145 off += cbThisRead;
146 }
147 else if (cbTotalRead > 0 && pcbRead)
148 {
149 *pcbRead = cbTotalRead;
150 return VINF_SUCCESS;
151 }
152 else
153 return RTErrConvertFromErrno(errno);
154 }
155
156 /*
157 * Unaligned start or not reading the whole buffer. For reasons of
158 * simplicity, we work the input segment by segment like the generic code.
159 */
160 int rc = VINF_SUCCESS;
161 while (cbToRead > 0)
162 {
163 size_t cbSeg;
164 void *pvSeg = RTSgBufGetCurrentSegment(pSgBuf, cbToRead, &cbSeg);
165 size_t cbThisRead = cbSeg;
166 rc = RTFileReadAt(hFile, off, pvSeg, cbSeg, pcbRead ? &cbThisRead : NULL);
167 if (RT_SUCCESS(rc))
168 {
169 RTSgBufAdvance(pSgBuf, cbThisRead);
170 cbTotalRead += cbThisRead;
171 }
172 else
173 break;
174 if ((size_t)cbThisRead < cbSeg)
175 {
176 AssertStmt(pcbRead, rc = VERR_INTERNAL_ERROR_2);
177 break;
178 }
179
180 Assert(cbSeg == cbThisRead);
181 cbToRead -= cbSeg;
182 off += cbSeg;
183 }
184 if (pcbRead)
185 *pcbRead = cbTotalRead;
186 return rc;
187}
188
189
190RTDECL(int) RTFileSgWriteAt(RTFILE hFile, RTFOFF off, PRTSGBUF pSgBuf, size_t cbToWrite, size_t *pcbWritten)
191{
192 /*
193 * Make sure we set pcbWritten.
194 */
195 if (pcbWritten)
196 *pcbWritten = 0;
197
198 /*
199 * Special case: Zero write == seek.
200 */
201 if (cbToWrite == 0)
202 return RTFileSeek(hFile, off, RTFILE_SEEK_BEGIN, NULL);
203
204 /*
205 * We can use the segment array directly if we're at the start of the
206 * current S/G segment and cbToWrite matches the remainder exactly.
207 */
208 size_t cbTotalWritten = 0;
209
210 size_t const cbSgBufLeft = RTSgBufCalcLengthLeft(pSgBuf);
211 AssertMsgReturn(cbSgBufLeft >= cbToWrite, ("%#zx vs %#zx\n", cbSgBufLeft, cbToWrite), VERR_INVALID_PARAMETER);
212
213 if (cbToWrite == cbSgBufLeft)
214 while (RTSgBufIsAtStartOfSegment(pSgBuf))
215 {
216 size_t const cSegsLeft = pSgBuf->cSegs - pSgBuf->idxSeg;
217 ssize_t cbThisWritten = pwritev(RTFileToNative(hFile), (const struct iovec *)&pSgBuf->paSegs[pSgBuf->idxSeg],
218 RT_MIN(cSegsLeft, UIO_MAXIOV), off);
219 if (cbThisWritten >= 0)
220 {
221 AssertStmt((size_t)cbThisWritten <= cbToWrite, cbThisWritten = cbToWrite);
222
223 RTSgBufAdvance(pSgBuf, cbThisWritten);
224 cbTotalWritten += cbThisWritten;
225 cbToWrite -= cbThisWritten;
226 if (cbToWrite == 0)
227 {
228 if (pcbWritten)
229 *pcbWritten = cbTotalWritten;
230 return VINF_SUCCESS;
231 }
232
233 if ( pcbWritten
234 && ( cSegsLeft <= UIO_MAXIOV
235 || cbThisWritten == 0 /* non-file, full buffer/whatever */ ))
236 {
237 *pcbWritten = cbTotalWritten;
238 return VINF_SUCCESS;
239 }
240 if (cbThisWritten == 0)
241 return VERR_TRY_AGAIN;
242
243 off += cbThisWritten;
244 }
245 else if (cbTotalWritten > 0 && pcbWritten)
246 {
247 *pcbWritten = cbTotalWritten;
248 return VINF_SUCCESS;
249 }
250 else
251 return RTErrConvertFromErrno(errno);
252 }
253
254 /*
255 * Unaligned start or not writing the whole buffer. For reasons of
256 * simplicity, we work the input segment by segment like the generic code.
257 */
258 int rc = VINF_SUCCESS;
259 while (cbToWrite > 0)
260 {
261 size_t cbSeg;
262 void *pvSeg = RTSgBufGetCurrentSegment(pSgBuf, cbToWrite, &cbSeg);
263 size_t cbThisWritten = cbSeg;
264 rc = RTFileWriteAt(hFile, off, pvSeg, cbSeg, pcbWritten ? &cbThisWritten : NULL);
265 if (RT_SUCCESS(rc))
266 {
267 RTSgBufAdvance(pSgBuf, cbThisWritten);
268 cbTotalWritten += cbThisWritten;
269 }
270 else
271 break;
272 if ((size_t)cbThisWritten < cbSeg)
273 {
274 AssertStmt(pcbWritten, rc = VERR_INTERNAL_ERROR_2);
275 break;
276 }
277
278 Assert(cbSeg == cbThisWritten);
279 cbToWrite -= cbSeg;
280 off += cbSeg;
281 }
282 if (pcbWritten)
283 *pcbWritten = cbTotalWritten;
284 return rc;
285}
286
287#endif /* HAVE_PREADV_AND_PWRITEV */
288
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