PageRenderTime 102ms CodeModel.GetById 14ms app.highlight 82ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llmessage/llbuffer.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 930 lines | 734 code | 66 blank | 130 comment | 128 complexity | 21d65cf50689d5df2016d91f63b0e570 MD5 | raw file
  1/** 
  2 * @file llbuffer.cpp
  3 * @author Phoenix
  4 * @date 2005-09-20
  5 * @brief Implementation of the segments, buffers, and buffer arrays.
  6 *
  7 * $LicenseInfo:firstyear=2005&license=viewerlgpl$
  8 * Second Life Viewer Source Code
  9 * Copyright (C) 2010, Linden Research, Inc.
 10 * 
 11 * This library is free software; you can redistribute it and/or
 12 * modify it under the terms of the GNU Lesser General Public
 13 * License as published by the Free Software Foundation;
 14 * version 2.1 of the License only.
 15 * 
 16 * This library is distributed in the hope that it will be useful,
 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19 * Lesser General Public License for more details.
 20 * 
 21 * You should have received a copy of the GNU Lesser General Public
 22 * License along with this library; if not, write to the Free Software
 23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 24 * 
 25 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 26 * $/LicenseInfo$
 27 */
 28
 29#include "linden_common.h"
 30#include "llbuffer.h"
 31
 32#include "llmath.h"
 33#include "llmemtype.h"
 34#include "llstl.h"
 35#include "llthread.h"
 36
 37#define ASSERT_LLBUFFERARRAY_MUTEX_LOCKED llassert(!mMutexp || mMutexp->isSelfLocked());
 38
 39/** 
 40 * LLSegment
 41 */
 42LLSegment::LLSegment() :
 43	mChannel(0),
 44	mData(NULL),
 45	mSize(0)
 46{
 47	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
 48}
 49
 50LLSegment::LLSegment(S32 channel, U8* data, S32 data_len) :
 51	mChannel(channel),
 52	mData(data),
 53	mSize(data_len)
 54{
 55	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
 56}
 57
 58LLSegment::~LLSegment()
 59{
 60	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
 61}
 62
 63bool LLSegment::isOnChannel(S32 channel) const
 64{
 65	return (mChannel == channel);
 66}
 67
 68S32 LLSegment::getChannel() const
 69{
 70	return mChannel;
 71}
 72
 73void LLSegment::setChannel(S32 channel)
 74{
 75	mChannel = channel;
 76}
 77
 78
 79U8* LLSegment::data() const
 80{
 81	return mData;
 82}
 83
 84S32 LLSegment::size() const
 85{
 86	return mSize;
 87}
 88
 89bool LLSegment::operator==(const LLSegment& rhs) const
 90{
 91	if((mData != rhs.mData)||(mSize != rhs.mSize)||(mChannel != rhs.mChannel))
 92	{
 93		return false;
 94	}
 95	return true;
 96}
 97
 98/** 
 99 * LLHeapBuffer
100 */
101LLHeapBuffer::LLHeapBuffer() :
102	mBuffer(NULL),
103	mSize(0),
104	mNextFree(NULL),
105	mReclaimedBytes(0)
106{
107	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
108	const S32 DEFAULT_HEAP_BUFFER_SIZE = 16384;
109	allocate(DEFAULT_HEAP_BUFFER_SIZE);
110}
111
112LLHeapBuffer::LLHeapBuffer(S32 size) :
113	mBuffer(NULL),
114	mSize(0),
115	mNextFree(NULL),
116	mReclaimedBytes(0)
117{
118	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
119	allocate(size);
120}
121
122LLHeapBuffer::LLHeapBuffer(const U8* src, S32 len) :
123	mBuffer(NULL),
124	mSize(0),
125	mNextFree(NULL),
126	mReclaimedBytes(0)
127{
128	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
129	if((len > 0) && src)
130	{
131		allocate(len);
132		if(mBuffer)
133		{
134			memcpy(mBuffer, src, len);	/*Flawfinder: ignore*/
135		}
136	}
137}
138
139// virtual
140LLHeapBuffer::~LLHeapBuffer()
141{
142	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
143	delete[] mBuffer;
144	mBuffer = NULL;
145	mSize = 0;
146	mNextFree = NULL;
147}
148
149S32 LLHeapBuffer::bytesLeft() const
150{
151	return (mSize - (mNextFree - mBuffer));
152}
153
154// virtual
155bool LLHeapBuffer::createSegment(
156	S32 channel,
157	S32 size,
158	LLSegment& segment)
159{
160	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
161	// get actual size of the segment.
162	S32 actual_size = llmin(size, (mSize - S32(mNextFree - mBuffer)));
163
164	// bail if we cannot build a valid segment
165	if(actual_size <= 0)
166	{
167		return false;
168	}
169
170	// Yay, we're done.
171	segment = LLSegment(channel, mNextFree, actual_size);
172	mNextFree += actual_size;
173	return true;
174}
175
176// virtual
177bool LLHeapBuffer::reclaimSegment(const LLSegment& segment)
178{
179	if(containsSegment(segment))
180	{
181		mReclaimedBytes += segment.size();
182		if(mReclaimedBytes == mSize)
183		{
184			// We have reclaimed all of the memory from this
185			// buffer. Therefore, we can reset the mNextFree to the
186			// start of the buffer, and reset the reclaimed bytes.
187			mReclaimedBytes = 0;
188			mNextFree = mBuffer;
189		}
190		else if(mReclaimedBytes > mSize)
191		{
192			llwarns << "LLHeapBuffer reclaimed more memory than allocated."
193				<< " This is probably programmer error." << llendl;
194		}
195		return true;
196	}
197	return false;
198}
199
200// virtual
201bool LLHeapBuffer::containsSegment(const LLSegment& segment) const
202{
203	// *NOTE: this check is fairly simple because heap buffers are
204	// simple contiguous chunks of heap memory.
205	if((mBuffer > segment.data())
206	   || ((mBuffer + mSize) < (segment.data() + segment.size())))
207	{
208		return false;
209	}
210	return true;
211}
212
213void LLHeapBuffer::allocate(S32 size)
214{
215	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
216	mReclaimedBytes = 0;	
217	mBuffer = new U8[size];
218	if(mBuffer)
219	{
220		mSize = size;
221		mNextFree = mBuffer;
222	}
223}
224
225
226/** 
227 * LLBufferArray
228 */
229LLBufferArray::LLBufferArray() :
230	mNextBaseChannel(0),
231	mMutexp(NULL)
232{
233	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
234}
235
236LLBufferArray::~LLBufferArray()
237{
238	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
239	std::for_each(mBuffers.begin(), mBuffers.end(), DeletePointer());
240
241	delete mMutexp;
242}
243
244// static
245LLChannelDescriptors LLBufferArray::makeChannelConsumer(
246	const LLChannelDescriptors& channels)
247{
248	LLChannelDescriptors rv(channels.out());
249	return rv;
250}
251
252void LLBufferArray::lock()
253{
254	if(mMutexp)
255	{
256		mMutexp->lock() ;
257	}
258}
259
260void LLBufferArray::unlock()
261{
262	if(mMutexp)
263	{
264		mMutexp->unlock() ;
265	}
266}
267
268LLMutex* LLBufferArray::getMutex()
269{
270	return mMutexp ;
271}
272
273void LLBufferArray::setThreaded(bool threaded)
274{
275	if(threaded)
276	{
277		if(!mMutexp)
278		{
279			mMutexp = new LLMutex(NULL);
280		}
281	}
282	else
283	{
284		if(mMutexp)
285		{
286			delete mMutexp ;
287			mMutexp = NULL ;
288		}
289	}
290}
291
292LLChannelDescriptors LLBufferArray::nextChannel()
293{
294	LLChannelDescriptors rv(mNextBaseChannel++);
295	return rv;
296}
297
298//mMutexp should be locked before calling this.
299S32 LLBufferArray::capacity() const
300{
301	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
302
303	S32 total = 0;
304	const_buffer_iterator_t iter = mBuffers.begin();
305	const_buffer_iterator_t end = mBuffers.end();
306	for(; iter != end; ++iter)
307	{
308		total += (*iter)->capacity();
309	}
310	return total;
311}
312
313bool LLBufferArray::append(S32 channel, const U8* src, S32 len)
314{
315	LLMutexLock lock(mMutexp) ;
316
317	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
318	std::vector<LLSegment> segments;
319	if(copyIntoBuffers(channel, src, len, segments))
320	{
321		mSegments.insert(mSegments.end(), segments.begin(), segments.end());
322		return true;
323	}
324	return false;
325}
326
327//mMutexp should be locked before calling this.
328bool LLBufferArray::prepend(S32 channel, const U8* src, S32 len)
329{
330	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
331
332	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
333	std::vector<LLSegment> segments;
334	if(copyIntoBuffers(channel, src, len, segments))
335	{
336		mSegments.insert(mSegments.begin(), segments.begin(), segments.end());
337		return true;
338	}
339	return false;
340}
341
342bool LLBufferArray::insertAfter(
343	segment_iterator_t segment,
344	S32 channel,
345	const U8* src,
346	S32 len)
347{
348	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
349	std::vector<LLSegment> segments;
350
351	LLMutexLock lock(mMutexp) ;
352	if(mSegments.end() != segment)
353	{
354		++segment;
355	}
356	if(copyIntoBuffers(channel, src, len, segments))
357	{
358		mSegments.insert(segment, segments.begin(), segments.end());
359		return true;
360	}
361	return false;
362}
363
364//mMutexp should be locked before calling this.
365LLBufferArray::segment_iterator_t LLBufferArray::splitAfter(U8* address)
366{
367	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
368
369	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
370	segment_iterator_t end = mSegments.end();
371	segment_iterator_t it = getSegment(address);
372	if(it == end)
373	{
374		return end;
375	}
376
377	// We have the location and the segment.
378	U8* base = (*it).data();
379	S32 size = (*it).size();
380	if(address == (base + size))
381	{
382		// No need to split, since this is the last byte of the
383		// segment. We do not want to have zero length segments, since
384		// that will only incur processing overhead with no advantage.
385		return it;
386	}
387	S32 channel = (*it).getChannel();
388	LLSegment segment1(channel, base, (address - base) + 1);
389	*it = segment1;
390	segment_iterator_t rv = it;
391	++it;
392	LLSegment segment2(channel, address + 1, size - (address - base) - 1);
393	mSegments.insert(it, segment2);
394	return rv;
395}
396							   
397//mMutexp should be locked before calling this.
398LLBufferArray::segment_iterator_t LLBufferArray::beginSegment()
399{
400	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
401	return mSegments.begin();
402}
403
404//mMutexp should be locked before calling this.
405LLBufferArray::segment_iterator_t LLBufferArray::endSegment()
406{
407	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
408	return mSegments.end();
409}
410
411//mMutexp should be locked before calling this.
412LLBufferArray::segment_iterator_t LLBufferArray::constructSegmentAfter(
413	U8* address,
414	LLSegment& segment)
415{
416	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
417	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
418	segment_iterator_t rv = mSegments.begin();
419	segment_iterator_t end = mSegments.end();
420	if(!address)
421	{
422		if(rv != end)
423		{
424			segment = (*rv);
425		}
426	}
427	else
428	{
429		// we have an address - find the segment it is in.
430		for( ; rv != end; ++rv)
431		{
432			if((address >= (*rv).data())
433			   && (address < ((*rv).data() + (*rv).size())))
434			{
435				if((++address) < ((*rv).data() + (*rv).size()))
436				{
437					// it's in this segment - construct an appropriate
438					// sub-segment.
439					segment = LLSegment(
440						(*rv).getChannel(),
441						address,
442						(*rv).size() - (address - (*rv).data()));
443				}
444				else
445				{
446					++rv;
447					if(rv != end)
448					{
449						segment = (*rv);
450					}
451				}
452				break;
453			}
454		}
455	}
456	if(rv == end)
457	{
458		segment = LLSegment();
459	}
460	return rv;
461}
462
463//mMutexp should be locked before calling this.
464LLBufferArray::segment_iterator_t LLBufferArray::getSegment(U8* address)
465{
466	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
467	segment_iterator_t end = mSegments.end();
468	if(!address)
469	{
470		return end;
471	}
472	segment_iterator_t it = mSegments.begin();
473	for( ; it != end; ++it)
474	{
475		if((address >= (*it).data())&&(address < (*it).data() + (*it).size()))
476		{
477			// found it.
478			return it;
479		}
480	}
481	return end;
482}
483
484//mMutexp should be locked before calling this.
485LLBufferArray::const_segment_iterator_t LLBufferArray::getSegment(
486	U8* address) const
487{
488	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
489	const_segment_iterator_t end = mSegments.end();
490	if(!address)
491	{
492		return end;
493	}
494	const_segment_iterator_t it = mSegments.begin();
495	for( ; it != end; ++it)
496	{
497		if((address >= (*it).data())
498		   && (address < (*it).data() + (*it).size()))
499		{
500			// found it.
501			return it;
502		}
503	}
504	return end;
505}
506
507/*
508U8* LLBufferArray::getAddressAfter(U8* address) 
509{
510	U8* rv = NULL;
511	segment_iterator_t it = getSegment(address);
512	segment_iterator_t end = mSegments.end();
513	if(it != end)
514	{
515		if(++address < ((*it).data() + (*it).size()))
516		{
517			// it's in the same segment
518			rv = address;
519		}
520		else
521		{
522			// it's in the next segment
523			if(++it != end)
524			{
525				rv = (*it).data();
526			}
527		}
528	}
529	return rv;
530}
531*/
532
533S32 LLBufferArray::countAfter(S32 channel, U8* start) const
534{
535	S32 count = 0;
536	S32 offset = 0;
537	const_segment_iterator_t it;
538
539	LLMutexLock lock(mMutexp) ;
540	const_segment_iterator_t end = mSegments.end();
541	if(start)
542	{
543		it = getSegment(start);
544		if(it == end)
545		{
546			return count;
547		}
548		if(++start < ((*it).data() + (*it).size()))
549		{
550			// it's in the same segment
551			offset = start - (*it).data();
552		}
553		else if(++it == end)
554		{
555			// it's in the next segment
556			return count;
557		}
558	}
559	else
560	{
561		it = mSegments.begin();
562	}
563	while(it != end)
564	{
565		if((*it).isOnChannel(channel))
566		{
567			count += (*it).size() - offset;
568		}
569		offset = 0;
570		++it;
571	}
572	return count;
573}
574
575U8* LLBufferArray::readAfter(
576	S32 channel,
577	U8* start,
578	U8* dest,
579	S32& len) const
580{
581	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
582	U8* rv = start;
583	if(!dest || len <= 0)
584	{
585		return rv;
586	}
587	S32 bytes_left = len;
588	len = 0;
589	S32 bytes_to_copy = 0;
590	const_segment_iterator_t it;
591
592	LLMutexLock lock(mMutexp) ;
593	const_segment_iterator_t end = mSegments.end();
594	if(start)
595	{
596		it = getSegment(start);
597		if(it == end)
598		{
599			return rv;
600		}
601		if((++start < ((*it).data() + (*it).size()))
602		   && (*it).isOnChannel(channel))
603		{
604			// copy the data out of this segment
605			S32 bytes_in_segment = (*it).size() - (start - (*it).data());
606			bytes_to_copy = llmin(bytes_left, bytes_in_segment);
607			memcpy(dest, start, bytes_to_copy); /*Flawfinder: ignore*/
608			len += bytes_to_copy;
609			bytes_left -= bytes_to_copy;
610			rv = start + bytes_to_copy - 1;
611			++it;
612		}
613		else
614		{
615			++it;
616		}
617	}
618	else
619	{
620		it = mSegments.begin();
621	}
622	while(bytes_left && (it != end))
623	{
624		if(!((*it).isOnChannel(channel)))
625		{
626			++it;
627			continue;
628		}
629		bytes_to_copy = llmin(bytes_left, (*it).size());
630		memcpy(dest + len, (*it).data(), bytes_to_copy); /*Flawfinder: ignore*/
631		len += bytes_to_copy;
632		bytes_left -= bytes_to_copy;
633		rv = (*it).data() + bytes_to_copy - 1;
634		++it;
635	}
636	return rv;
637}
638
639U8* LLBufferArray::seek(
640	S32 channel,
641	U8* start,
642	S32 delta) const
643{
644	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
645	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
646	const_segment_iterator_t it;
647	const_segment_iterator_t end = mSegments.end();
648	U8* rv = start;
649	if(0 == delta)
650	{
651		if((U8*)npos == start)
652		{
653			// someone is looking for end of data. 
654			segment_list_t::const_reverse_iterator rit = mSegments.rbegin();
655			segment_list_t::const_reverse_iterator rend = mSegments.rend();
656			while(rit != rend)
657			{
658				if(!((*rit).isOnChannel(channel)))
659				{
660					++rit;
661					continue;
662				}
663				rv = (*rit).data() + (*rit).size();
664				break;
665			}
666		}
667		else if(start)
668		{
669			// This is sort of a weird case - check if zero bytes away
670			// from current position is on channel and return start if
671			// that is true. Otherwise, return NULL.
672			it = getSegment(start);
673			if((it == end) || !(*it).isOnChannel(channel))
674			{
675				rv = NULL;
676			}
677		}
678		else
679		{
680			// Start is NULL, so return the very first byte on the
681			// channel, or NULL.
682			it = mSegments.begin();
683			while((it != end) && !(*it).isOnChannel(channel))
684			{
685				++it;
686			}
687			if(it != end)
688			{
689				rv = (*it).data();
690			}
691		}
692		return rv;
693	}
694	if(start)
695	{
696		it = getSegment(start);
697		if((it != end) && (*it).isOnChannel(channel))
698		{
699			if(delta > 0)
700			{
701				S32 bytes_in_segment = (*it).size() - (start - (*it).data());
702				S32 local_delta = llmin(delta, bytes_in_segment);
703				rv += local_delta;
704				delta -= local_delta;
705				++it;
706			}
707			else
708			{
709				S32 bytes_in_segment = start - (*it).data();
710				S32 local_delta = llmin(llabs(delta), bytes_in_segment);
711				rv -= local_delta;
712				delta += local_delta;
713			}
714		}
715	}
716	else if(delta < 0)
717	{
718		// start is NULL, and delta indicates seeking backwards -
719		// return NULL.
720		return NULL;
721	}
722	else
723	{
724		// start is NULL and delta > 0
725		it = mSegments.begin();
726	}
727	if(delta > 0)
728	{
729		// At this point, we have an iterator into the segments, and
730		// are seeking forward until delta is zero or we run out
731		while(delta && (it != end))
732		{
733			if(!((*it).isOnChannel(channel)))
734			{
735				++it;
736				continue;
737			}
738			if(delta <= (*it).size())
739			{
740				// it's in this segment
741				rv = (*it).data() + delta;
742			}
743			delta -= (*it).size();
744			++it;
745		}
746		if(delta && (it == end))
747		{
748			// Whoops - sought past end.
749			rv = NULL;
750		}
751	}
752	else //if(delta < 0)
753	{
754		// We are at the beginning of a segment, and need to search
755		// backwards.
756		segment_list_t::const_reverse_iterator rit(it);
757		segment_list_t::const_reverse_iterator rend = mSegments.rend();
758		while(delta && (rit != rend))
759		{
760			if(!((*rit).isOnChannel(channel)))
761			{
762				++rit;
763				continue;
764			}
765			if(llabs(delta) <= (*rit).size())
766			{
767				// it's in this segment.
768				rv = (*rit).data() + (*rit).size() + delta;
769				delta = 0;
770			}
771			else
772			{
773				delta += (*rit).size();
774			}
775			++rit;
776		}
777		if(delta && (rit == rend))
778		{
779			// sought past the beginning.
780			rv = NULL;
781		}
782	}
783	return rv;
784}
785
786//test use only
787bool LLBufferArray::takeContents(LLBufferArray& source)
788{
789	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
790
791	LLMutexLock lock(mMutexp);
792	source.lock();
793
794	std::copy(
795		source.mBuffers.begin(),
796		source.mBuffers.end(),
797		std::back_insert_iterator<buffer_list_t>(mBuffers));
798	source.mBuffers.clear();
799	std::copy(
800		source.mSegments.begin(),
801		source.mSegments.end(),
802		std::back_insert_iterator<segment_list_t>(mSegments));
803	source.mSegments.clear();
804	source.mNextBaseChannel = 0;
805	source.unlock();
806
807	return true;
808}
809
810//mMutexp should be locked before calling this.
811LLBufferArray::segment_iterator_t LLBufferArray::makeSegment(
812	S32 channel,
813	S32 len)
814{
815	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
816	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
817	// start at the end of the buffers, because it is the most likely
818	// to have free space.
819	LLSegment segment;
820	buffer_list_t::reverse_iterator it = mBuffers.rbegin();
821	buffer_list_t::reverse_iterator end = mBuffers.rend();
822	bool made_segment = false;
823	for(; it != end; ++it)
824	{
825		if((*it)->createSegment(channel, len, segment))
826		{
827			made_segment = true;
828			break;
829		}
830	}
831	segment_iterator_t send = mSegments.end();
832	if(!made_segment)
833	{
834		LLBuffer* buf = new LLHeapBuffer;
835		mBuffers.push_back(buf);
836		if(!buf->createSegment(channel, len, segment))
837		{
838			// failed. this should never happen.
839			return send;
840		}
841	}
842
843	// store and return the newly made segment
844	mSegments.insert(send, segment);
845	std::list<LLSegment>::reverse_iterator rv = mSegments.rbegin();
846	++rv;
847	send = rv.base();
848	return send;
849}
850
851//mMutexp should be locked before calling this.
852bool LLBufferArray::eraseSegment(const segment_iterator_t& erase_iter)
853{
854	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
855	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
856
857	// Find out which buffer contains the segment, and if it is found,
858	// ask it to reclaim the memory.
859	bool rv = false;
860	LLSegment segment(*erase_iter);
861	buffer_iterator_t iter = mBuffers.begin();
862	buffer_iterator_t end = mBuffers.end();
863	for(; iter != end; ++iter)
864	{
865		// We can safely call reclaimSegment on every buffer, and once
866		// it returns true, the segment was found.
867		if((*iter)->reclaimSegment(segment))
868		{
869			rv = true;
870			break;
871		}
872	}
873
874	// No need to get the return value since we are not interested in
875	// the interator retured by the call.
876	(void)mSegments.erase(erase_iter);
877	return rv;
878}
879
880//mMutexp should be locked before calling this.
881bool LLBufferArray::copyIntoBuffers(
882	S32 channel,
883	const U8* src,
884	S32 len,
885	std::vector<LLSegment>& segments)
886{
887	ASSERT_LLBUFFERARRAY_MUTEX_LOCKED
888	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
889	if(!src || !len) return false;
890	S32 copied = 0;
891	LLSegment segment;
892	buffer_iterator_t it = mBuffers.begin();
893	buffer_iterator_t end = mBuffers.end();
894	for(; it != end;)
895	{
896		if(!(*it)->createSegment(channel, len, segment))
897		{
898			++it;
899			continue;
900		}
901		segments.push_back(segment);
902		S32 bytes = llmin(segment.size(), len);
903		memcpy(segment.data(), src + copied, bytes);  /* Flawfinder: Ignore */
904		copied += bytes;
905		len -= bytes;
906		if(0 == len)
907		{
908			break;
909		}
910	}
911	while(len)
912	{
913		LLBuffer* buf = new LLHeapBuffer;
914		mBuffers.push_back(buf);
915		if(!buf->createSegment(channel, len, segment))
916		{
917			// this totally failed - bail. This is the weird corner
918			// case were we 'leak' memory. No worries about an actual
919			// leak - we will still reclaim the memory later, but this
920			// particular buffer array is hosed for some reason.
921			// This should never happen.
922			return false;
923		}
924		segments.push_back(segment);
925		memcpy(segment.data(), src + copied, segment.size());	/*Flawfinder: ignore*/
926		copied += segment.size();
927		len -= segment.size();
928	}
929	return true;
930}