Beispiel #1
0
bool LLBufferArray::copyIntoBuffers(
	S32 channel,
	const U8* src,
	S32 len,
	std::vector<LLSegment>& segments)
{
	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
	if(!src || !len) return false;
	S32 copied = 0;
	LLSegment segment;
	buffer_iterator_t it = mBuffers.begin();
	buffer_iterator_t end = mBuffers.end();
	for(; it != end;)
	{
		if(!(*it)->createSegment(channel, len, segment))
		{
			++it;
			continue;
		}
		segments.push_back(segment);
		S32 bytes = llmin(segment.size(), len);
		memcpy(segment.data(), src + copied, bytes);  /* Flawfinder: Ignore */
		copied += bytes;
		len -= bytes;
		if(0 == len)
		{
			break;
		}
	}
	while(len)
	{
		LLBuffer* buf = new LLHeapBuffer;
		mBuffers.push_back(buf);
		if(!buf->createSegment(channel, len, segment))
		{
			// this totally failed - bail. This is the weird corner
			// case were we 'leak' memory. No worries about an actual
			// leak - we will still reclaim the memory later, but this
			// particular buffer array is hosed for some reason.
			// This should never happen.
			return false;
		}
		segments.push_back(segment);
		memcpy(segment.data(), src + copied, segment.size());	/*Flawfinder: ignore*/
		copied += segment.size();
		len -= segment.size();
	}
	return true;
}
// virtual
bool LLHeapBuffer::containsSegment(const LLSegment& segment) const
{
	// *NOTE: this check is fairly simple because heap buffers are
	// simple contiguous chunks of heap memory.
	if((mBuffer > segment.data())
	   || ((mBuffer + mSize) < (segment.data() + segment.size())))
	{
		return false;
	}
	return true;
}
// virtual
bool LLHeapBuffer::reclaimSegment(const LLSegment& segment)
{
	if(containsSegment(segment))
	{
		mReclaimedBytes += segment.size();
		if(mReclaimedBytes == mSize)
		{
			// We have reclaimed all of the memory from this
			// buffer. Therefore, we can reset the mNextFree to the
			// start of the buffer, and reset the reclaimed bytes.
			mReclaimedBytes = 0;
			mNextFree = mBuffer;
		}
		else if(mReclaimedBytes > mSize)
		{
			LL_WARNS() << "LLHeapBuffer reclaimed more memory than allocated."
				<< " This is probably programmer error." << LL_ENDL;
		}
		return true;
	}
	return false;
}
// virtual
LLIOPipe::EStatus LLIOSocketWriter::process_impl(
	const LLChannelDescriptors& channels,
	buffer_ptr_t& buffer,
	bool& eos,
	LLSD& context,
	LLPumpIO* pump)
{
	LL_RECORD_BLOCK_TIME(FTM_PROCESS_SOCKET_WRITER);
	PUMP_DEBUG;
	if(!mDestination) return STATUS_PRECONDITION_NOT_MET;
	if(!mInitialized)
	{
		PUMP_DEBUG;
		// Since the write will not block, it's ok to initialize and
		// attempt to write immediately.
		mInitialized = true;
		if(pump)
		{
			PUMP_DEBUG;
			LL_DEBUGS() << "Initializing poll descriptor for LLIOSocketWriter."
					 << LL_ENDL;
			apr_pollfd_t poll_fd;
			poll_fd.p = NULL;
			poll_fd.desc_type = APR_POLL_SOCKET;
			poll_fd.reqevents = APR_POLLOUT;
			poll_fd.rtnevents = 0x0;
			poll_fd.desc.s = mDestination->getSocket();
			poll_fd.client_data = NULL;
			pump->setConditional(this, &poll_fd);
		}
	}

	PUMP_DEBUG;
	// *FIX: Some sort of writev implementation would be much more
	// efficient - not only because writev() is better, but also
	// because we won't have to do as much work to find the start
	// address.
	buffer->lock();
	LLBufferArray::segment_iterator_t it;
	LLBufferArray::segment_iterator_t end = buffer->endSegment();
	LLSegment segment;
	it = buffer->constructSegmentAfter(mLastWritten, segment);
	/*
	if(NULL == mLastWritten)
	{
		it = buffer->beginSegment();
		segment = (*it);
	}
	else
	{
		it = buffer->getSegment(mLastWritten);
		segment = (*it);
		S32 size = segment.size();
		U8* data = segment.data();
		if((data + size) == mLastWritten)
		{
			++it;
			segment = (*it);
		}
		else
		{
			// *FIX: check the math on this one
			segment = LLSegment(
				(*it).getChannelMask(),
				mLastWritten + 1,
				size - (mLastWritten - data));
		}
	}
	*/

	PUMP_DEBUG;
	apr_size_t len;
	bool done = false;
	apr_status_t status = APR_SUCCESS;
	while(it != end)
	{

		PUMP_DEBUG;
		if((*it).isOnChannel(channels.in()))
		{
			PUMP_DEBUG;
			len = (apr_size_t)segment.size();
			status = apr_socket_send(
				mDestination->getSocket(),
				(const char*)segment.data(),
				&len);
			// We sometimes get a 'non-blocking socket operation could not be 
			// completed immediately' error from apr_socket_send.  In this
			// case we break and the data will be sent the next time the chain
			// is pumped.
			if(APR_STATUS_IS_EAGAIN(status))
			{
				ll_apr_warn_status(status);
				break;
			}

			mLastWritten = segment.data() + len - 1;

			PUMP_DEBUG;
			if((S32)len < segment.size())
			{
				break;
			}
			
		}

		++it;
		if(it != end)
		{
			segment = (*it);
		}
		else
		{
			done = true;
		}

	}
	buffer->unlock();

	PUMP_DEBUG;
	if(done && eos)
	{
		return STATUS_DONE;
	}
	return STATUS_OK;
}
// virtual
int LLBufferStreamBuf::underflow()
{
	LLMemType m1(LLMemType::MTYPE_IO_BUFFER);
	//lldebugs << "LLBufferStreamBuf::underflow()" << llendl;
	if(!mBuffer)
	{
		return EOF;
	}

	LLMutexLock lock(mBuffer->getMutex());
	LLBufferArray::segment_iterator_t iter;
	LLBufferArray::segment_iterator_t end = mBuffer->endSegment();
	U8* last_pos = (U8*)gptr();
	LLSegment segment;
	if(last_pos)
	{
		// Back up into a piece of memory we know that we have
		// allocated so that calls for the next segment based on
		// 'after' will succeed.
		--last_pos;
		iter = mBuffer->splitAfter(last_pos);
		if(iter != end)
		{
			// We need to clear the read segment just in case we have
			// an early exit in the function and never collect the
			// next segment. Calling eraseSegment() with the same
			// segment twice is just like double deleting -- nothing
			// good comes from it.
			mBuffer->eraseSegment(iter++);
			if(iter != end) segment = (*iter);
		}
		else
		{
			// This should never really happen, but somehow, the
			// istream is telling the buf that it just finished
			// reading memory that is not in the buf. I think this
			// would only happen if there were a bug in the c++ stream
			// class. Just bail.
			// *TODO: can we set the fail bit on the stream somehow?
			return EOF;
		}
	}
	else
	{
		// Get iterator to full segment containing last_pos
		// and construct sub-segment starting at last_pos.
		// Note: segment may != *it at this point
		iter = mBuffer->constructSegmentAfter(last_pos, segment);
	}
	if(iter == end)
	{
		return EOF;
	}

	// Iterate through segments to find a non-empty segment on input channel.
	while((!segment.isOnChannel(mChannels.in()) || (segment.size() == 0)))
	{
		++iter;
		if(iter == end)
		{
			return EOF;
		}

		segment = *(iter);
	}

	// set up the stream to read from the next segment.
	char* start = (char*)segment.data();
	setg(start, start, start + segment.size());
	return *gptr();
}
Beispiel #6
0
	void buffer_object_t::test<4>()
	{
		S32 channel = 50;
		S32 bigSize = 16384*2;
		char str[] = "SecondLife";
		S32 smallSize = sizeof(str);

		LLSegment segment;
		LLHeapBuffer buf; // use default size of DEFAULT_HEAP_BUFFER_SIZE = 16384

		S32 requestSize;

		requestSize = 16384-1;
		ensure("1. LLHeapBuffer createSegment failed", (TRUE == buf.createSegment(channel, requestSize, segment)) && segment.size() == requestSize);
		// second request for remainign 1 byte

		requestSize = 1;
		ensure("2. LLHeapBuffer createSegment failed", (TRUE == buf.createSegment(channel, requestSize, segment)) && segment.size() == requestSize);

		// it should fail now.
		requestSize = 1;
		ensure("3. LLHeapBuffer createSegment failed", (FALSE == buf.createSegment(channel, requestSize, segment)));

		LLHeapBuffer buf1(bigSize);

		// requst for more than default size but less than total sizeit should fail now.
		requestSize = 16384 + 1;
		ensure("4. LLHeapBuffer createSegment failed", (TRUE == buf1.createSegment(channel, requestSize, segment)) && segment.size() == requestSize);

		LLHeapBuffer buf2((U8*) str, smallSize);
		requestSize = smallSize;
		ensure("5. LLHeapBuffer createSegment failed", (TRUE == buf2.createSegment(channel, requestSize, segment)) && segment.size() == requestSize && memcmp(segment.data(), (U8*) str, requestSize) == 0);
		requestSize = smallSize+1;
		ensure("6. LLHeapBuffer createSegment failed", (FALSE == buf2.createSegment(channel, requestSize, segment)));
	}	
Beispiel #7
0
	void buffer_object_t::test<2>()
	{
		LLSegment segment;
		ensure("LLSegment get functions failed", (0 == segment.getChannel() && NULL == segment.data() && 0 == segment.size()));
		segment.setChannel(50);
		ensure_equals("LLSegment setChannel() function failed", segment.getChannel(), 50);
		ensure("LLSegment isOnChannel() function failed", (TRUE == segment.isOnChannel(50)));
	}