blob: b5fe4b391e1ef880d491b3fe327ce9fffd865c2e [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
46 errno = ENOSYS;
47 return -1;
48#endif
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070049}
50
Glenn Kasten09acf782016-06-17 10:28:05 -070051audio_utils_fifo_base::audio_utils_fifo_base(uint32_t frameCount)
Glenn Kasten6d7ad762016-06-15 17:05:54 -070052 __attribute__((no_sanitize("integer"))) :
Glenn Kasten9b4fe472016-06-13 09:34:57 -070053 mFrameCount(frameCount), mFrameCountP2(roundup(frameCount)),
Glenn Kasten09acf782016-06-17 10:28:05 -070054 mFudgeFactor(mFrameCountP2 - mFrameCount),
Glenn Kasten3ddacbb2016-06-20 14:41:03 -070055 mIsPrivate(true),
Glenn Kasten6d7ad762016-06-15 17:05:54 -070056 mSharedRear(0), mThrottleFront(NULL)
Glenn Kasten9b4c8052015-01-06 14:13:13 -080057{
Glenn Kasten09acf782016-06-17 10:28:05 -070058 // actual upper bound on frameCount will depend on the frame size
Glenn Kasten0ab1d862016-06-20 12:04:56 -070059 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameCount > ((uint32_t) INT_MAX));
Glenn Kasten9b4c8052015-01-06 14:13:13 -080060}
61
Glenn Kasten09acf782016-06-17 10:28:05 -070062audio_utils_fifo_base::~audio_utils_fifo_base()
Glenn Kasten9b4c8052015-01-06 14:13:13 -080063{
64}
65
Glenn Kasten09acf782016-06-17 10:28:05 -070066uint32_t audio_utils_fifo_base::sum(uint32_t index, uint32_t increment)
Glenn Kasten9b4fe472016-06-13 09:34:57 -070067 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080068{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070069 if (mFudgeFactor) {
70 uint32_t mask = mFrameCountP2 - 1;
71 ALOG_ASSERT((index & mask) < mFrameCount);
72 ALOG_ASSERT(increment <= mFrameCountP2);
73 if ((index & mask) + increment >= mFrameCount) {
74 increment += mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -080075 }
76 index += increment;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070077 ALOG_ASSERT((index & mask) < mFrameCount);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080078 return index;
79 } else {
80 return index + increment;
81 }
82}
83
Glenn Kasten09acf782016-06-17 10:28:05 -070084int32_t audio_utils_fifo_base::diff(uint32_t rear, uint32_t front, size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -070085 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -080086{
Glenn Kasten9b4fe472016-06-13 09:34:57 -070087 uint32_t diff = rear - front;
88 if (mFudgeFactor) {
89 uint32_t mask = mFrameCountP2 - 1;
90 uint32_t rearMasked = rear & mask;
91 uint32_t frontMasked = front & mask;
92 if (rearMasked >= mFrameCount || frontMasked >= mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070093 return -EIO;
Glenn Kasten9b4fe472016-06-13 09:34:57 -070094 }
95 uint32_t genDiff = (rear & ~mask) - (front & ~mask);
Glenn Kasten9b4c8052015-01-06 14:13:13 -080096 if (genDiff != 0) {
Glenn Kasten9b4fe472016-06-13 09:34:57 -070097 if (genDiff > mFrameCountP2) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -070098 if (lost != NULL) {
99 // TODO provide a more accurate estimate
100 *lost = (genDiff / mFrameCountP2) * mFrameCount;
101 }
102 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700103 }
104 diff -= mFudgeFactor;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800105 }
106 }
107 // FIFO should not be overfull
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700108 if (diff > mFrameCount) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700109 if (lost != NULL) {
110 *lost = diff - mFrameCount;
111 }
112 return -EOVERFLOW;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700113 }
114 return (int32_t) diff;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800115}
116
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700117////////////////////////////////////////////////////////////////////////////////
118
Glenn Kasten09acf782016-06-17 10:28:05 -0700119audio_utils_fifo::audio_utils_fifo(uint32_t frameCount, uint32_t frameSize, void *buffer)
120 __attribute__((no_sanitize("integer"))) :
121 audio_utils_fifo_base(frameCount), mFrameSize(frameSize), mBuffer(buffer)
122{
123 // maximum value of frameCount * frameSize is INT_MAX (2^31 - 1), not 2^31, because we need to
124 // be able to distinguish successful and error return values from read and write.
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700125 LOG_ALWAYS_FATAL_IF(frameCount == 0 || frameSize == 0 || buffer == NULL ||
126 frameCount > ((uint32_t) INT_MAX) / frameSize);
Glenn Kasten09acf782016-06-17 10:28:05 -0700127}
128
129audio_utils_fifo::~audio_utils_fifo()
130{
131}
132
133////////////////////////////////////////////////////////////////////////////////
134
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700135audio_utils_fifo_provider::audio_utils_fifo_provider() :
136 mObtained(0)
137{
138}
139
140audio_utils_fifo_provider::~audio_utils_fifo_provider()
141{
142}
143
144////////////////////////////////////////////////////////////////////////////////
145
146audio_utils_fifo_writer::audio_utils_fifo_writer(audio_utils_fifo& fifo) :
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700147 audio_utils_fifo_provider(), mFifo(fifo), mLocalRear(0),
148 mLowLevelArm(fifo.mFrameCount), mHighLevelTrigger(0), mArmed(false),
149 mEffectiveFrames(fifo.mFrameCount)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700150{
151}
152
153audio_utils_fifo_writer::~audio_utils_fifo_writer()
154{
155}
156
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700157ssize_t audio_utils_fifo_writer::write(const void *buffer, size_t count, struct timespec *timeout)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700158 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800159{
Glenn Kasten547a9922016-06-15 13:07:31 -0700160 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700161 ssize_t availToWrite = obtain(iovec, count, timeout);
Glenn Kasten547a9922016-06-15 13:07:31 -0700162 if (availToWrite > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700163 memcpy((char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize, buffer,
164 iovec[0].mLength * mFifo.mFrameSize);
165 if (iovec[1].mLength > 0) {
166 memcpy((char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
167 (char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
168 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700169 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700170 release(availToWrite);
Glenn Kasten547a9922016-06-15 13:07:31 -0700171 }
172 return availToWrite;
173}
174
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700175ssize_t audio_utils_fifo_writer::obtain(audio_utils_iovec iovec[2], size_t count,
176 struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700177 __attribute__((no_sanitize("integer")))
178{
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700179 size_t availToWrite;
180 if (mFifo.mThrottleFront != NULL) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700181 uint32_t front;
182 for (;;) {
183 front = (uint32_t) atomic_load_explicit(mFifo.mThrottleFront,
184 std::memory_order_acquire);
185 int32_t filled = mFifo.diff(mLocalRear, front, NULL /*lost*/);
186 if (filled < 0) {
187 mObtained = 0;
188 return (ssize_t) filled;
189 }
190 availToWrite = mEffectiveFrames > (uint32_t) filled ?
191 mEffectiveFrames - (uint32_t) filled : 0;
192 // TODO pull out "count == 0"
193 if (count == 0 || availToWrite > 0 || timeout == NULL ||
194 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
195 break;
196 }
197 int err = sys_futex(mFifo.mThrottleFront,
198 mFifo.mIsPrivate ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, front, timeout, NULL, 0);
199 if (err < 0) {
200 switch (errno) {
201 case EWOULDBLOCK:
202 case EINTR:
203 case ETIMEDOUT:
204 break;
205 default:
206 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
207 break;
208 }
209 }
210 timeout = NULL;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700211 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700212 } else {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700213 availToWrite = mEffectiveFrames;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700214 }
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800215 if (availToWrite > count) {
216 availToWrite = count;
217 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700218 uint32_t rearMasked = mLocalRear & (mFifo.mFrameCountP2 - 1);
219 size_t part1 = mFifo.mFrameCount - rearMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800220 if (part1 > availToWrite) {
221 part1 = availToWrite;
222 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700223 size_t part2 = part1 > 0 ? availToWrite - part1 : 0;
Glenn Kasten169f3a22016-06-17 10:43:34 -0700224 iovec[0].mOffset = rearMasked;
225 iovec[0].mLength = part1;
226 iovec[1].mOffset = 0;
227 iovec[1].mLength = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700228 mObtained = availToWrite;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800229 return availToWrite;
230}
231
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700232void audio_utils_fifo_writer::release(size_t count)
233 __attribute__((no_sanitize("integer")))
Glenn Kasten547a9922016-06-15 13:07:31 -0700234{
235 if (count > 0) {
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700236 LOG_ALWAYS_FATAL_IF(count > mObtained);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700237 if (mFifo.mThrottleFront != NULL) {
238 uint32_t front = (uint32_t) atomic_load_explicit(mFifo.mThrottleFront,
239 std::memory_order_acquire);
240 int32_t filled = mFifo.diff(mLocalRear, front, NULL /*lost*/);
241 mLocalRear = mFifo.sum(mLocalRear, count);
242 atomic_store_explicit(&mFifo.mSharedRear, (uint_fast32_t) mLocalRear,
243 std::memory_order_release);
244 if (filled >= 0) {
245 if (filled + count <= mLowLevelArm) {
246 mArmed = true;
247 }
248 if (mArmed && filled + count >= mHighLevelTrigger) {
249 int err = sys_futex(&mFifo.mSharedRear,
250 mFifo.mIsPrivate ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
251 INT_MAX /*waiters*/, NULL, NULL, 0);
252 // err is number of processes woken up
253 if (err < 0) {
254 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d", __func__, err, errno);
255 }
256 mArmed = false;
257 }
258 }
259 } else {
260 mLocalRear = mFifo.sum(mLocalRear, count);
261 atomic_store_explicit(&mFifo.mSharedRear, (uint_fast32_t) mLocalRear,
262 std::memory_order_release);
263 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700264 mObtained -= count;
Glenn Kasten547a9922016-06-15 13:07:31 -0700265 }
266}
267
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700268////////////////////////////////////////////////////////////////////////////////
269
270audio_utils_fifo_reader::audio_utils_fifo_reader(audio_utils_fifo& fifo, bool throttlesWriter) :
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700271 audio_utils_fifo_provider(), mFifo(fifo), mLocalFront(0), mSharedFront(0),
272 mHighLevelArm(0), mLowLevelTrigger(mFifo.mFrameCount), mArmed(false)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700273{
274 if (throttlesWriter) {
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700275 LOG_ALWAYS_FATAL_IF(fifo.mThrottleFront != NULL);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700276 fifo.mThrottleFront = &mSharedFront;
277 }
278}
279
280audio_utils_fifo_reader::~audio_utils_fifo_reader()
281{
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700282 // TODO Need a way to pass throttle capability to the another reader, should one reader exit.
Glenn Kastena7a0e042016-06-17 10:53:09 -0700283 if (mFifo.mThrottleFront == &mSharedFront) {
284 mFifo.mThrottleFront = NULL;
285 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700286}
287
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700288ssize_t audio_utils_fifo_reader::read(void *buffer, size_t count, struct timespec *timeout,
289 size_t *lost)
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700290 __attribute__((no_sanitize("integer")))
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800291{
Glenn Kasten547a9922016-06-15 13:07:31 -0700292 audio_utils_iovec iovec[2];
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700293 ssize_t availToRead = obtain(iovec, count, timeout, lost);
Glenn Kasten547a9922016-06-15 13:07:31 -0700294 if (availToRead > 0) {
Glenn Kasten169f3a22016-06-17 10:43:34 -0700295 memcpy(buffer, (char *) mFifo.mBuffer + iovec[0].mOffset * mFifo.mFrameSize,
296 iovec[0].mLength * mFifo.mFrameSize);
297 if (iovec[1].mLength > 0) {
298 memcpy((char *) buffer + (iovec[0].mLength * mFifo.mFrameSize),
299 (char *) mFifo.mBuffer + iovec[1].mOffset * mFifo.mFrameSize,
300 iovec[1].mLength * mFifo.mFrameSize);
Glenn Kasten547a9922016-06-15 13:07:31 -0700301 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700302 release(availToRead);
Glenn Kasten547a9922016-06-15 13:07:31 -0700303 }
304 return availToRead;
305}
306
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700307ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
308 struct timespec *timeout)
Glenn Kasten547a9922016-06-15 13:07:31 -0700309 __attribute__((no_sanitize("integer")))
310{
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700311 return obtain(iovec, count, timeout, NULL);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700312}
313
314void audio_utils_fifo_reader::release(size_t count)
315 __attribute__((no_sanitize("integer")))
316{
317 if (count > 0) {
Glenn Kasten0ab1d862016-06-20 12:04:56 -0700318 LOG_ALWAYS_FATAL_IF(count > mObtained);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700319 if (mFifo.mThrottleFront == &mSharedFront) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700320 uint32_t rear = (uint32_t) atomic_load_explicit(&mFifo.mSharedRear,
321 std::memory_order_acquire);
322 int32_t filled = mFifo.diff(rear, mLocalFront, NULL /*lost*/);
323 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700324 atomic_store_explicit(&mSharedFront, (uint_fast32_t) mLocalFront,
325 std::memory_order_release);
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700326 if (filled >= 0) {
327 if (filled - count >= mHighLevelArm) {
328 mArmed = true;
329 }
330 if (mArmed && filled - count <= mLowLevelTrigger) {
331 int err = sys_futex(&mFifo.mSharedRear,
332 mFifo.mIsPrivate ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
333 1 /*waiters*/, NULL, NULL, 0);
334 // err is number of processes woken up
335 if (err < 0 || err > 1) {
336 LOG_ALWAYS_FATAL("%s: unexpected err=%d errno=%d", __func__, err, errno);
337 }
338 mArmed = false;
339 }
340 }
341 } else {
342 mLocalFront = mFifo.sum(mLocalFront, count);
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700343 }
344 mObtained -= count;
345 }
346}
347
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700348ssize_t audio_utils_fifo_reader::obtain(audio_utils_iovec iovec[2], size_t count,
349 struct timespec *timeout, size_t *lost)
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700350 __attribute__((no_sanitize("integer")))
351{
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700352 uint32_t rear;
353 for (;;) {
354 rear = (uint32_t) atomic_load_explicit(&mFifo.mSharedRear,
355 std::memory_order_acquire);
356 // TODO pull out "count == 0"
357 if (count == 0 || rear != mLocalFront || timeout == NULL ||
358 (timeout->tv_sec == 0 && timeout->tv_nsec == 0)) {
359 break;
360 }
361 int err = sys_futex(&mFifo.mSharedRear, mFifo.mIsPrivate ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT,
362 rear, timeout, NULL, 0);
363 if (err < 0) {
364 switch (errno) {
365 case EWOULDBLOCK:
366 case EINTR:
367 case ETIMEDOUT:
368 break;
369 default:
370 LOG_ALWAYS_FATAL("unexpected err=%d errno=%d", err, errno);
371 break;
372 }
373 }
374 timeout = NULL;
375 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700376 int32_t filled = mFifo.diff(rear, mLocalFront, lost);
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700377 if (filled < 0) {
Glenn Kasten3ddacbb2016-06-20 14:41:03 -0700378 if (filled == -EOVERFLOW) {
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700379 mLocalFront = rear;
380 }
381 mObtained = 0;
Glenn Kasten9b4fe472016-06-13 09:34:57 -0700382 return (ssize_t) filled;
383 }
384 size_t availToRead = (size_t) filled;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800385 if (availToRead > count) {
386 availToRead = count;
387 }
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700388 uint32_t frontMasked = mLocalFront & (mFifo.mFrameCountP2 - 1);
389 size_t part1 = mFifo.mFrameCount - frontMasked;
Glenn Kasten9b4c8052015-01-06 14:13:13 -0800390 if (part1 > availToRead) {
391 part1 = availToRead;
392 }
Glenn Kasten547a9922016-06-15 13:07:31 -0700393 size_t part2 = part1 > 0 ? availToRead - part1 : 0;
Glenn Kasten169f3a22016-06-17 10:43:34 -0700394 iovec[0].mOffset = frontMasked;
395 iovec[0].mLength = part1;
396 iovec[1].mOffset = 0;
397 iovec[1].mLength = part2;
Glenn Kasten6d7ad762016-06-15 17:05:54 -0700398 mObtained = availToRead;
Glenn Kasten547a9922016-06-15 13:07:31 -0700399 return availToRead;
400}