/*------------------------------------------------------------------------- * drawElements Stream Library * --------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Buffered and threaded input and output streams *//*--------------------------------------------------------------------*/ #include "deThreadStream.h" #include "deStreamCpyThread.h" #include "deRingbuffer.h" #include "stdlib.h" typedef struct deThreadInStream_s { deRingbuffer* ringbuffer; deInStream* input; deInStream consumerStream; deOutStream producerStream; deThread thread; int bufferSize; } deThreadInStream; typedef struct deThreadOutStream_s { deRingbuffer* ringbuffer; deInStream consumerStream; deOutStream producerStream; deStreamCpyThread* thread; } deThreadOutStream; static void inStreamCopy (void* arg) { deThreadInStream* threadStream = (deThreadInStream*)arg; deUint8* buffer = malloc(sizeof(deUint8) * (size_t)threadStream->bufferSize); for(;;) { deInt32 read = 0; deInt32 written = 0; deStreamResult readResult = DE_STREAMRESULT_ERROR; readResult = deInStream_read(threadStream->input, buffer, threadStream->bufferSize, &read); DE_ASSERT(readResult != DE_STREAMRESULT_ERROR); while (written < read) { deInt32 wrote = 0; /* \todo [mika] Handle errors */ deOutStream_write(&(threadStream->producerStream), buffer, read - written, &wrote); written += wrote; } if (readResult == DE_STREAMRESULT_END_OF_STREAM) { break; } } deOutStream_flush(&(threadStream->producerStream)); deRingbuffer_stop(threadStream->ringbuffer); free(buffer); } static deStreamResult threadInStream_read (deStreamData* stream, void* buf, deInt32 bufSize, deInt32* numRead) { deThreadInStream* threadStream = (deThreadInStream*)stream; return deInStream_read(&(threadStream->consumerStream), buf, bufSize, numRead); } static const char* threadInStream_getError (deStreamData* stream) { deThreadInStream* threadStream = (deThreadInStream*)stream; /* \todo [mika] Add handling for errors on thread stream */ return deInStream_getError(&(threadStream->consumerStream)); } static deStreamStatus threadInStream_getStatus (deStreamData* stream) { deThreadInStream* threadStream = (deThreadInStream*)stream; /* \todo [mika] Add handling for status on thread stream */ return deInStream_getStatus(&(threadStream->consumerStream)); } /* \note [mika] Used by both in and out stream */ static deStreamResult threadStream_deinit (deStreamData* stream) { deThreadInStream* threadStream = (deThreadInStream*)stream; deRingbuffer_stop(threadStream->ringbuffer); deThread_join(threadStream->thread); deThread_destroy(threadStream->thread); deOutStream_deinit(&(threadStream->producerStream)); deInStream_deinit(&(threadStream->consumerStream)); deRingbuffer_destroy(threadStream->ringbuffer); return DE_STREAMRESULT_SUCCESS; } static const deIOStreamVFTable threadInStreamVFTable = { threadInStream_read, DE_NULL, threadInStream_getError, DE_NULL, threadStream_deinit, threadInStream_getStatus }; void deThreadInStream_init (deInStream* stream, deInStream* input, int ringbufferBlockSize, int ringbufferBlockCount) { deThreadInStream* threadStream = DE_NULL; threadStream = malloc(sizeof(deThreadInStream)); DE_ASSERT(threadStream); threadStream->ringbuffer = deRingbuffer_create(ringbufferBlockSize, ringbufferBlockCount); DE_ASSERT(threadStream->ringbuffer); threadStream->bufferSize = ringbufferBlockSize; threadStream->input = input; deProducerStream_init(&(threadStream->producerStream), threadStream->ringbuffer); deConsumerStream_init(&(threadStream->consumerStream), threadStream->ringbuffer); threadStream->thread = deThread_create(inStreamCopy, threadStream, DE_NULL); stream->ioStream.vfTable = &threadInStreamVFTable; stream->ioStream.streamData = threadStream; } static deStreamResult threadOutStream_write (deStreamData* stream, const void* buf, deInt32 bufSize, deInt32* numWritten) { deThreadOutStream* threadStream = (deThreadOutStream*)stream; return deOutStream_write(&(threadStream->producerStream), buf, bufSize, numWritten); } static const char* threadOutStream_getError (deStreamData* stream) { deThreadOutStream* threadStream = (deThreadOutStream*)stream; /* \todo [mika] Add handling for errors on thread stream */ return deOutStream_getError(&(threadStream->producerStream)); } static deStreamStatus threadOutStream_getStatus (deStreamData* stream) { deThreadOutStream* threadStream = (deThreadOutStream*)stream; /* \todo [mika] Add handling for errors on thread stream */ return deOutStream_getStatus(&(threadStream->producerStream)); } static deStreamResult threadOutStream_flush (deStreamData* stream) { deThreadOutStream* threadStream = (deThreadOutStream*)stream; return deOutStream_flush(&(threadStream->producerStream)); } static const deIOStreamVFTable threadOutStreamVFTable = { DE_NULL, threadOutStream_write, threadOutStream_getError, threadOutStream_flush, threadStream_deinit, threadOutStream_getStatus }; void deThreadOutStream_init (deOutStream* stream, deOutStream* output, int ringbufferBlockSize, int ringbufferBlockCount) { deThreadOutStream* threadStream = DE_NULL; threadStream = malloc(sizeof(deThreadOutStream)); DE_ASSERT(threadStream); threadStream->ringbuffer = deRingbuffer_create(ringbufferBlockSize, ringbufferBlockCount); DE_ASSERT(threadStream->ringbuffer); deProducerStream_init(&(threadStream->producerStream), threadStream->ringbuffer); deConsumerStream_init(&(threadStream->consumerStream), threadStream->ringbuffer); threadStream->thread = deStreamCpyThread_create(&(threadStream->consumerStream), output, ringbufferBlockSize); stream->ioStream.vfTable = &threadOutStreamVFTable; stream->ioStream.streamData = threadStream; }