PageRenderTime 109ms CodeModel.GetById 12ms app.highlight 88ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llmessage/llpumpio.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1225 lines | 979 code | 82 blank | 164 comment | 126 complexity | ebdaf1d2775c78b0b70cfcbf2eecc990 MD5 | raw file
   1/** 
   2 * @file llpumpio.cpp
   3 * @author Phoenix
   4 * @date 2004-11-21
   5 * @brief Implementation of the i/o pump and related functions.
   6 *
   7 * $LicenseInfo:firstyear=2004&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 "llpumpio.h"
  31
  32#include <map>
  33#include <set>
  34#include "apr_poll.h"
  35
  36#include "llapr.h"
  37#include "llmemtype.h"
  38#include "llstl.h"
  39#include "llstat.h"
  40
  41// These should not be enabled in production, but they can be
  42// intensely useful during development for finding certain kinds of
  43// bugs.
  44#if LL_LINUX
  45//#define LL_DEBUG_PIPE_TYPE_IN_PUMP 1
  46//#define LL_DEBUG_POLL_FILE_DESCRIPTORS 1
  47#if LL_DEBUG_POLL_FILE_DESCRIPTORS
  48#include "apr_portable.h"
  49#endif
  50#endif
  51
  52#if LL_DEBUG_PIPE_TYPE_IN_PUMP
  53#include <typeinfo>
  54#endif
  55
  56// constants for poll timeout. if we are threading, we want to have a
  57// longer poll timeout.
  58#if LL_THREADS_APR
  59static const S32 DEFAULT_POLL_TIMEOUT = 1000;
  60#else
  61static const S32 DEFAULT_POLL_TIMEOUT = 0;
  62#endif
  63
  64// The default (and fallback) expiration time for chains
  65const F32 DEFAULT_CHAIN_EXPIRY_SECS = 30.0f;
  66extern const F32 SHORT_CHAIN_EXPIRY_SECS = 1.0f;
  67extern const F32 NEVER_CHAIN_EXPIRY_SECS = 0.0f;
  68
  69// sorta spammy debug modes.
  70//#define LL_DEBUG_SPEW_BUFFER_CHANNEL_IN_ON_ERROR 1
  71//#define LL_DEBUG_PROCESS_LINK 1
  72//#define LL_DEBUG_PROCESS_RETURN_VALUE 1
  73
  74// Super spammy debug mode.
  75//#define LL_DEBUG_SPEW_BUFFER_CHANNEL_IN 1
  76//#define LL_DEBUG_SPEW_BUFFER_CHANNEL_OUT 1
  77
  78//
  79// local functions
  80//
  81void ll_debug_poll_fd(const char* msg, const apr_pollfd_t* poll)
  82{
  83#if LL_DEBUG_POLL_FILE_DESCRIPTORS
  84	if(!poll)
  85	{
  86		lldebugs << "Poll -- " << (msg?msg:"") << ": no pollfd." << llendl;
  87		return;
  88	}
  89	if(poll->desc.s)
  90	{
  91		apr_os_sock_t os_sock;
  92		if(APR_SUCCESS == apr_os_sock_get(&os_sock, poll->desc.s))
  93		{
  94			lldebugs << "Poll -- " << (msg?msg:"") << " on fd " << os_sock
  95				 << " at " << poll->desc.s << llendl;
  96		}
  97		else
  98		{
  99			lldebugs << "Poll -- " << (msg?msg:"") << " no fd "
 100				 << " at " << poll->desc.s << llendl;
 101		}
 102	}
 103	else if(poll->desc.f)
 104	{
 105		apr_os_file_t os_file;
 106		if(APR_SUCCESS == apr_os_file_get(&os_file, poll->desc.f))
 107		{
 108			lldebugs << "Poll -- " << (msg?msg:"") << " on fd " << os_file
 109				 << " at " << poll->desc.f << llendl;
 110		}
 111		else
 112		{
 113			lldebugs << "Poll -- " << (msg?msg:"") << " no fd "
 114				 << " at " << poll->desc.f << llendl;
 115		}
 116	}
 117	else
 118	{
 119		lldebugs << "Poll -- " << (msg?msg:"") << ": no descriptor." << llendl;
 120	}
 121#endif	
 122}
 123
 124/**
 125 * @class
 126 */
 127class LLChainSleeper : public LLRunnable
 128{
 129public:
 130	static LLRunner::run_ptr_t build(LLPumpIO* pump, S32 key)
 131	{
 132		return LLRunner::run_ptr_t(new LLChainSleeper(pump, key));
 133	}
 134	
 135	virtual void run(LLRunner* runner, S64 handle)
 136	{
 137		mPump->clearLock(mKey);
 138	}
 139
 140protected:
 141	LLChainSleeper(LLPumpIO* pump, S32 key) : mPump(pump), mKey(key) {}
 142	LLPumpIO* mPump;
 143	S32 mKey;
 144};
 145
 146
 147/**
 148 * @struct ll_delete_apr_pollset_fd_client_data
 149 * @brief This is a simple helper class to clean up our client data.
 150 */
 151struct ll_delete_apr_pollset_fd_client_data
 152{
 153	typedef std::pair<LLIOPipe::ptr_t, apr_pollfd_t> pipe_conditional_t;
 154	void operator()(const pipe_conditional_t& conditional)
 155	{
 156		LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 157		S32* client_id = (S32*)conditional.second.client_data;
 158		delete client_id;
 159	}
 160};
 161
 162/**
 163 * LLPumpIO
 164 */
 165LLPumpIO::LLPumpIO(apr_pool_t* pool) :
 166	mState(LLPumpIO::NORMAL),
 167	mRebuildPollset(false),
 168	mPollset(NULL),
 169	mPollsetClientID(0),
 170	mNextLock(0),
 171	mPool(NULL),
 172	mCurrentPool(NULL),
 173	mCurrentPoolReallocCount(0),
 174	mChainsMutex(NULL),
 175	mCallbackMutex(NULL),
 176	mCurrentChain(mRunningChains.end())
 177{
 178	mCurrentChain = mRunningChains.end();
 179
 180	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 181	initialize(pool);
 182}
 183
 184LLPumpIO::~LLPumpIO()
 185{
 186	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 187	cleanup();
 188}
 189
 190bool LLPumpIO::prime(apr_pool_t* pool)
 191{
 192	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 193	cleanup();
 194	initialize(pool);
 195	return ((pool == NULL) ? false : true);
 196}
 197
 198bool LLPumpIO::addChain(const chain_t& chain, F32 timeout, bool has_curl_request)
 199{
 200	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 201	if(chain.empty()) return false;
 202
 203#if LL_THREADS_APR
 204	LLScopedLock lock(mChainsMutex);
 205#endif
 206	LLChainInfo info;
 207	info.mHasCurlRequest = has_curl_request;
 208	info.setTimeoutSeconds(timeout);
 209	info.mData = LLIOPipe::buffer_ptr_t(new LLBufferArray);
 210	info.mData->setThreaded(has_curl_request);
 211	LLLinkInfo link;
 212#if LL_DEBUG_PIPE_TYPE_IN_PUMP
 213	lldebugs << "LLPumpIO::addChain() " << chain[0] << " '"
 214		<< typeid(*(chain[0])).name() << "'" << llendl;
 215#else
 216	lldebugs << "LLPumpIO::addChain() " << chain[0] <<llendl;
 217#endif
 218	chain_t::const_iterator it = chain.begin();
 219	chain_t::const_iterator end = chain.end();
 220	for(; it != end; ++it)
 221	{
 222		link.mPipe = (*it);
 223		link.mChannels = info.mData->nextChannel();
 224		info.mChainLinks.push_back(link);
 225	}
 226	mPendingChains.push_back(info);
 227	return true;
 228}
 229
 230bool LLPumpIO::addChain(
 231	const LLPumpIO::links_t& links,
 232	LLIOPipe::buffer_ptr_t data,
 233	LLSD context,
 234	F32 timeout)
 235{
 236	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 237
 238	// remember that if the caller is providing a full link
 239	// description, we need to have that description matched to a
 240	// particular buffer.
 241	if(!data) return false;
 242	if(links.empty()) return false;
 243
 244#if LL_THREADS_APR
 245	LLScopedLock lock(mChainsMutex);
 246#endif
 247#if LL_DEBUG_PIPE_TYPE_IN_PUMP
 248	lldebugs << "LLPumpIO::addChain() " << links[0].mPipe << " '"
 249		<< typeid(*(links[0].mPipe)).name() << "'" << llendl;
 250#else
 251	lldebugs << "LLPumpIO::addChain() " << links[0].mPipe << llendl;
 252#endif
 253	LLChainInfo info;
 254	info.setTimeoutSeconds(timeout);
 255	info.mChainLinks = links;
 256	info.mData = data;
 257	info.mContext = context;
 258	mPendingChains.push_back(info);
 259	return true;
 260}
 261
 262bool LLPumpIO::setTimeoutSeconds(F32 timeout)
 263{
 264	// If no chain is running, return failure.
 265	if(mRunningChains.end() == mCurrentChain)
 266	{
 267		return false;
 268	}
 269	(*mCurrentChain).setTimeoutSeconds(timeout);
 270	return true;
 271}
 272
 273void LLPumpIO::adjustTimeoutSeconds(F32 delta)
 274{
 275	// Ensure a chain is running
 276	if(mRunningChains.end() != mCurrentChain)
 277	{
 278		(*mCurrentChain).adjustTimeoutSeconds(delta);
 279	}
 280}
 281
 282static std::string events_2_string(apr_int16_t events)
 283{
 284	std::ostringstream ostr;
 285	if(events & APR_POLLIN)
 286	{
 287		ostr << "read,";
 288	}
 289	if(events & APR_POLLPRI)
 290	{
 291		ostr << "priority,";
 292	}
 293	if(events & APR_POLLOUT)
 294	{
 295		ostr << "write,";
 296	}
 297	if(events & APR_POLLERR)
 298	{
 299		ostr << "error,";
 300	}
 301	if(events & APR_POLLHUP)
 302	{
 303		ostr << "hangup,";
 304	}
 305	if(events & APR_POLLNVAL)
 306	{
 307		ostr << "invalid,";
 308	}
 309	return chop_tail_copy(ostr.str(), 1);
 310}
 311
 312bool LLPumpIO::setConditional(LLIOPipe* pipe, const apr_pollfd_t* poll)
 313{
 314	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 315	if(!pipe) return false;
 316	ll_debug_poll_fd("Set conditional", poll);
 317
 318	lldebugs << "Setting conditionals (" << (poll ? events_2_string(poll->reqevents) :"null")
 319		 << ") "
 320#if LL_DEBUG_PIPE_TYPE_IN_PUMP
 321		 << "on pipe " << typeid(*pipe).name() 
 322#endif
 323		 << " at " << pipe << llendl;
 324
 325	// remove any matching poll file descriptors for this pipe.
 326	LLIOPipe::ptr_t pipe_ptr(pipe);
 327	LLChainInfo::conditionals_t::iterator it;
 328	it = (*mCurrentChain).mDescriptors.begin();
 329	while(it != (*mCurrentChain).mDescriptors.end())
 330	{
 331		LLChainInfo::pipe_conditional_t& value = (*it);
 332		if(pipe_ptr == value.first)
 333		{
 334			ll_delete_apr_pollset_fd_client_data()(value);
 335			it = (*mCurrentChain).mDescriptors.erase(it);
 336			mRebuildPollset = true;
 337		}
 338		else
 339		{
 340			++it;
 341		}
 342	}
 343
 344	if(!poll)
 345	{
 346		mRebuildPollset = true;
 347		return true;
 348	}
 349	LLChainInfo::pipe_conditional_t value;
 350	value.first = pipe_ptr;
 351	value.second = *poll;
 352	value.second.rtnevents = 0;
 353	if(!poll->p)
 354	{
 355		// each fd needs a pool to work with, so if one was
 356		// not specified, use this pool.
 357		// *FIX: Should it always be this pool?
 358		value.second.p = mPool;
 359	}
 360	value.second.client_data = new S32(++mPollsetClientID);
 361	(*mCurrentChain).mDescriptors.push_back(value);
 362	mRebuildPollset = true;
 363	return true;
 364}
 365
 366S32 LLPumpIO::setLock()
 367{
 368	// *NOTE: I do not think it is necessary to acquire a mutex here
 369	// since this should only be called during the pump(), and should
 370	// only change the running chain. Any other use of this method is
 371	// incorrect usage. If it becomes necessary to acquire a lock
 372	// here, be sure to lock here and call a protected method to get
 373	// the lock, and sleepChain() should probably acquire the same
 374	// lock while and calling the same protected implementation to
 375	// lock the runner at the same time.
 376
 377	// If no chain is running, return failure.
 378	if(mRunningChains.end() == mCurrentChain)
 379	{
 380		return 0;
 381	}
 382
 383	// deal with wrap.
 384	if(++mNextLock <= 0)
 385	{
 386		mNextLock = 1;
 387	}
 388
 389	// set the lock
 390	(*mCurrentChain).mLock = mNextLock;
 391	return mNextLock;
 392}
 393
 394void LLPumpIO::clearLock(S32 key)
 395{
 396	// We need to lock it here since we do not want to be iterating
 397	// over the chains twice. We can safely call process() while this
 398	// is happening since we should not be erasing a locked pipe, and
 399	// therefore won't be treading into deleted memory. I think we can
 400	// also clear the lock on the chain safely since the pump only
 401	// reads that value.
 402#if LL_THREADS_APR
 403	LLScopedLock lock(mChainsMutex);
 404#endif
 405	mClearLocks.insert(key);
 406}
 407
 408bool LLPumpIO::sleepChain(F64 seconds)
 409{
 410	// Much like the call to setLock(), this should only be called
 411	// from one chain during processing, so there is no need to
 412	// acquire a mutex.
 413	if(seconds <= 0.0) return false;
 414	S32 key = setLock();
 415	if(!key) return false;
 416	LLRunner::run_handle_t handle = mRunner.addRunnable(
 417		LLChainSleeper::build(this, key),
 418		LLRunner::RUN_IN,
 419		seconds);
 420	if(0 == handle) return false;
 421	return true;
 422}
 423
 424bool LLPumpIO::copyCurrentLinkInfo(links_t& links) const
 425{
 426	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 427	if(mRunningChains.end() == mCurrentChain)
 428	{
 429		return false;
 430	}
 431	std::copy(
 432		(*mCurrentChain).mChainLinks.begin(),
 433		(*mCurrentChain).mChainLinks.end(),
 434		std::back_insert_iterator<links_t>(links));
 435	return true;
 436}
 437
 438void LLPumpIO::pump()
 439{
 440	pump(DEFAULT_POLL_TIMEOUT);
 441}
 442
 443static LLFastTimer::DeclareTimer FTM_PUMP_IO("Pump IO");
 444
 445LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t& run_chain) 
 446{
 447	std::for_each(
 448				(*run_chain).mDescriptors.begin(),
 449				(*run_chain).mDescriptors.end(),
 450				ll_delete_apr_pollset_fd_client_data());
 451	return mRunningChains.erase(run_chain);
 452}
 453
 454//timeout is in microseconds
 455void LLPumpIO::pump(const S32& poll_timeout)
 456{
 457	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 458	LLFastTimer t1(FTM_PUMP_IO);
 459	//llinfos << "LLPumpIO::pump()" << llendl;
 460
 461	// Run any pending runners.
 462	mRunner.run();
 463
 464	// We need to move all of the pending heads over to the running
 465	// chains.
 466	PUMP_DEBUG;
 467	if(true)
 468	{
 469#if LL_THREADS_APR
 470		LLScopedLock lock(mChainsMutex);
 471#endif
 472		// bail if this pump is paused.
 473		if(PAUSING == mState)
 474		{
 475			mState = PAUSED;
 476		}
 477		if(PAUSED == mState)
 478		{
 479			return;
 480		}
 481
 482		PUMP_DEBUG;
 483		// Move the pending chains over to the running chaings
 484		if(!mPendingChains.empty())
 485		{
 486			PUMP_DEBUG;
 487			//lldebugs << "Pushing " << mPendingChains.size() << "." << llendl;
 488			std::copy(
 489				mPendingChains.begin(),
 490				mPendingChains.end(),
 491				std::back_insert_iterator<running_chains_t>(mRunningChains));
 492			mPendingChains.clear();
 493			PUMP_DEBUG;
 494		}
 495
 496		// Clear any locks. This needs to be done here so that we do
 497		// not clash during a call to clearLock().
 498		if(!mClearLocks.empty())
 499		{
 500			PUMP_DEBUG;
 501			running_chains_t::iterator it = mRunningChains.begin();
 502			running_chains_t::iterator end = mRunningChains.end();
 503			std::set<S32>::iterator not_cleared = mClearLocks.end();
 504			for(; it != end; ++it)
 505			{
 506				if((*it).mLock && mClearLocks.find((*it).mLock) != not_cleared)
 507				{
 508					(*it).mLock = 0;
 509				}
 510			}
 511			PUMP_DEBUG;
 512			mClearLocks.clear();
 513		}
 514	}
 515
 516	PUMP_DEBUG;
 517	// rebuild the pollset if necessary
 518	if(mRebuildPollset)
 519	{
 520		PUMP_DEBUG;
 521		rebuildPollset();
 522		mRebuildPollset = false;
 523	}
 524
 525	// Poll based on the last known pollset
 526	// *TODO: may want to pass in a poll timeout so it works correctly
 527	// in single and multi threaded processes.
 528	PUMP_DEBUG;
 529	typedef std::map<S32, S32> signal_client_t;
 530	signal_client_t signalled_client;
 531	const apr_pollfd_t* poll_fd = NULL;
 532	if(mPollset)
 533	{
 534		PUMP_DEBUG;
 535		//llinfos << "polling" << llendl;
 536		S32 count = 0;
 537		S32 client_id = 0;
 538        {
 539            LLPerfBlock polltime("pump_poll");
 540            apr_pollset_poll(mPollset, poll_timeout, &count, &poll_fd);
 541        }
 542		PUMP_DEBUG;
 543		for(S32 ii = 0; ii < count; ++ii)
 544		{
 545			ll_debug_poll_fd("Signalled pipe", &poll_fd[ii]);
 546			client_id = *((S32*)poll_fd[ii].client_data);
 547			signalled_client[client_id] = ii;
 548		}
 549		PUMP_DEBUG;
 550	}
 551
 552	PUMP_DEBUG;
 553	// set up for a check to see if each one was signalled
 554	signal_client_t::iterator not_signalled = signalled_client.end();
 555
 556	// Process everything as appropriate
 557	//lldebugs << "Running chain count: " << mRunningChains.size() << llendl;
 558	running_chains_t::iterator run_chain = mRunningChains.begin();
 559	bool process_this_chain = false;
 560	while( run_chain != mRunningChains.end() )
 561	{
 562		PUMP_DEBUG;
 563		if((*run_chain).mInit
 564		   && (*run_chain).mTimer.getStarted()
 565		   && (*run_chain).mTimer.hasExpired())
 566		{
 567			PUMP_DEBUG;
 568			if(handleChainError(*run_chain, LLIOPipe::STATUS_EXPIRED))
 569			{
 570				// the pipe probably handled the error. If the handler
 571				// forgot to reset the expiration then we need to do
 572				// that here.
 573				if((*run_chain).mTimer.getStarted()
 574				   && (*run_chain).mTimer.hasExpired())
 575				{
 576					PUMP_DEBUG;
 577					llinfos << "Error handler forgot to reset timeout. "
 578							<< "Resetting to " << DEFAULT_CHAIN_EXPIRY_SECS
 579							<< " seconds." << llendl;
 580					(*run_chain).setTimeoutSeconds(DEFAULT_CHAIN_EXPIRY_SECS);
 581				}
 582			}
 583			else
 584			{
 585				PUMP_DEBUG;
 586				// it timed out and no one handled it, so we need to
 587				// retire the chain
 588#if LL_DEBUG_PIPE_TYPE_IN_PUMP
 589				lldebugs << "Removing chain "
 590						<< (*run_chain).mChainLinks[0].mPipe
 591						<< " '"
 592						<< typeid(*((*run_chain).mChainLinks[0].mPipe)).name()
 593						<< "' because it timed out." << llendl;
 594#else
 595//				lldebugs << "Removing chain "
 596//						<< (*run_chain).mChainLinks[0].mPipe
 597//						<< " because we reached the end." << llendl;
 598#endif
 599				run_chain = removeRunningChain(run_chain);
 600				continue;
 601			}
 602		}
 603		else if(isChainExpired(*run_chain))
 604		{
 605			run_chain = removeRunningChain(run_chain);
 606			continue;
 607		}
 608
 609		PUMP_DEBUG;
 610		if((*run_chain).mLock)
 611		{
 612			++run_chain;
 613			continue;
 614		}
 615		PUMP_DEBUG;
 616		mCurrentChain = run_chain;
 617		
 618		if((*run_chain).mDescriptors.empty())
 619		{
 620			// if there are no conditionals, just process this chain.
 621			process_this_chain = true;
 622			//lldebugs << "no conditionals - processing" << llendl;
 623		}
 624		else
 625		{
 626			PUMP_DEBUG;
 627			//lldebugs << "checking conditionals" << llendl;
 628			// Check if this run chain was signalled. If any file
 629			// descriptor is ready for something, then go ahead and
 630			// process this chian.
 631			process_this_chain = false;
 632			if(!signalled_client.empty())
 633			{
 634				PUMP_DEBUG;
 635				LLChainInfo::conditionals_t::iterator it;
 636				it = (*run_chain).mDescriptors.begin();
 637				LLChainInfo::conditionals_t::iterator end;
 638				end = (*run_chain).mDescriptors.end();
 639				S32 client_id = 0;
 640				signal_client_t::iterator signal;
 641				for(; it != end; ++it)
 642				{
 643					PUMP_DEBUG;
 644					client_id = *((S32*)((*it).second.client_data));
 645					signal = signalled_client.find(client_id);
 646					if (signal == not_signalled) continue;
 647					static const apr_int16_t POLL_CHAIN_ERROR =
 648						APR_POLLHUP | APR_POLLNVAL | APR_POLLERR;
 649					const apr_pollfd_t* poll = &(poll_fd[(*signal).second]);
 650					if(poll->rtnevents & POLL_CHAIN_ERROR)
 651					{
 652						// Potential eror condition has been
 653						// returned. If HUP was one of them, we pass
 654						// that as the error even though there may be
 655						// more. If there are in fact more errors,
 656						// we'll just wait for that detection until
 657						// the next pump() cycle to catch it so that
 658						// the logic here gets no more strained than
 659						// it already is.
 660						LLIOPipe::EStatus error_status;
 661						if(poll->rtnevents & APR_POLLHUP)
 662							error_status = LLIOPipe::STATUS_LOST_CONNECTION;
 663						else
 664							error_status = LLIOPipe::STATUS_ERROR;
 665						if(handleChainError(*run_chain, error_status)) break;
 666						ll_debug_poll_fd("Removing pipe", poll);
 667						llwarns << "Removing pipe "
 668							<< (*run_chain).mChainLinks[0].mPipe
 669							<< " '"
 670#if LL_DEBUG_PIPE_TYPE_IN_PUMP
 671							<< typeid(
 672								*((*run_chain).mChainLinks[0].mPipe)).name()
 673#endif
 674							<< "' because: "
 675							<< events_2_string(poll->rtnevents)
 676							<< llendl;
 677						(*run_chain).mHead = (*run_chain).mChainLinks.end();
 678						break;
 679					}
 680
 681					// at least 1 fd got signalled, and there were no
 682					// errors. That means we process this chain.
 683					process_this_chain = true;
 684					break;
 685				}
 686			}
 687		}
 688		if(process_this_chain)
 689		{
 690			PUMP_DEBUG;
 691			if(!((*run_chain).mInit))
 692			{
 693				(*run_chain).mHead = (*run_chain).mChainLinks.begin();
 694				(*run_chain).mInit = true;
 695			}
 696			PUMP_DEBUG;
 697			processChain(*run_chain);
 698		}
 699
 700		PUMP_DEBUG;
 701		if((*run_chain).mHead == (*run_chain).mChainLinks.end())
 702		{
 703#if LL_DEBUG_PIPE_TYPE_IN_PUMP
 704			lldebugs << "Removing chain " << (*run_chain).mChainLinks[0].mPipe
 705					<< " '"
 706					<< typeid(*((*run_chain).mChainLinks[0].mPipe)).name()
 707					<< "' because we reached the end." << llendl;
 708#else
 709//			lldebugs << "Removing chain " << (*run_chain).mChainLinks[0].mPipe
 710//					<< " because we reached the end." << llendl;
 711#endif
 712
 713			PUMP_DEBUG;
 714			// This chain is done. Clean up any allocated memory and
 715			// erase the chain info.
 716			run_chain = removeRunningChain(run_chain);
 717
 718			// *NOTE: may not always need to rebuild the pollset.
 719			mRebuildPollset = true;
 720		}
 721		else
 722		{
 723			PUMP_DEBUG;
 724			// this chain needs more processing - just go to the next
 725			// chain.
 726			++run_chain;
 727		}
 728	}
 729
 730	PUMP_DEBUG;
 731	// null out the chain
 732	mCurrentChain = mRunningChains.end();
 733	END_PUMP_DEBUG;
 734}
 735
 736//bool LLPumpIO::respond(const chain_t& pipes)
 737//{
 738//#if LL_THREADS_APR
 739//	LLScopedLock lock(mCallbackMutex);
 740//#endif
 741//	LLChainInfo info;
 742//	links_t links;
 743//	
 744//	mPendingCallbacks.push_back(info);
 745//	return true;
 746//}
 747
 748bool LLPumpIO::respond(LLIOPipe* pipe)
 749{
 750	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 751	if(NULL == pipe) return false;
 752
 753#if LL_THREADS_APR
 754	LLScopedLock lock(mCallbackMutex);
 755#endif
 756	LLChainInfo info;
 757	LLLinkInfo link;
 758	link.mPipe = pipe;
 759	info.mChainLinks.push_back(link);
 760	mPendingCallbacks.push_back(info);
 761	return true;
 762}
 763
 764bool LLPumpIO::respond(
 765	const links_t& links,
 766	LLIOPipe::buffer_ptr_t data,
 767	LLSD context)
 768{
 769	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 770	// if the caller is providing a full link description, we need to
 771	// have that description matched to a particular buffer.
 772	if(!data) return false;
 773	if(links.empty()) return false;
 774
 775#if LL_THREADS_APR
 776	LLScopedLock lock(mCallbackMutex);
 777#endif
 778
 779	// Add the callback response
 780	LLChainInfo info;
 781	info.mChainLinks = links;
 782	info.mData = data;
 783	info.mContext = context;
 784	mPendingCallbacks.push_back(info);
 785	return true;
 786}
 787
 788static LLFastTimer::DeclareTimer FTM_PUMP_CALLBACK_CHAIN("Chain");
 789
 790void LLPumpIO::callback()
 791{
 792	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 793	//llinfos << "LLPumpIO::callback()" << llendl;
 794	if(true)
 795	{
 796#if LL_THREADS_APR
 797		LLScopedLock lock(mCallbackMutex);
 798#endif
 799		std::copy(
 800			mPendingCallbacks.begin(),
 801			mPendingCallbacks.end(),
 802			std::back_insert_iterator<callbacks_t>(mCallbacks));
 803		mPendingCallbacks.clear();
 804	}
 805	if(!mCallbacks.empty())
 806	{
 807		callbacks_t::iterator it = mCallbacks.begin();
 808		callbacks_t::iterator end = mCallbacks.end();
 809		for(; it != end; ++it)
 810		{
 811			LLFastTimer t(FTM_PUMP_CALLBACK_CHAIN);
 812			// it's always the first and last time for respone chains
 813			(*it).mHead = (*it).mChainLinks.begin();
 814			(*it).mInit = true;
 815			(*it).mEOS = true;
 816			processChain(*it);
 817		}
 818		mCallbacks.clear();
 819	}
 820}
 821
 822void LLPumpIO::control(LLPumpIO::EControl op)
 823{
 824#if LL_THREADS_APR
 825	LLScopedLock lock(mChainsMutex);
 826#endif
 827	switch(op)
 828	{
 829	case PAUSE:
 830		mState = PAUSING;
 831		break;
 832	case RESUME:
 833		mState = NORMAL;
 834		break;
 835	default:
 836		// no-op
 837		break;
 838	}
 839}
 840
 841void LLPumpIO::initialize(apr_pool_t* pool)
 842{
 843	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 844	if(!pool) return;
 845#if LL_THREADS_APR
 846	// SJB: Windows defaults to NESTED and OSX defaults to UNNESTED, so use UNNESTED explicitly.
 847	apr_thread_mutex_create(&mChainsMutex, APR_THREAD_MUTEX_UNNESTED, pool);
 848	apr_thread_mutex_create(&mCallbackMutex, APR_THREAD_MUTEX_UNNESTED, pool);
 849#endif
 850	mPool = pool;
 851}
 852
 853void LLPumpIO::cleanup()
 854{
 855	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 856#if LL_THREADS_APR
 857	if(mChainsMutex) apr_thread_mutex_destroy(mChainsMutex);
 858	if(mCallbackMutex) apr_thread_mutex_destroy(mCallbackMutex);
 859#endif
 860	mChainsMutex = NULL;
 861	mCallbackMutex = NULL;
 862	if(mPollset)
 863	{
 864//		lldebugs << "cleaning up pollset" << llendl;
 865		apr_pollset_destroy(mPollset);
 866		mPollset = NULL;
 867	}
 868	if(mCurrentPool)
 869	{
 870		apr_pool_destroy(mCurrentPool);
 871		mCurrentPool = NULL;
 872	}
 873	mPool = NULL;
 874}
 875
 876void LLPumpIO::rebuildPollset()
 877{
 878	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 879//	lldebugs << "LLPumpIO::rebuildPollset()" << llendl;
 880	if(mPollset)
 881	{
 882		//lldebugs << "destroying pollset" << llendl;
 883		apr_pollset_destroy(mPollset);
 884		mPollset = NULL;
 885	}
 886	U32 size = 0;
 887	running_chains_t::iterator run_it = mRunningChains.begin();
 888	running_chains_t::iterator run_end = mRunningChains.end();
 889	for(; run_it != run_end; ++run_it)
 890	{
 891		size += (*run_it).mDescriptors.size();
 892	}
 893	//lldebugs << "found " << size << " descriptors." << llendl;
 894	if(size)
 895	{
 896		// Recycle the memory pool
 897		const S32 POLLSET_POOL_RECYCLE_COUNT = 100;
 898		if(mCurrentPool
 899		   && (0 == (++mCurrentPoolReallocCount % POLLSET_POOL_RECYCLE_COUNT)))
 900		{
 901			apr_pool_destroy(mCurrentPool);
 902			mCurrentPool = NULL;
 903			mCurrentPoolReallocCount = 0;
 904		}
 905		if(!mCurrentPool)
 906		{
 907			apr_status_t status = apr_pool_create(&mCurrentPool, mPool);
 908			(void)ll_apr_warn_status(status);
 909		}
 910
 911		// add all of the file descriptors
 912		run_it = mRunningChains.begin();
 913		LLChainInfo::conditionals_t::iterator fd_it;
 914		LLChainInfo::conditionals_t::iterator fd_end;
 915		apr_pollset_create(&mPollset, size, mCurrentPool, 0);
 916		for(; run_it != run_end; ++run_it)
 917		{
 918			fd_it = (*run_it).mDescriptors.begin();
 919			fd_end = (*run_it).mDescriptors.end();
 920			for(; fd_it != fd_end; ++fd_it)
 921			{
 922				apr_pollset_add(mPollset, &((*fd_it).second));
 923			}
 924		}
 925	}
 926}
 927
 928void LLPumpIO::processChain(LLChainInfo& chain)
 929{
 930	PUMP_DEBUG;
 931	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
 932	LLIOPipe::EStatus status = LLIOPipe::STATUS_OK;
 933	links_t::iterator it = chain.mHead;
 934	links_t::iterator end = chain.mChainLinks.end();
 935	bool need_process_signaled = false;
 936	bool keep_going = true;
 937	do
 938	{
 939#if LL_DEBUG_PROCESS_LINK
 940#if LL_DEBUG_PIPE_TYPE_IN_PUMP
 941		llinfos << "Processing " << typeid(*((*it).mPipe)).name() << "."
 942				<< llendl;
 943#else
 944		llinfos << "Processing link " << (*it).mPipe << "." << llendl;
 945#endif
 946#endif
 947#if LL_DEBUG_SPEW_BUFFER_CHANNEL_IN
 948		if(chain.mData)
 949		{
 950			char* buf = NULL;
 951			S32 bytes = chain.mData->countAfter((*it).mChannels.in(), NULL);
 952			if(bytes)
 953			{
 954				buf = new char[bytes + 1];
 955				chain.mData->readAfter(
 956					(*it).mChannels.in(),
 957					NULL,
 958					(U8*)buf,
 959					bytes);
 960				buf[bytes] = '\0';
 961				llinfos << "CHANNEL IN(" << (*it).mChannels.in() << "): "
 962						<< buf << llendl;
 963				delete[] buf;
 964				buf = NULL;
 965			}
 966			else
 967			{
 968				llinfos << "CHANNEL IN(" << (*it).mChannels.in()<< "): (null)"
 969						<< llendl;
 970			}
 971		}
 972#endif
 973		PUMP_DEBUG;
 974		status = (*it).mPipe->process(
 975			(*it).mChannels,
 976			chain.mData,
 977			chain.mEOS,
 978			chain.mContext,
 979			this);
 980#if LL_DEBUG_SPEW_BUFFER_CHANNEL_OUT
 981		if(chain.mData)
 982		{
 983			char* buf = NULL;
 984			S32 bytes = chain.mData->countAfter((*it).mChannels.out(), NULL);
 985			if(bytes)
 986			{
 987				buf = new char[bytes + 1];
 988				chain.mData->readAfter(
 989					(*it).mChannels.out(),
 990					NULL,
 991					(U8*)buf,
 992					bytes);
 993				buf[bytes] = '\0';
 994				llinfos << "CHANNEL OUT(" << (*it).mChannels.out()<< "): "
 995						<< buf << llendl;
 996				delete[] buf;
 997				buf = NULL;
 998			}
 999			else
1000			{
1001				llinfos << "CHANNEL OUT(" << (*it).mChannels.out()<< "): (null)"
1002						<< llendl;
1003			}
1004		}
1005#endif
1006
1007#if LL_DEBUG_PROCESS_RETURN_VALUE
1008		// Only bother with the success codes - error codes are logged
1009		// below.
1010		if(LLIOPipe::isSuccess(status))
1011		{
1012			llinfos << "Pipe returned: '"
1013#if LL_DEBUG_PIPE_TYPE_IN_PUMP
1014					<< typeid(*((*it).mPipe)).name() << "':'"
1015#endif
1016					<< LLIOPipe::lookupStatusString(status) << "'" << llendl;
1017		}
1018#endif
1019
1020		PUMP_DEBUG;
1021		switch(status)
1022		{
1023		case LLIOPipe::STATUS_OK:
1024			// no-op
1025			break;
1026		case LLIOPipe::STATUS_STOP:
1027			PUMP_DEBUG;
1028			status = LLIOPipe::STATUS_OK;
1029			chain.mHead = end;
1030			keep_going = false;
1031			break;
1032		case LLIOPipe::STATUS_DONE:
1033			PUMP_DEBUG;
1034			status = LLIOPipe::STATUS_OK;
1035			chain.mHead = (it + 1);
1036			chain.mEOS = true;
1037			break;
1038		case LLIOPipe::STATUS_BREAK:
1039			PUMP_DEBUG;
1040			status = LLIOPipe::STATUS_OK;
1041			keep_going = false;
1042			break;
1043		case LLIOPipe::STATUS_NEED_PROCESS:
1044			PUMP_DEBUG;
1045			status = LLIOPipe::STATUS_OK;
1046			if(!need_process_signaled)
1047			{
1048				need_process_signaled = true;
1049				chain.mHead = it;
1050			}
1051			break;
1052		default:
1053			PUMP_DEBUG;
1054			if(LLIOPipe::isError(status))
1055			{
1056				llinfos << "Pump generated pipe err: '"
1057#if LL_DEBUG_PIPE_TYPE_IN_PUMP
1058						<< typeid(*((*it).mPipe)).name() << "':'"
1059#endif
1060						<< LLIOPipe::lookupStatusString(status)
1061						<< "'" << llendl;
1062#if LL_DEBUG_SPEW_BUFFER_CHANNEL_IN_ON_ERROR
1063				if(chain.mData)
1064				{
1065					char* buf = NULL;
1066					S32 bytes = chain.mData->countAfter(
1067						(*it).mChannels.in(),
1068						NULL);
1069					if(bytes)
1070					{
1071						buf = new char[bytes + 1];
1072						chain.mData->readAfter(
1073							(*it).mChannels.in(),
1074							NULL,
1075							(U8*)buf,
1076							bytes);
1077						buf[bytes] = '\0';
1078						llinfos << "Input After Error: " << buf << llendl;
1079						delete[] buf;
1080						buf = NULL;
1081					}
1082					else
1083					{
1084						llinfos << "Input After Error: (null)" << llendl;
1085					}
1086				}
1087				else
1088				{
1089					llinfos << "Input After Error: (null)" << llendl;
1090				}
1091#endif
1092				keep_going = false;
1093				chain.mHead  = it;
1094				if(!handleChainError(chain, status))
1095				{
1096					chain.mHead = end;
1097				}
1098			}
1099			else
1100			{
1101				llinfos << "Unhandled status code: " << status << ":"
1102						<< LLIOPipe::lookupStatusString(status) << llendl;
1103			}
1104			break;
1105		}
1106		PUMP_DEBUG;
1107	} while(keep_going && (++it != end));
1108	PUMP_DEBUG;
1109}
1110
1111bool LLPumpIO::isChainExpired(LLChainInfo& chain)
1112{
1113	if(!chain.mHasCurlRequest)
1114	{
1115		return false ;
1116	}
1117
1118	for(links_t::iterator iter = chain.mChainLinks.begin(); iter != chain.mChainLinks.end(); ++iter)
1119	{
1120		if(!(*iter).mPipe->isValid())
1121		{
1122			return true ;
1123		}
1124	}
1125
1126	return false ;
1127}
1128
1129bool LLPumpIO::handleChainError(
1130	LLChainInfo& chain,
1131	LLIOPipe::EStatus error)
1132{
1133	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
1134	links_t::reverse_iterator rit;
1135	if(chain.mHead == chain.mChainLinks.end())
1136	{
1137		rit = links_t::reverse_iterator(chain.mHead);
1138	}
1139	else
1140	{
1141		rit = links_t::reverse_iterator(chain.mHead + 1);
1142	}
1143	
1144	links_t::reverse_iterator rend = chain.mChainLinks.rend();
1145	bool handled = false;
1146	bool keep_going = true;
1147	do
1148	{
1149#if LL_DEBUG_PIPE_TYPE_IN_PUMP
1150		lldebugs << "Passing error to " << typeid(*((*rit).mPipe)).name()
1151				 << "." << llendl;
1152#endif
1153		error = (*rit).mPipe->handleError(error, this);
1154		switch(error)
1155		{
1156		case LLIOPipe::STATUS_OK:
1157			handled = true;
1158			chain.mHead = rit.base();
1159			break;
1160		case LLIOPipe::STATUS_STOP:
1161		case LLIOPipe::STATUS_DONE:
1162		case LLIOPipe::STATUS_BREAK:
1163		case LLIOPipe::STATUS_NEED_PROCESS:
1164#if LL_DEBUG_PIPE_TYPE_IN_PUMP
1165			lldebugs << "Pipe " << typeid(*((*rit).mPipe)).name()
1166					 << " returned code to stop error handler." << llendl;
1167#endif
1168			keep_going = false;
1169			break;
1170		case LLIOPipe::STATUS_EXPIRED:
1171			keep_going = false;
1172			break ;
1173		default:
1174			if(LLIOPipe::isSuccess(error))
1175			{
1176				llinfos << "Unhandled status code: " << error << ":"
1177						<< LLIOPipe::lookupStatusString(error) << llendl;
1178				error = LLIOPipe::STATUS_ERROR;
1179				keep_going = false;
1180			}
1181			break;
1182		}
1183	} while(keep_going && !handled && (++rit != rend));
1184	return handled;
1185}
1186
1187/**
1188 * LLPumpIO::LLChainInfo
1189 */
1190
1191LLPumpIO::LLChainInfo::LLChainInfo() :
1192	mInit(false),
1193	mLock(0),
1194	mEOS(false),
1195	mHasCurlRequest(false)
1196{
1197	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
1198	mTimer.setTimerExpirySec(DEFAULT_CHAIN_EXPIRY_SECS);
1199}
1200
1201void LLPumpIO::LLChainInfo::setTimeoutSeconds(F32 timeout)
1202{
1203	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
1204	if(timeout > 0.0f)
1205	{
1206		mTimer.start();
1207		mTimer.reset();
1208		mTimer.setTimerExpirySec(timeout);
1209	}
1210	else
1211	{
1212		mTimer.stop();
1213	}
1214}
1215
1216void LLPumpIO::LLChainInfo::adjustTimeoutSeconds(F32 delta)
1217{
1218	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
1219	if(mTimer.getStarted())
1220	{
1221		F64 expiry = mTimer.expiresAt();
1222		expiry += delta;
1223		mTimer.setExpiryAt(expiry);
1224	}
1225}