blob: 3574dbfd5d6505feb05133486d4bf0ef68af2585 [file] [log] [blame]
Glenn Kasten9b4c8052015-01-06 14:13:13 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "audio_utils_fifo"
19
Glenn Kasten9052f3b2016-07-08 16:24:41 -070020#include <errno.h>
Glenn Kasten0ab1d862016-06-20 12:04:56 -070021#include <limits.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080022#include <stdlib.h>
23#include <string.h>
Glenn Kasten9052f3b2016-07-08 16:24:41 -070024
25// FIXME futex portion is not supported on Mac, should use the Mac alternative
26#ifdef __linux__
27#include <linux/futex.h>
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070028#include <sys/syscall.h>
Glenn Kasten9052f3b2016-07-08 16:24:41 -070029#else
30#define FUTEX_WAIT 0
31#define FUTEX_WAIT_PRIVATE 0
32#define FUTEX_WAKE 0
33#define FUTEX_WAKE_PRIVATE 0
34#endif
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070035
Glenn Kasten9b4c8052015-01-06 14:13:13 -080036#include <audio_utils/fifo.h>
37#include <audio_utils/roundup.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080038#include <cutils/log.h>
Glenn Kasten9b4fe472016-06-13 09:34:57 -070039#include <utils/Errors.h>
Glenn Kasten9b4c8052015-01-06 14:13:13 -080040
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070041static int sys_futex(void *addr1, int op, int val1, struct timespec *timeout, void *addr2, int val3)
42{
Glenn Kasten9052f3b2016-07-08 16:24:41 -070043#ifdef __linux__
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070044 return syscall(SYS_futex, addr1, op, val1, timeout, addr2, val3);
Glenn Kasten9052f3b2016-07-08 16:24:41 -070045#else
Glenn Kasten86c4a6d2016-07-09 10:37:17 -070046 (void) addr1;
47 (void) op;
48 (void) val1;
49 (void) timeout;
50 (void) addr2;
51 (void) val3;
Glenn Kasten9052f3b2016-07-08 16:24:41 -070052 errno = ENOSYS;
53 return -1;
54#endif
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070055}
56
Glenn Kasten09acf782016-06-17 10:28:05 -070057audio_utils_fifo_base::audio_utils_fifo_base(uint32_t frameCount)
Glenn Kasten6d7ad762016-06-15 17:05:54 -070058 __attribute__((no_sanitize("integer"))) :
Glenn Kasten9b4fe472016-06-13 09:34:57 -070059 mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
Glenn Kasten09acf782016-06-17 10:28:05 -070060 mFudgeFactor(mFrameCountP2 - mFrameCount),
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070061 mIsPrivate(true),
Glenn Kasten6d7ad762016-06-15 17:05:54 -070062 mSharedRear(0), mThrottleFront(NULL)
Glenn Kasten9b4c8052015-01-06 14:13:13 -080063{
Glenn Kasten09acf782016-06-17 10:28:05 -070064 // actual upper bound on frameCount will depend on the frame size
Glenn Kasten0ab1d862016-06-20 12:04:56 -070065 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameCount > ((uint32_t) INT_MAX));
Glenn Kasten9b4c8052015-01-06 14:13:13 -080066}
67
Glenn Kasten09acf782016-06-17 10:28:05 -070068audio_utils_fifo_base::~audio_utils_fifo_base()
Glenn Kasten9b4c8052015-01-06 14:13:13 -080069{
70}
71
Glenn Kasten09acf782016-06-17 10:28:05 -070072uint32_t audio_utils_fifo_base::sum(uint32_t index, uint32_t increment)
Glenn Kasten9b4fe472016-06-13 09:34:57 -070073 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080074{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070075 if (mFudgeFactor) {
76 uint32_t mask = mFrameCountP2 - 1;
77 ALOG_ASSERT((index & mask) < mFrameCount);
78 ALOG_ASSERT(increment <= mFrameCountP2);
79 if ((index & mask) + increment >= mFrameCount) {
80 increment += mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080081 }
82 index += increment;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070083 ALOG_ASSERT((index & mask) < mFrameCount);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080084 return index;
85 } else {
86 return index + increment;
87 }
88}
89
Glenn Kasten09acf782016-06-17 10:28:05 -070090int32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -070091 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080092{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070093 uint32_t diff = rear - front;
94 if (mFudgeFactor) {
95 uint32_t mask = mFrameCountP2 - 1;
96 uint32_t rearMasked = rear & mask;
97 uint32_t frontMasked = front & mask;
98 if (rearMasked >= mFrameCount || frontMasked >= mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070099 return -EIO;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700100 }
101 uint32_t genDiff = (rear & ~mask) - (front & ~mask);
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800102 if (genDiff != 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700103 if (genDiff > mFrameCountP2) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700104 if (lost != NULL) {
105 // TODO provide a more accurate estimate
106 *lost = (genDiff / mFrameCountP2) * mFrameCount;
107 }
108 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700109 }
110 diff -= mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800111 }
112 }
113 // FIFO should not be overfull
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700114 if (diff > mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700115 if (lost != NULL) {
116 *lost = diff - mFrameCount;
117 }
118 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700119 }
120 return (int32_t) diff;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800121}
122
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700123////////////////////////////////////////////////////////////////////////////////
124
Glenn Kasten09acf782016-06-17 10:28:05 -0700125audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer)
126 __attribute__((no_sanitize("integer"))) :
127 audio_utils_fifo_base(frameCount), mFrameSize(frameSize), mBuffer(buffer)
128{
129 // maximum value of frameCount * frameSize is INT_MAX (2^31 - 1), not 2^31, because we need to
130 // be able to distinguish successful and error return values from read and write.
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700131 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL ||
132 frameCount > ((uint32_t) INT_MAX) / frameSize);
Glenn Kasten09acf782016-06-17 10:28:05 -0700133}
134
135audio_utils_fifo::~audio_utils_fifo()
136{
137}
138
139////////////////////////////////////////////////////////////////////////////////
140
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700141audio_utils_fifo_provider::audio_utils_fifo_provider() :
142 mObtained(0)
143{
144}
145
146audio_utils_fifo_provider::~audio_utils_fifo_provider()
147{
148}
149
150////////////////////////////////////////////////////////////////////////////////
151
152audio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700153 audio_utils_fifo_provider(), mFifo(fifo), mLocalRear(0),
154 mLowLevelArm(fifo.mFrameCount), mHighLevelTrigger(0), mArmed(false),
155 mEffectiveFrames(fifo.mFrameCount)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700156{
157}
158
159audio_utils_fifo_writer::~audio_utils_fifo_writer()
160{
161}
162
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700163ssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count, struct timespec *timeout)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700164 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800165{
Glenn Kasten547a9922016-06-15 13:07:31 -0700166 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700167 ssize_t availToWrite = obtain(iovec, count, timeout);
Glenn Kasten547a9922016-06-15 13:07:31 -0700168 if (availToWrite > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700169 memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
170 iovec[0].mLength * mFifo.mFrameSize);
171 if (iovec[1].mLength > 0) {
172 memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
173 (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
174 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700175 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700176 release(availToWrite);
Glenn Kasten547a9922016-06-15 13:07:31 -0700177 }
178 return availToWrite;
179}
180
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700181ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count,
182 struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700183 __attribute__((no_sanitize("integer")))
184{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700185 size_t availToWrite;
186 if (mFifo.mThrottleFront != NULL) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700187 uint32_t front;
188 for (;;) {
189 front = (uint32_t) atomic_load_explicit(mFifo.mThrottleFront,
190 std::memory_order_acquire);
191 int32_t filled = mFifo.diff(mLocalRear, front, NULL /*lost*/);
192 if (filled < 0) {
193 mObtained = 0;
194 return (ssize_t) filled;
195 }
196 availToWrite = mEffectiveFrames > (uint32_t) filled ?
197 mEffectiveFrames - (uint32_t) filled : 0;
198 // TODO pull out "count == 0"
199 if (count == 0 || availToWrite > 0 || timeout == NULL ||
200 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
201 break;
202 }
203 int err = sys_futex(mFifo.mThrottleFront,
204 mFifo.mIsPrivate ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, front, timeout, NULL, 0);
205 if (err < 0) {
206 switch (errno) {
207 case EWOULDBLOCK:
208 case EINTR:
209 case ETIMEDOUT:
210 break;
211 default:
212 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
213 break;
214 }
215 }
216 timeout = NULL;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700217 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700218 } else {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700219 availToWrite = mEffectiveFrames;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700220 }
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800221 if (availToWrite > count) {
222 availToWrite = count;
223 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700224 uint32_t rearMasked = mLocalRear & (mFifo.mFrameCountP2 - 1);
225 size_t part1 = mFifo.mFrameCount - rearMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800226 if (part1 > availToWrite) {
227 part1 = availToWrite;
228 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700229 size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
Glenn Kasten169f3a22016-06-17 10:43:34 -0700230 iovec[0].mOffset = rearMasked;
231 iovec[0].mLength = part1;
232 iovec[1].mOffset = 0;
233 iovec[1].mLength = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700234 mObtained = availToWrite;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800235 return availToWrite;
236}
237
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700238void audio_utils_fifo_writer::release(size_t count)
239 __attribute__((no_sanitize("integer")))
Glenn Kasten547a9922016-06-15 13:07:31 -0700240{
241 if (count > 0) {
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700242 LOG_ALWAYS_FATAL_IF(count > mObtained);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700243 if (mFifo.mThrottleFront != NULL) {
244 uint32_t front = (uint32_t) atomic_load_explicit(mFifo.mThrottleFront,
245 std::memory_order_acquire);
246 int32_t filled = mFifo.diff(mLocalRear, front, NULL /*lost*/);
247 mLocalRear = mFifo.sum(mLocalRear, count);
248 atomic_store_explicit(&mFifo.mSharedRear, (uint_fast32_t) mLocalRear,
249 std::memory_order_release);
250 if (filled >= 0) {
251 if (filled + count <= mLowLevelArm) {
252 mArmed = true;
253 }
254 if (mArmed && filled + count >= mHighLevelTrigger) {
255 int err = sys_futex(&mFifo.mSharedRear,
256 mFifo.mIsPrivate ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
257 INT_MAX /*waiters*/, NULL, NULL, 0);
258 // err is number of processes woken up
259 if (err < 0) {
260 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d", __func__, err, errno);
261 }
262 mArmed = false;
263 }
264 }
265 } else {
266 mLocalRear = mFifo.sum(mLocalRear, count);
267 atomic_store_explicit(&mFifo.mSharedRear, (uint_fast32_t) mLocalRear,
268 std::memory_order_release);
269 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700270 mObtained -= count;
Glenn Kasten547a9922016-06-15 13:07:31 -0700271 }
272}
273
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700274////////////////////////////////////////////////////////////////////////////////
275
276audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter) :
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700277 audio_utils_fifo_provider(), mFifo(fifo), mLocalFront(0), mSharedFront(0),
278 mHighLevelArm(0), mLowLevelTrigger(mFifo.mFrameCount), mArmed(false)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700279{
280 if (throttlesWriter) {
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700281 LOG_ALWAYS_FATAL_IF(fifo.mThrottleFront != NULL);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700282 fifo.mThrottleFront = &mSharedFront;
283 }
284}
285
286audio_utils_fifo_reader::~audio_utils_fifo_reader()
287{
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700288 // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
Glenn Kastena7a0e042016-06-17 10:53:09 -0700289 if (mFifo.mThrottleFront == &mSharedFront) {
290 mFifo.mThrottleFront = NULL;
291 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700292}
293
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700294ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, struct timespec *timeout,
295 size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700296 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800297{
Glenn Kasten547a9922016-06-15 13:07:31 -0700298 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700299 ssize_t availToRead = obtain(iovec, count, timeout, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700300 if (availToRead > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700301 memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
302 iovec[0].mLength * mFifo.mFrameSize);
303 if (iovec[1].mLength > 0) {
304 memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
305 (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
306 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700307 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700308 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700309 }
310 return availToRead;
311}
312
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700313ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
314 struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700315 __attribute__((no_sanitize("integer")))
316{
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700317 return obtain(iovec, count, timeout, NULL);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700318}
319
320void audio_utils_fifo_reader::release(size_t count)
321 __attribute__((no_sanitize("integer")))
322{
323 if (count > 0) {
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700324 LOG_ALWAYS_FATAL_IF(count > mObtained);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700325 if (mFifo.mThrottleFront == &mSharedFront) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700326 uint32_t rear = (uint32_t) atomic_load_explicit(&mFifo.mSharedRear,
327 std::memory_order_acquire);
328 int32_t filled = mFifo.diff(rear, mLocalFront, NULL /*lost*/);
329 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700330 atomic_store_explicit(&mSharedFront, (uint_fast32_t) mLocalFront,
331 std::memory_order_release);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700332 if (filled >= 0) {
333 if (filled - count >= mHighLevelArm) {
334 mArmed = true;
335 }
336 if (mArmed && filled - count <= mLowLevelTrigger) {
337 int err = sys_futex(&mFifo.mSharedRear,
338 mFifo.mIsPrivate ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
339 1 /*waiters*/, NULL, NULL, 0);
340 // err is number of processes woken up
341 if (err < 0 || err > 1) {
342 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d", __func__, err, errno);
343 }
344 mArmed = false;
345 }
346 }
347 } else {
348 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700349 }
350 mObtained -= count;
351 }
352}
353
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700354ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
355 struct timespec *timeout, size_t *lost)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700356 __attribute__((no_sanitize("integer")))
357{
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700358 uint32_t rear;
359 for (;;) {
360 rear = (uint32_t) atomic_load_explicit(&mFifo.mSharedRear,
361 std::memory_order_acquire);
362 // TODO pull out "count == 0"
363 if (count == 0 || rear != mLocalFront || timeout == NULL ||
364 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
365 break;
366 }
367 int err = sys_futex(&mFifo.mSharedRear, mFifo.mIsPrivate ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT,
368 rear, timeout, NULL, 0);
369 if (err < 0) {
370 switch (errno) {
371 case EWOULDBLOCK:
372 case EINTR:
373 case ETIMEDOUT:
374 break;
375 default:
376 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
377 break;
378 }
379 }
380 timeout = NULL;
381 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700382 int32_t filled = mFifo.diff(rear, mLocalFront, lost);
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700383 if (filled < 0) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700384 if (filled == -EOVERFLOW) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700385 mLocalFront = rear;
386 }
387 mObtained = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700388 return (ssize_t) filled;
389 }
390 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800391 if (availToRead > count) {
392 availToRead = count;
393 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700394 uint32_t frontMasked = mLocalFront & (mFifo.mFrameCountP2 - 1);
395 size_t part1 = mFifo.mFrameCount - frontMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800396 if (part1 > availToRead) {
397 part1 = availToRead;
398 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700399 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
Glenn Kasten169f3a22016-06-17 10:43:34 -0700400 iovec[0].mOffset = frontMasked;
401 iovec[0].mLength = part1;
402 iovec[1].mOffset = 0;
403 iovec[1].mLength = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700404 mObtained = availToRead;
Glenn Kasten547a9922016-06-15 13:07:31 -0700405 return availToRead;
406}