PageRenderTime 786ms CodeModel.GetById 140ms app.highlight 477ms RepoModel.GetById 157ms app.codeStats 1ms

/indra/llplugin/llpluginprocessparent.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1105 lines | 803 code | 169 blank | 133 comment | 150 complexity | 316fa129904c7ec4bed9f7bb2dc0be1a MD5 | raw file
   1/** 
   2 * @file llpluginprocessparent.cpp
   3 * @brief LLPluginProcessParent handles the parent side of the external-process plugin API.
   4 *
   5 * @cond
   6 * $LicenseInfo:firstyear=2008&license=viewerlgpl$
   7 * Second Life Viewer Source Code
   8 * Copyright (C) 2010, Linden Research, Inc.
   9 * 
  10 * This library is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU Lesser General Public
  12 * License as published by the Free Software Foundation;
  13 * version 2.1 of the License only.
  14 * 
  15 * This library is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18 * Lesser General Public License for more details.
  19 * 
  20 * You should have received a copy of the GNU Lesser General Public
  21 * License along with this library; if not, write to the Free Software
  22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  23 * 
  24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  25 * $/LicenseInfo$
  26 * @endcond
  27 */
  28
  29#include "linden_common.h"
  30
  31#include "llpluginprocessparent.h"
  32#include "llpluginmessagepipe.h"
  33#include "llpluginmessageclasses.h"
  34
  35#include "llapr.h"
  36
  37//virtual 
  38LLPluginProcessParentOwner::~LLPluginProcessParentOwner()
  39{
  40	
  41}
  42
  43bool LLPluginProcessParent::sUseReadThread = false;
  44apr_pollset_t *LLPluginProcessParent::sPollSet = NULL;
  45bool LLPluginProcessParent::sPollsetNeedsRebuild = false;
  46LLMutex *LLPluginProcessParent::sInstancesMutex;
  47std::list<LLPluginProcessParent*> LLPluginProcessParent::sInstances;
  48LLThread *LLPluginProcessParent::sReadThread = NULL;
  49
  50
  51class LLPluginProcessParentPollThread: public LLThread
  52{
  53public:
  54	LLPluginProcessParentPollThread() :
  55		LLThread("LLPluginProcessParentPollThread", gAPRPoolp)
  56	{
  57	}
  58protected:
  59	// Inherited from LLThread
  60	/*virtual*/ void run(void)
  61	{
  62		while(!isQuitting() && LLPluginProcessParent::getUseReadThread())
  63		{
  64			LLPluginProcessParent::poll(0.1f);
  65			checkPause();
  66		}
  67		
  68		// Final poll to clean up the pollset, etc.
  69		LLPluginProcessParent::poll(0.0f);
  70	} 
  71
  72	// Inherited from LLThread
  73	/*virtual*/ bool runCondition(void)
  74	{
  75		return(LLPluginProcessParent::canPollThreadRun());
  76	}
  77
  78};
  79
  80LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
  81	mIncomingQueueMutex(gAPRPoolp)
  82{
  83	if(!sInstancesMutex)
  84	{
  85		sInstancesMutex = new LLMutex(gAPRPoolp);
  86	}
  87	
  88	mOwner = owner;
  89	mBoundPort = 0;
  90	mState = STATE_UNINITIALIZED;
  91	mSleepTime = 0.0;
  92	mCPUUsage = 0.0;
  93	mDisableTimeout = false;
  94	mDebug = false;
  95	mBlocked = false;
  96	mPolledInput = false;
  97	mPollFD.client_data = NULL;
  98
  99	mPluginLaunchTimeout = 60.0f;
 100	mPluginLockupTimeout = 15.0f;
 101	
 102	// Don't start the timer here -- start it when we actually launch the plugin process.
 103	mHeartbeat.stop();
 104	
 105	// Don't add to the global list until fully constructed.
 106	{
 107		LLMutexLock lock(sInstancesMutex);
 108		sInstances.push_back(this);
 109	}
 110}
 111
 112LLPluginProcessParent::~LLPluginProcessParent()
 113{
 114	LL_DEBUGS("Plugin") << "destructor" << LL_ENDL;
 115
 116	// Remove from the global list before beginning destruction.
 117	{
 118		// Make sure to get the global mutex _first_ here, to avoid a possible deadlock against LLPluginProcessParent::poll()
 119		LLMutexLock lock(sInstancesMutex);
 120		{
 121			LLMutexLock lock2(&mIncomingQueueMutex);
 122			sInstances.remove(this);
 123		}
 124	}
 125
 126	// Destroy any remaining shared memory regions
 127	sharedMemoryRegionsType::iterator iter;
 128	while((iter = mSharedMemoryRegions.begin()) != mSharedMemoryRegions.end())
 129	{
 130		// destroy the shared memory region
 131		iter->second->destroy();
 132		
 133		// and remove it from our map
 134		mSharedMemoryRegions.erase(iter);
 135	}
 136	
 137	mProcess.kill();
 138	killSockets();
 139}
 140
 141void LLPluginProcessParent::killSockets(void)
 142{
 143	{
 144		LLMutexLock lock(&mIncomingQueueMutex);
 145		killMessagePipe();
 146	}
 147
 148	mListenSocket.reset();
 149	mSocket.reset();
 150}
 151
 152void LLPluginProcessParent::errorState(void)
 153{
 154	if(mState < STATE_RUNNING)
 155		setState(STATE_LAUNCH_FAILURE);
 156	else
 157		setState(STATE_ERROR);
 158}
 159
 160void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug)
 161{	
 162	mProcess.setExecutable(launcher_filename);
 163	mProcess.setWorkingDirectory(plugin_dir);
 164	mPluginFile = plugin_filename;
 165	mPluginDir = plugin_dir;
 166	mCPUUsage = 0.0f;
 167	mDebug = debug;	
 168	setState(STATE_INITIALIZED);
 169}
 170
 171bool LLPluginProcessParent::accept()
 172{
 173	bool result = false;
 174	
 175	apr_status_t status = APR_EGENERAL;
 176	apr_socket_t *new_socket = NULL;
 177	
 178	status = apr_socket_accept(
 179		&new_socket,
 180		mListenSocket->getSocket(),
 181		gAPRPoolp);
 182
 183	
 184	if(status == APR_SUCCESS)
 185	{
 186//		llinfos << "SUCCESS" << llendl;
 187		// Success.  Create a message pipe on the new socket
 188
 189		// we MUST create a new pool for the LLSocket, since it will take ownership of it and delete it in its destructor!
 190		apr_pool_t* new_pool = NULL;
 191		status = apr_pool_create(&new_pool, gAPRPoolp);
 192
 193		mSocket = LLSocket::create(new_socket, new_pool);
 194		new LLPluginMessagePipe(this, mSocket);
 195
 196		result = true;
 197	}
 198	else if(APR_STATUS_IS_EAGAIN(status))
 199	{
 200//		llinfos << "EAGAIN" << llendl;
 201
 202		// No incoming connections.  This is not an error.
 203		status = APR_SUCCESS;
 204	}
 205	else
 206	{
 207//		llinfos << "Error:" << llendl;
 208		ll_apr_warn_status(status);
 209		
 210		// Some other error.
 211		errorState();
 212	}
 213	
 214	return result;	
 215}
 216
 217void LLPluginProcessParent::idle(void)
 218{
 219	bool idle_again;
 220
 221	do
 222	{
 223		// process queued messages
 224		mIncomingQueueMutex.lock();
 225		while(!mIncomingQueue.empty())
 226		{
 227			LLPluginMessage message = mIncomingQueue.front();
 228			mIncomingQueue.pop();
 229			mIncomingQueueMutex.unlock();
 230				
 231			receiveMessage(message);
 232			
 233			mIncomingQueueMutex.lock();
 234		}
 235
 236		mIncomingQueueMutex.unlock();
 237		
 238		// Give time to network processing
 239		if(mMessagePipe)
 240		{
 241			// Drain any queued outgoing messages
 242			mMessagePipe->pumpOutput();
 243			
 244			// Only do input processing here if this instance isn't in a pollset.
 245			if(!mPolledInput)
 246			{
 247				mMessagePipe->pumpInput();
 248			}
 249		}
 250		
 251		if(mState <= STATE_RUNNING)
 252		{
 253			if(APR_STATUS_IS_EOF(mSocketError))
 254			{
 255				// Plugin socket was closed.  This covers both normal plugin termination and plugin crashes.
 256				errorState();
 257			}
 258			else if(mSocketError != APR_SUCCESS)
 259			{
 260				// The socket is in an error state -- the plugin is gone.
 261				LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL;
 262				errorState();
 263			}
 264		}	
 265		
 266		// If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState().
 267		// USE THIS CAREFULLY, since it can starve other code.  Specifically make sure there's no way to get into a closed cycle and never return.
 268		// When in doubt, don't do it.
 269		idle_again = false;
 270		switch(mState)
 271		{
 272			case STATE_UNINITIALIZED:
 273			break;
 274
 275			case STATE_INITIALIZED:
 276			{
 277	
 278				apr_status_t status = APR_SUCCESS;
 279				apr_sockaddr_t* addr = NULL;
 280				mListenSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
 281				mBoundPort = 0;
 282				
 283				// This code is based on parts of LLSocket::create() in lliosocket.cpp.
 284				
 285				status = apr_sockaddr_info_get(
 286					&addr,
 287					"127.0.0.1",
 288					APR_INET,
 289					0,	// port 0 = ephemeral ("find me a port")
 290					0,
 291					gAPRPoolp);
 292					
 293				if(ll_apr_warn_status(status))
 294				{
 295					killSockets();
 296					errorState();
 297					break;
 298				}
 299
 300				// This allows us to reuse the address on quick down/up. This is unlikely to create problems.
 301				ll_apr_warn_status(apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_REUSEADDR, 1));
 302				
 303				status = apr_socket_bind(mListenSocket->getSocket(), addr);
 304				if(ll_apr_warn_status(status))
 305				{
 306					killSockets();
 307					errorState();
 308					break;
 309				}
 310
 311				// Get the actual port the socket was bound to
 312				{
 313					apr_sockaddr_t* bound_addr = NULL;
 314					if(ll_apr_warn_status(apr_socket_addr_get(&bound_addr, APR_LOCAL, mListenSocket->getSocket())))
 315					{
 316						killSockets();
 317						errorState();
 318						break;
 319					}
 320					mBoundPort = bound_addr->port;	
 321
 322					if(mBoundPort == 0)
 323					{
 324						LL_WARNS("Plugin") << "Bound port number unknown, bailing out." << LL_ENDL;
 325						
 326						killSockets();
 327						errorState();
 328						break;
 329					}
 330				}
 331				
 332				LL_DEBUGS("Plugin") << "Bound tcp socket to port: " << addr->port << LL_ENDL;
 333
 334				// Make the listen socket non-blocking
 335				status = apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_NONBLOCK, 1);
 336				if(ll_apr_warn_status(status))
 337				{
 338					killSockets();
 339					errorState();
 340					break;
 341				}
 342
 343				apr_socket_timeout_set(mListenSocket->getSocket(), 0);
 344				if(ll_apr_warn_status(status))
 345				{
 346					killSockets();
 347					errorState();
 348					break;
 349				}
 350				
 351				// If it's a stream based socket, we need to tell the OS
 352				// to keep a queue of incoming connections for ACCEPT.
 353				status = apr_socket_listen(
 354					mListenSocket->getSocket(),
 355					10); // FIXME: Magic number for queue size
 356					
 357				if(ll_apr_warn_status(status))
 358				{
 359					killSockets();
 360					errorState();
 361					break;
 362				}
 363				
 364				// If we got here, we're listening.
 365				setState(STATE_LISTENING);
 366			}
 367			break;
 368			
 369			case STATE_LISTENING:
 370			{
 371				// Launch the plugin process.
 372				
 373				// Only argument to the launcher is the port number we're listening on
 374				std::stringstream stream;
 375				stream << mBoundPort;
 376				mProcess.addArgument(stream.str());
 377				if(mProcess.launch() != 0)
 378				{
 379					errorState();
 380				}
 381				else
 382				{
 383					if(mDebug)
 384					{
 385						#if LL_DARWIN
 386						// If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue.
 387						
 388						// The command we're constructing would look like this on the command line:
 389						// osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell'
 390
 391						std::stringstream cmd;
 392						
 393						mDebugger.setExecutable("/usr/bin/osascript");
 394						mDebugger.addArgument("-e");
 395						mDebugger.addArgument("tell application \"Terminal\"");
 396						mDebugger.addArgument("-e");
 397						cmd << "set win to do script \"gdb -pid " << mProcess.getProcessID() << "\"";
 398						mDebugger.addArgument(cmd.str());
 399						mDebugger.addArgument("-e");
 400						mDebugger.addArgument("do script \"continue\" in win");
 401						mDebugger.addArgument("-e");
 402						mDebugger.addArgument("end tell");
 403						mDebugger.launch();
 404
 405						#endif
 406					}
 407					
 408					// This will allow us to time out if the process never starts.
 409					mHeartbeat.start();
 410					mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout);
 411					setState(STATE_LAUNCHED);
 412				}
 413			}
 414			break;
 415
 416			case STATE_LAUNCHED:
 417				// waiting for the plugin to connect
 418				if(pluginLockedUpOrQuit())
 419				{
 420					errorState();
 421				}
 422				else
 423				{
 424					// Check for the incoming connection.
 425					if(accept())
 426					{
 427						// Stop listening on the server port
 428						mListenSocket.reset();
 429						setState(STATE_CONNECTED);
 430					}
 431				}
 432			break;
 433			
 434			case STATE_CONNECTED:
 435				// waiting for hello message from the plugin
 436
 437				if(pluginLockedUpOrQuit())
 438				{
 439					errorState();
 440				}
 441			break;
 442
 443			case STATE_HELLO:
 444				LL_DEBUGS("Plugin") << "received hello message" << LL_ENDL;
 445				
 446				// Send the message to load the plugin
 447				{
 448					LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin");
 449					message.setValue("file", mPluginFile);
 450					message.setValue("dir", mPluginDir);
 451					sendMessage(message);
 452				}
 453
 454				setState(STATE_LOADING);
 455			break;
 456			
 457			case STATE_LOADING:
 458				// The load_plugin_response message will kick us from here into STATE_RUNNING
 459				if(pluginLockedUpOrQuit())
 460				{
 461					errorState();
 462				}
 463			break;
 464			
 465			case STATE_RUNNING:
 466				if(pluginLockedUpOrQuit())
 467				{
 468					errorState();
 469				}
 470			break;
 471			
 472			case STATE_EXITING:
 473				if(!mProcess.isRunning())
 474				{
 475					setState(STATE_CLEANUP);
 476				}
 477				else if(pluginLockedUp())
 478				{
 479					LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << LL_ENDL;
 480					errorState();
 481				}
 482			break;
 483
 484			case STATE_LAUNCH_FAILURE:
 485				if(mOwner != NULL)
 486				{
 487					mOwner->pluginLaunchFailed();
 488				}
 489				setState(STATE_CLEANUP);
 490			break;
 491
 492			case STATE_ERROR:
 493				if(mOwner != NULL)
 494				{
 495					mOwner->pluginDied();
 496				}
 497				setState(STATE_CLEANUP);
 498			break;
 499			
 500			case STATE_CLEANUP:
 501				mProcess.kill();
 502				killSockets();
 503				setState(STATE_DONE);
 504			break;
 505			
 506			
 507			case STATE_DONE:
 508				// just sit here.
 509			break;
 510			
 511		}
 512	
 513	} while (idle_again);
 514}
 515
 516bool LLPluginProcessParent::isLoading(void)
 517{
 518	bool result = false;
 519	
 520	if(mState <= STATE_LOADING)
 521		result = true;
 522		
 523	return result;
 524}
 525
 526bool LLPluginProcessParent::isRunning(void)
 527{
 528	bool result = false;
 529	
 530	if(mState == STATE_RUNNING)
 531		result = true;
 532		
 533	return result;
 534}
 535
 536bool LLPluginProcessParent::isDone(void)
 537{
 538	bool result = false;
 539	
 540	if(mState == STATE_DONE)
 541		result = true;
 542		
 543	return result;
 544}
 545
 546void LLPluginProcessParent::setSleepTime(F64 sleep_time, bool force_send)
 547{
 548	if(force_send || (sleep_time != mSleepTime))
 549	{
 550		// Cache the time locally
 551		mSleepTime = sleep_time;
 552		
 553		if(canSendMessage())
 554		{
 555			// and send to the plugin.
 556			LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "sleep_time");
 557			message.setValueReal("time", mSleepTime);
 558			sendMessage(message);
 559		}
 560		else
 561		{
 562			// Too early to send -- the load_plugin_response message will trigger us to send mSleepTime later.
 563		}
 564	}
 565}
 566
 567void LLPluginProcessParent::sendMessage(const LLPluginMessage &message)
 568{
 569	if(message.hasValue("blocking_response"))
 570	{
 571		mBlocked = false;
 572
 573		// reset the heartbeat timer, since there will have been no heartbeats while the plugin was blocked.
 574		mHeartbeat.setTimerExpirySec(mPluginLockupTimeout);
 575	}
 576	
 577	std::string buffer = message.generate();
 578	LL_DEBUGS("Plugin") << "Sending: " << buffer << LL_ENDL;	
 579	writeMessageRaw(buffer);
 580	
 581	// Try to send message immediately.
 582	if(mMessagePipe)
 583	{
 584		mMessagePipe->pumpOutput();
 585	}
 586}
 587
 588//virtual 
 589void LLPluginProcessParent::setMessagePipe(LLPluginMessagePipe *message_pipe)
 590{
 591	bool update_pollset = false;
 592	
 593	if(mMessagePipe)
 594	{
 595		// Unsetting an existing message pipe -- remove from the pollset		
 596		mPollFD.client_data = NULL;
 597
 598		// pollset needs an update
 599		update_pollset = true;
 600	}
 601	if(message_pipe != NULL)
 602	{
 603		// Set up the apr_pollfd_t
 604		mPollFD.p = gAPRPoolp;
 605		mPollFD.desc_type = APR_POLL_SOCKET;
 606		mPollFD.reqevents = APR_POLLIN|APR_POLLERR|APR_POLLHUP;
 607		mPollFD.rtnevents = 0;
 608		mPollFD.desc.s = mSocket->getSocket();
 609		mPollFD.client_data = (void*)this;	
 610		
 611		// pollset needs an update
 612		update_pollset = true;
 613	}
 614
 615	mMessagePipe = message_pipe;
 616	
 617	if(update_pollset)
 618	{
 619		dirtyPollSet();
 620	}
 621}
 622
 623//static 
 624void LLPluginProcessParent::dirtyPollSet()
 625{
 626	sPollsetNeedsRebuild = true;
 627	
 628	if(sReadThread)
 629	{
 630		LL_DEBUGS("PluginPoll") << "unpausing read thread " << LL_ENDL;
 631		sReadThread->unpause();
 632	}
 633}
 634
 635void LLPluginProcessParent::updatePollset()
 636{
 637	if(!sInstancesMutex)
 638	{
 639		// No instances have been created yet.  There's no work to do.
 640		return;
 641	}
 642		
 643	LLMutexLock lock(sInstancesMutex);
 644
 645	if(sPollSet)
 646	{
 647		LL_DEBUGS("PluginPoll") << "destroying pollset " << sPollSet << LL_ENDL;
 648		// delete the existing pollset.
 649		apr_pollset_destroy(sPollSet);
 650		sPollSet = NULL;
 651	}
 652	
 653	std::list<LLPluginProcessParent*>::iterator iter;
 654	int count = 0;
 655	
 656	// Count the number of instances that want to be in the pollset
 657	for(iter = sInstances.begin(); iter != sInstances.end(); iter++)
 658	{
 659		(*iter)->mPolledInput = false;
 660		if((*iter)->mPollFD.client_data)
 661		{
 662			// This instance has a socket that needs to be polled.
 663			++count;
 664		}
 665	}
 666
 667	if(sUseReadThread && sReadThread && !sReadThread->isQuitting())
 668	{
 669		if(!sPollSet && (count > 0))
 670		{
 671#ifdef APR_POLLSET_NOCOPY
 672			// The pollset doesn't exist yet.  Create it now.
 673			apr_status_t status = apr_pollset_create(&sPollSet, count, gAPRPoolp, APR_POLLSET_NOCOPY);
 674			if(status != APR_SUCCESS)
 675			{
 676#endif // APR_POLLSET_NOCOPY
 677				LL_WARNS("PluginPoll") << "Couldn't create pollset.  Falling back to non-pollset mode." << LL_ENDL;
 678				sPollSet = NULL;
 679#ifdef APR_POLLSET_NOCOPY
 680			}
 681			else
 682			{
 683				LL_DEBUGS("PluginPoll") << "created pollset " << sPollSet << LL_ENDL;
 684				
 685				// Pollset was created, add all instances to it.
 686				for(iter = sInstances.begin(); iter != sInstances.end(); iter++)
 687				{
 688					if((*iter)->mPollFD.client_data)
 689					{
 690						status = apr_pollset_add(sPollSet, &((*iter)->mPollFD));
 691						if(status == APR_SUCCESS)
 692						{
 693							(*iter)->mPolledInput = true;
 694						}
 695						else
 696						{
 697							LL_WARNS("PluginPoll") << "apr_pollset_add failed with status " << status << LL_ENDL;
 698						}
 699					}
 700				}
 701			}
 702#endif // APR_POLLSET_NOCOPY
 703		}
 704	}
 705}
 706
 707void LLPluginProcessParent::setUseReadThread(bool use_read_thread)
 708{
 709	if(sUseReadThread != use_read_thread)
 710	{
 711		sUseReadThread = use_read_thread;
 712		
 713		if(sUseReadThread)
 714		{
 715			if(!sReadThread)
 716			{
 717				// start up the read thread
 718				LL_INFOS("PluginPoll") << "creating read thread " << LL_ENDL;
 719
 720				// make sure the pollset gets rebuilt.
 721				sPollsetNeedsRebuild = true;
 722				
 723				sReadThread = new LLPluginProcessParentPollThread;
 724				sReadThread->start();
 725			}
 726		}
 727		else
 728		{
 729			if(sReadThread)
 730			{
 731				// shut down the read thread
 732				LL_INFOS("PluginPoll") << "destroying read thread " << LL_ENDL;
 733				delete sReadThread;
 734				sReadThread = NULL;
 735			}
 736		}
 737
 738	}
 739}
 740
 741void LLPluginProcessParent::poll(F64 timeout)
 742{
 743	if(sPollsetNeedsRebuild || !sUseReadThread)
 744	{
 745		sPollsetNeedsRebuild = false;
 746		updatePollset();
 747	}
 748	
 749	if(sPollSet)
 750	{
 751		apr_status_t status;
 752		apr_int32_t count;
 753		const apr_pollfd_t *descriptors;
 754		status = apr_pollset_poll(sPollSet, (apr_interval_time_t)(timeout * 1000000), &count, &descriptors);
 755		if(status == APR_SUCCESS)
 756		{
 757			// One or more of the descriptors signalled.  Call them.
 758			for(int i = 0; i < count; i++)
 759			{
 760				LLPluginProcessParent *self = (LLPluginProcessParent *)(descriptors[i].client_data);
 761				// NOTE: the descriptor returned here is actually a COPY of the original (even though we create the pollset with APR_POLLSET_NOCOPY).
 762				// This means that even if the parent has set its mPollFD.client_data to NULL, the old pointer may still there in this descriptor.
 763				// It's even possible that the old pointer no longer points to a valid LLPluginProcessParent.
 764				// This means that we can't safely dereference the 'self' pointer here without some extra steps...
 765				if(self)
 766				{
 767					// Make sure this pointer is still in the instances list
 768					bool valid = false;
 769					{
 770						LLMutexLock lock(sInstancesMutex);
 771						for(std::list<LLPluginProcessParent*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
 772						{
 773							if(*iter == self)
 774							{
 775								// Lock the instance's mutex before unlocking the global mutex.  
 776								// This avoids a possible race condition where the instance gets deleted between this check and the servicePoll() call.
 777								self->mIncomingQueueMutex.lock();
 778								valid = true;
 779								break;
 780							}
 781						}
 782					}
 783					
 784					if(valid)
 785					{
 786						// The instance is still valid.
 787						// Pull incoming messages off the socket
 788						self->servicePoll();
 789						self->mIncomingQueueMutex.unlock();
 790					}
 791					else
 792					{
 793						LL_DEBUGS("PluginPoll") << "detected deleted instance " << self << LL_ENDL;
 794					}
 795
 796				}
 797			}
 798		}
 799		else if(APR_STATUS_IS_TIMEUP(status))
 800		{
 801			// timed out with no incoming data.  Just return.
 802		}
 803		else if(status == EBADF)
 804		{
 805			// This happens when one of the file descriptors in the pollset is destroyed, which happens whenever a plugin's socket is closed.
 806			// The pollset has been or will be recreated, so just return.
 807			LL_DEBUGS("PluginPoll") << "apr_pollset_poll returned EBADF" << LL_ENDL;
 808		}
 809		else if(status != APR_SUCCESS)
 810		{
 811			LL_WARNS("PluginPoll") << "apr_pollset_poll failed with status " << status << LL_ENDL;
 812		}
 813	}
 814}
 815
 816void LLPluginProcessParent::servicePoll()
 817{
 818	bool result = true;
 819	
 820	// poll signalled on this object's socket.  Try to process incoming messages.
 821	if(mMessagePipe)
 822	{
 823		result = mMessagePipe->pumpInput(0.0f);
 824	}
 825
 826	if(!result)
 827	{
 828		// If we got a read error on input, remove this pipe from the pollset
 829		apr_pollset_remove(sPollSet, &mPollFD);
 830
 831		// and tell the code not to re-add it
 832		mPollFD.client_data = NULL;
 833	}
 834}
 835
 836void LLPluginProcessParent::receiveMessageRaw(const std::string &message)
 837{
 838	LL_DEBUGS("Plugin") << "Received: " << message << LL_ENDL;
 839	
 840	LLPluginMessage parsed;
 841	if(parsed.parse(message) != -1)
 842	{
 843		if(parsed.hasValue("blocking_request"))
 844		{
 845			mBlocked = true;
 846		}
 847
 848		if(mPolledInput)
 849		{
 850			// This is being called on the polling thread -- only do minimal processing/queueing.
 851			receiveMessageEarly(parsed);
 852		}
 853		else
 854		{
 855			// This is not being called on the polling thread -- do full message processing at this time.
 856			receiveMessage(parsed);
 857		}
 858	}
 859}
 860
 861void LLPluginProcessParent::receiveMessageEarly(const LLPluginMessage &message)
 862{
 863	// NOTE: this function will be called from the polling thread.  It will be called with mIncomingQueueMutex _already locked_. 
 864
 865	bool handled = false;
 866	
 867	std::string message_class = message.getClass();
 868	if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL)
 869	{
 870		// no internal messages need to be handled early.
 871	}
 872	else
 873	{
 874		// Call out to the owner and see if they to reply
 875		// TODO: Should this only happen when blocked?
 876		if(mOwner != NULL)
 877		{
 878			handled = mOwner->receivePluginMessageEarly(message);
 879		}
 880	}
 881	
 882	if(!handled)
 883	{
 884		// any message that wasn't handled early needs to be queued.
 885		mIncomingQueue.push(message);
 886	}
 887}
 888
 889void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message)
 890{
 891	std::string message_class = message.getClass();
 892	if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL)
 893	{
 894		// internal messages should be handled here
 895		std::string message_name = message.getName();
 896		if(message_name == "hello")
 897		{
 898			if(mState == STATE_CONNECTED)
 899			{
 900				// Plugin host has launched.  Tell it which plugin to load.
 901				setState(STATE_HELLO);
 902			}
 903			else
 904			{
 905				LL_WARNS("Plugin") << "received hello message in wrong state -- bailing out" << LL_ENDL;
 906				errorState();
 907			}
 908			
 909		}
 910		else if(message_name == "load_plugin_response")
 911		{
 912			if(mState == STATE_LOADING)
 913			{
 914				// Plugin has been loaded. 
 915				
 916				mPluginVersionString = message.getValue("plugin_version");
 917				LL_INFOS("Plugin") << "plugin version string: " << mPluginVersionString << LL_ENDL;
 918
 919				// Check which message classes/versions the plugin supports.
 920				// TODO: check against current versions
 921				// TODO: kill plugin on major mismatches?
 922				mMessageClassVersions = message.getValueLLSD("versions");
 923				LLSD::map_iterator iter;
 924				for(iter = mMessageClassVersions.beginMap(); iter != mMessageClassVersions.endMap(); iter++)
 925				{
 926					LL_INFOS("Plugin") << "message class: " << iter->first << " -> version: " << iter->second.asString() << LL_ENDL;
 927				}
 928				
 929				// Send initial sleep time
 930				llassert_always(mSleepTime != 0.f);
 931				setSleepTime(mSleepTime, true);			
 932
 933				setState(STATE_RUNNING);
 934			}
 935			else
 936			{
 937				LL_WARNS("Plugin") << "received load_plugin_response message in wrong state -- bailing out" << LL_ENDL;
 938				errorState();
 939			}
 940		}
 941		else if(message_name == "heartbeat")
 942		{
 943			// this resets our timer.
 944			mHeartbeat.setTimerExpirySec(mPluginLockupTimeout);
 945
 946			mCPUUsage = message.getValueReal("cpu_usage");
 947
 948			LL_DEBUGS("Plugin") << "cpu usage reported as " << mCPUUsage << LL_ENDL;
 949			
 950		}
 951		else if(message_name == "shm_add_response")
 952		{
 953			// Nothing to do here.
 954		}
 955		else if(message_name == "shm_remove_response")
 956		{
 957			std::string name = message.getValue("name");
 958			sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
 959			
 960			if(iter != mSharedMemoryRegions.end())
 961			{
 962				// destroy the shared memory region
 963				iter->second->destroy();
 964				
 965				// and remove it from our map
 966				mSharedMemoryRegions.erase(iter);
 967			}
 968		}
 969		else
 970		{
 971			LL_WARNS("Plugin") << "Unknown internal message from child: " << message_name << LL_ENDL;
 972		}
 973	}
 974	else
 975	{
 976		if(mOwner != NULL)
 977		{
 978			mOwner->receivePluginMessage(message);
 979		}
 980	}
 981}
 982
 983std::string LLPluginProcessParent::addSharedMemory(size_t size)
 984{
 985	std::string name;
 986	
 987	LLPluginSharedMemory *region = new LLPluginSharedMemory;
 988
 989	// This is a new region
 990	if(region->create(size))
 991	{
 992		name = region->getName();
 993		
 994		mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region));
 995		
 996		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_add");
 997		message.setValue("name", name);
 998		message.setValueS32("size", (S32)size);
 999		sendMessage(message);
1000	}
1001	else
1002	{
1003		LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL;
1004
1005		// Don't leak
1006		delete region;
1007	}
1008
1009	return name;
1010}
1011
1012void LLPluginProcessParent::removeSharedMemory(const std::string &name)
1013{
1014	sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
1015	
1016	if(iter != mSharedMemoryRegions.end())
1017	{
1018		// This segment exists.  Send the message to the child to unmap it.  The response will cause the parent to unmap our end.
1019		LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove");
1020		message.setValue("name", name);
1021		sendMessage(message);
1022	}
1023	else
1024	{
1025		LL_WARNS("Plugin") << "Request to remove an unknown shared memory segment." << LL_ENDL;
1026	}
1027}
1028size_t LLPluginProcessParent::getSharedMemorySize(const std::string &name)
1029{
1030	size_t result = 0;
1031	
1032	sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
1033	if(iter != mSharedMemoryRegions.end())
1034	{
1035		result = iter->second->getSize();
1036	}
1037	
1038	return result;
1039}
1040void *LLPluginProcessParent::getSharedMemoryAddress(const std::string &name)
1041{
1042	void *result = NULL;
1043	
1044	sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name);
1045	if(iter != mSharedMemoryRegions.end())
1046	{
1047		result = iter->second->getMappedAddress();
1048	}
1049	
1050	return result;
1051}
1052
1053std::string LLPluginProcessParent::getMessageClassVersion(const std::string &message_class)
1054{
1055	std::string result;
1056	
1057	if(mMessageClassVersions.has(message_class))
1058	{
1059		result = mMessageClassVersions[message_class].asString();
1060	}
1061	
1062	return result;
1063}
1064
1065std::string LLPluginProcessParent::getPluginVersion(void)
1066{
1067	return mPluginVersionString;
1068}
1069
1070void LLPluginProcessParent::setState(EState state)
1071{
1072	LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL;
1073	mState = state; 
1074};
1075
1076bool LLPluginProcessParent::pluginLockedUpOrQuit()
1077{
1078	bool result = false;
1079	
1080	if(!mProcess.isRunning())
1081	{
1082		LL_WARNS("Plugin") << "child exited" << LL_ENDL;
1083		result = true;
1084	}
1085	else if(pluginLockedUp())
1086	{
1087		LL_WARNS("Plugin") << "timeout" << LL_ENDL;
1088		result = true;
1089	}
1090	
1091	return result;
1092}
1093
1094bool LLPluginProcessParent::pluginLockedUp()
1095{
1096	if(mDisableTimeout || mDebug || mBlocked)
1097	{
1098		// Never time out a plugin process in these cases.
1099		return false;
1100	}
1101	
1102	// If the timer is running and has expired, the plugin has locked up.
1103	return (mHeartbeat.getStarted() && mHeartbeat.hasExpired());
1104}
1105