summaryrefslogtreecommitdiff
path: root/indra/llplugin
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llplugin')
-rw-r--r--indra/llplugin/CMakeLists.txt3
-rw-r--r--indra/llplugin/llpluginclassmedia.cpp279
-rw-r--r--indra/llplugin/llpluginclassmedia.h11
-rw-r--r--indra/llplugin/llpluginclassmediaowner.h2
-rw-r--r--indra/llplugin/llpluginprocesschild.cpp43
-rw-r--r--indra/llplugin/llpluginprocesschild.h7
-rw-r--r--indra/llplugin/llpluginprocessparent.cpp308
-rw-r--r--indra/llplugin/llpluginprocessparent.h28
-rw-r--r--indra/llplugin/slplugin/slplugin.cpp1
9 files changed, 415 insertions, 267 deletions
diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt
index 05fc12e338..8c4ddd524e 100644
--- a/indra/llplugin/CMakeLists.txt
+++ b/indra/llplugin/CMakeLists.txt
@@ -20,7 +20,6 @@ include_directories(
${LLRENDER_INCLUDE_DIRS}
${LLXML_INCLUDE_DIRS}
${LLWINDOW_INCLUDE_DIRS}
- ${LLQTWEBKIT_INCLUDE_DIR}
)
include_directories(SYSTEM
${LLCOMMON_SYSTEM_INCLUDE_DIRS}
@@ -68,7 +67,7 @@ list(APPEND llplugin_SOURCE_FILES ${llplugin_HEADER_FILES})
add_library (llplugin ${llplugin_SOURCE_FILES})
-##add_subdirectory(slplugin)
+add_subdirectory(slplugin)
# Add tests
if (LL_TESTS)
diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp
index 4bfd0de81e..3d173d0459 100644
--- a/indra/llplugin/llpluginclassmedia.cpp
+++ b/indra/llplugin/llpluginclassmedia.cpp
@@ -1,4 +1,4 @@
-/**
+/**
* @file llpluginclassmedia.cpp
* @brief LLPluginClassMedia handles a plugin which knows about the "media" message class.
*
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
- *
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
+ *
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
* @endcond
@@ -41,14 +41,13 @@ static int nextPowerOf2( int value )
{
next_power_of_2 <<= 1;
}
-
+
return next_power_of_2;
}
LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner)
{
mOwner = owner;
- mPlugin = NULL;
reset();
//debug use
@@ -63,19 +62,19 @@ LLPluginClassMedia::~LLPluginClassMedia()
}
bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_dir, const std::string &plugin_filename, bool debug)
-{
+{
LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL;
LL_DEBUGS("Plugin") << "dir: " << plugin_dir << LL_ENDL;
LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL;
-
- mPlugin = new LLPluginProcessParent(this);
+
+ mPlugin = LLPluginProcessParent::create(this);
mPlugin->setSleepTime(mSleepTime);
-
+
// Queue up the media init message -- it will be sent after all the currently queued messages.
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "init");
message.setValue("target", mTarget);
sendMessage(message);
-
+
mPlugin->init(launcher_filename, plugin_dir, plugin_filename, debug);
return true;
@@ -84,10 +83,10 @@ bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::s
void LLPluginClassMedia::reset()
{
- if(mPlugin != NULL)
+ if(mPlugin)
{
- delete mPlugin;
- mPlugin = NULL;
+ mPlugin->requestShutdown();
+ mPlugin.reset();
}
mTextureParamsReceived = false;
@@ -115,7 +114,7 @@ void LLPluginClassMedia::reset()
mTextureHeight = 0;
mMediaWidth = 0;
mMediaHeight = 0;
- mDirtyRect = LLRect::null;
+ mDirtyRect = LLRect::null;
mAutoScaleMedia = false;
mRequestedVolume = 1.0f;
mPriority = PRIORITY_NORMAL;
@@ -132,7 +131,7 @@ void LLPluginClassMedia::reset()
mMediaName.clear();
mMediaDescription.clear();
mBackgroundColor = LLColor4(1.0f, 1.0f, 1.0f, 1.0f);
-
+
// media_browser class
mNavigateURI.clear();
mNavigateResultCode = -1;
@@ -140,7 +139,7 @@ void LLPluginClassMedia::reset()
mHistoryBackAvailable = false;
mHistoryForwardAvailable = false;
mStatusText.clear();
- mProgressPercent = 0;
+ mProgressPercent = 0;
mClickURL.clear();
mClickNavType.clear();
mClickTarget.clear();
@@ -148,7 +147,7 @@ void LLPluginClassMedia::reset()
mStatusCode = 0;
mClickEnforceTarget = false;
-
+
// media_time class
mCurrentTime = 0.0f;
mDuration = 0.0f;
@@ -162,7 +161,7 @@ void LLPluginClassMedia::idle(void)
{
mPlugin->idle();
}
-
+
if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL) || (mPlugin->isBlocked()) || (mOwner == NULL))
{
// Can't process a size change at this time
@@ -179,7 +178,7 @@ void LLPluginClassMedia::idle(void)
else
{
mRequestedTextureWidth = mRequestedMediaWidth;
-
+
if(mPadding > 1)
{
// Pad up to a multiple of the specified number of bytes per row
@@ -189,7 +188,7 @@ void LLPluginClassMedia::idle(void)
{
rowbytes += mPadding - pad;
}
-
+
if(rowbytes % mRequestedTextureDepth == 0)
{
mRequestedTextureWidth = rowbytes / mRequestedTextureDepth;
@@ -201,7 +200,7 @@ void LLPluginClassMedia::idle(void)
}
}
-
+
// Size change has been requested but not initiated yet.
size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth;
@@ -216,22 +215,22 @@ void LLPluginClassMedia::idle(void)
mPlugin->removeSharedMemory(mTextureSharedMemoryName);
mTextureSharedMemoryName.clear();
}
-
+
mTextureSharedMemorySize = newsize;
mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize);
if(!mTextureSharedMemoryName.empty())
{
void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName);
-
+
// clear texture memory to avoid random screen visual fuzz from uninitialized texture data
memset( addr, 0x00, newsize );
-
+
// We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin,
// so it may not be worthwhile.
// mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight);
}
}
-
+
// This is our local indicator that a change is in progress.
mTextureWidth = -1;
mTextureHeight = -1;
@@ -240,7 +239,7 @@ void LLPluginClassMedia::idle(void)
// This invalidates any existing dirty rect.
resetDirty();
-
+
// Send a size change message to the plugin
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change");
@@ -254,11 +253,11 @@ void LLPluginClassMedia::idle(void)
message.setValueReal("background_b", mBackgroundColor.mV[VZ]);
message.setValueReal("background_a", mBackgroundColor.mV[VW]);
mPlugin->sendMessage(message); // DO NOT just use sendMessage() here -- we want this to jump ahead of the queue.
-
+
LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL;
}
}
-
+
if(mPlugin && mPlugin->isRunning())
{
// Send queued messages
@@ -324,11 +323,11 @@ void LLPluginClassMedia::setSizeInternal(void)
mRequestedMediaWidth = mDefaultMediaWidth;
mRequestedMediaHeight = mDefaultMediaHeight;
}
-
+
// Save these for size/interest calculations
mFullMediaWidth = mRequestedMediaWidth;
mFullMediaHeight = mRequestedMediaHeight;
-
+
if(mAllowDownsample)
{
switch(mPriority)
@@ -342,19 +341,19 @@ void LLPluginClassMedia::setSizeInternal(void)
mRequestedMediaHeight /= 2;
}
break;
-
+
default:
// Don't adjust texture size
break;
}
}
-
+
if(mAutoScaleMedia)
{
mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth);
mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight);
}
-
+
if(mRequestedMediaWidth > 2048)
mRequestedMediaWidth = 2048;
@@ -382,9 +381,9 @@ bool LLPluginClassMedia::textureValid(void)
mRequestedMediaWidth != mMediaWidth ||
mRequestedMediaHeight != mMediaHeight ||
getBitsData() == NULL
- )
+ )
return false;
-
+
return true;
}
@@ -408,8 +407,8 @@ void LLPluginClassMedia::resetDirty(void)
std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
{
std::string result;
-
-
+
+
if(modifiers & MASK_CONTROL)
{
result += "control|";
@@ -432,7 +431,7 @@ std::string LLPluginClassMedia::translateModifiers(MASK modifiers)
{
result += "meta|";
}
-*/
+*/
return result;
}
@@ -540,11 +539,11 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int
// Don't spam unnecessary mouse move events.
return;
}
-
+
mLastMouseX = x;
mLastMouseY = y;
}
-
+
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event");
std::string temp;
switch(type)
@@ -559,7 +558,7 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int
message.setValueS32("button", button);
message.setValueS32("x", x);
-
+
// Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it.
if(!mRequestedTextureCoordsOpenGL)
{
@@ -569,42 +568,42 @@ void LLPluginClassMedia::mouseEvent(EMouseEventType type, int button, int x, int
message.setValueS32("y", y);
message.setValue("modifiers", translateModifiers(modifiers));
-
+
sendMessage(message);
}
bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers, LLSD native_key_data)
{
bool result = true;
-
+
// FIXME:
// HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode.
// For now, return false for the ones the webkit plugin won't handle properly.
-
+
switch(key_code)
{
- case KEY_BACKSPACE:
- case KEY_TAB:
- case KEY_RETURN:
- case KEY_PAD_RETURN:
- case KEY_SHIFT:
- case KEY_CONTROL:
- case KEY_ALT:
- case KEY_CAPSLOCK:
- case KEY_ESCAPE:
- case KEY_PAGE_UP:
- case KEY_PAGE_DOWN:
- case KEY_END:
- case KEY_HOME:
- case KEY_LEFT:
- case KEY_UP:
- case KEY_RIGHT:
- case KEY_DOWN:
- case KEY_INSERT:
+ case KEY_BACKSPACE:
+ case KEY_TAB:
+ case KEY_RETURN:
+ case KEY_PAD_RETURN:
+ case KEY_SHIFT:
+ case KEY_CONTROL:
+ case KEY_ALT:
+ case KEY_CAPSLOCK:
+ case KEY_ESCAPE:
+ case KEY_PAGE_UP:
+ case KEY_PAGE_DOWN:
+ case KEY_END:
+ case KEY_HOME:
+ case KEY_LEFT:
+ case KEY_UP:
+ case KEY_RIGHT:
+ case KEY_DOWN:
+ case KEY_INSERT:
case KEY_DELETE:
- // These will be handled
+ // These will be handled
break;
-
+
default:
// regular ASCII characters will also be handled
if(key_code >= KEY_SPECIAL)
@@ -615,7 +614,7 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie
break;
}
-#if LL_DARWIN
+#if LL_DARWIN
if(modifiers & MASK_ALT)
{
// Option-key modified characters should be handled by the unicode input path instead of this one.
@@ -634,15 +633,15 @@ bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifie
case KEY_EVENT_REPEAT: temp = "repeat"; break;
}
message.setValue("event", temp);
-
+
message.setValueS32("key", key_code);
message.setValue("modifiers", translateModifiers(modifiers));
message.setValueLLSD("native_key_data", native_key_data);
-
+
sendMessage(message);
}
-
+
return result;
}
@@ -653,10 +652,10 @@ void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers)
message.setValueS32("x", x);
message.setValueS32("y", y);
message.setValue("modifiers", translateModifiers(modifiers));
-
+
sendMessage(message);
}
-
+
bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD native_key_data)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event");
@@ -664,18 +663,33 @@ bool LLPluginClassMedia::textInput(const std::string &text, MASK modifiers, LLSD
message.setValue("text", text);
message.setValue("modifiers", translateModifiers(modifiers));
message.setValueLLSD("native_key_data", native_key_data);
-
+
sendMessage(message);
-
+
return true;
}
+void LLPluginClassMedia::setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure)
+{
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_cookie");
+
+ message.setValue("uri", uri);
+ message.setValue("name", name);
+ message.setValue("value", value);
+ message.setValue("domain", domain);
+ message.setValue("path", path);
+ message.setValueBoolean("httponly", httponly);
+ message.setValueBoolean("secure", secure);
+
+ sendMessage(message);
+}
+
void LLPluginClassMedia::loadURI(const std::string &uri)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri");
message.setValue("uri", uri);
-
+
sendMessage(message);
}
@@ -692,7 +706,7 @@ const char* LLPluginClassMedia::priorityToString(EPriority priority)
case PRIORITY_NORMAL: result = "normal"; break;
case PRIORITY_HIGH: result = "high"; break;
}
-
+
return result;
}
@@ -703,44 +717,44 @@ void LLPluginClassMedia::setPriority(EPriority priority)
mPriority = priority;
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority");
-
+
std::string priority_string = priorityToString(priority);
switch(priority)
{
- case PRIORITY_UNLOADED:
+ case PRIORITY_UNLOADED:
mSleepTime = 1.0f;
break;
- case PRIORITY_STOPPED:
+ case PRIORITY_STOPPED:
mSleepTime = 1.0f;
break;
- case PRIORITY_HIDDEN:
+ case PRIORITY_HIDDEN:
mSleepTime = 1.0f;
break;
case PRIORITY_SLIDESHOW:
mSleepTime = 1.0f;
break;
- case PRIORITY_LOW:
+ case PRIORITY_LOW:
mSleepTime = 1.0f / 25.0f;
break;
- case PRIORITY_NORMAL:
+ case PRIORITY_NORMAL:
mSleepTime = 1.0f / 50.0f;
break;
- case PRIORITY_HIGH:
+ case PRIORITY_HIGH:
mSleepTime = 1.0f / 100.0f;
break;
}
-
+
message.setValue("priority", priority_string);
sendMessage(message);
-
+
if(mPlugin)
{
mPlugin->setSleepTime(mSleepTime);
}
-
+
LL_DEBUGS("PluginPriority") << this << ": setting priority to " << priority_string << LL_ENDL;
-
+
// This may affect the calculated size, so recalculate it here.
setSizeInternal();
}
@@ -761,12 +775,12 @@ void LLPluginClassMedia::setLowPrioritySizeLimit(int size)
F64 LLPluginClassMedia::getCPUUsage()
{
F64 result = 0.0f;
-
+
if(mPlugin)
{
result = mPlugin->getCPUUsage();
}
-
+
return result;
}
@@ -814,10 +828,11 @@ void LLPluginClassMedia::paste()
sendMessage(message);
}
-void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path)
+void LLPluginClassMedia::setUserDataPath(const std::string &user_data_path_cache, const std::string &user_data_path_cookies)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_user_data_path");
- message.setValue("path", user_data_path);
+ message.setValue("cache_path", user_data_path_cache);
+ message.setValue("cookies_path", user_data_path_cookies);
sendMessage(message);
}
@@ -830,14 +845,14 @@ void LLPluginClassMedia::setLanguageCode(const std::string &language_code)
void LLPluginClassMedia::setPluginsEnabled(const bool enabled)
{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "plugins_enabled");
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "plugins_enabled");
message.setValueBoolean("enable", enabled);
sendMessage(message);
}
void LLPluginClassMedia::setJavascriptEnabled(const bool enabled)
{
- LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "javascript_enabled");
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "javascript_enabled");
message.setValueBoolean("enable", enabled);
sendMessage(message);
}
@@ -855,11 +870,11 @@ void LLPluginClassMedia::setTarget(const std::string &target)
mTarget = target;
}
-/* virtual */
+/* virtual */
void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
{
std::string message_class = message.getClass();
-
+
if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA)
{
std::string message_name = message.getName();
@@ -870,21 +885,21 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mRequestedTextureFormat = message.getValueU32("format");
mRequestedTextureType = message.getValueU32("type");
mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes");
- mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");
-
+ mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl");
+
// These two are optional, and will default to 0 if they're not specified.
mDefaultMediaWidth = message.getValueS32("default_width");
mDefaultMediaHeight = message.getValueS32("default_height");
-
+
mAllowDownsample = message.getValueBoolean("allow_downsample");
mPadding = message.getValueS32("padding");
setSizeInternal();
-
+
mTextureParamsReceived = true;
}
else if(message_name == "updated")
- {
+ {
if(message.hasValue("left"))
{
LLRect newDirtyRect;
@@ -892,7 +907,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
newDirtyRect.mTop = message.getValueS32("top");
newDirtyRect.mRight = message.getValueS32("right");
newDirtyRect.mBottom = message.getValueS32("bottom");
-
+
// The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion.
// If they're backwards, swap them.
if(newDirtyRect.mTop < newDirtyRect.mBottom)
@@ -901,7 +916,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
newDirtyRect.mTop = newDirtyRect.mBottom;
newDirtyRect.mBottom = temp;
}
-
+
if(mDirtyRect.isEmpty())
{
mDirtyRect = newDirtyRect;
@@ -911,7 +926,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mDirtyRect.unionWith(newDirtyRect);
}
- LL_DEBUGS("Plugin") << "adjusted incoming rect is: ("
+ LL_DEBUGS("Plugin") << "adjusted incoming rect is: ("
<< newDirtyRect.mLeft << ", "
<< newDirtyRect.mTop << ", "
<< newDirtyRect.mRight << ", "
@@ -921,10 +936,10 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
<< mDirtyRect.mRight << ", "
<< mDirtyRect.mBottom << ")"
<< LL_ENDL;
-
+
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED);
- }
-
+ }
+
bool time_duration_updated = false;
int previous_percent = mProgressPercent;
@@ -944,7 +959,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
{
mCurrentRate = message.getValueReal("current_rate");
}
-
+
if(message.hasValue("loaded_duration"))
{
mLoadedDuration = message.getValueReal("loaded_duration");
@@ -955,7 +970,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
// If the message doesn't contain a loaded_duration param, assume it's equal to duration
mLoadedDuration = mDuration;
}
-
+
// Calculate a percentage based on the loaded duration and total duration.
if(mDuration != 0.0f) // Don't divide by zero.
{
@@ -966,7 +981,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
{
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED);
}
-
+
if(previous_percent != mProgressPercent)
{
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED);
@@ -975,9 +990,9 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
else if(message_name == "media_status")
{
std::string status = message.getValue("status");
-
+
LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL;
-
+
if(status == "loading")
{
mStatus = LLPluginClassMediaOwner::MEDIA_LOADING;
@@ -1017,24 +1032,24 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
// TODO: check that name matches?
mNaturalMediaWidth = width;
mNaturalMediaHeight = height;
-
+
setSizeInternal();
}
else if(message_name == "size_change_response")
{
std::string name = message.getValue("name");
-
+
// TODO: check that name matches?
-
+
mTextureWidth = message.getValueS32("texture_width");
mTextureHeight = message.getValueS32("texture_height");
mMediaWidth = message.getValueS32("width");
mMediaHeight = message.getValueS32("height");
-
+
// This invalidates any existing dirty rect.
resetDirty();
-
- // TODO: should we verify that the plugin sent back the right values?
+
+ // TODO: should we verify that the plugin sent back the right values?
// Two size changes in a row may cause them to not match, due to queueing, etc.
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED);
@@ -1075,6 +1090,11 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mAuthRealm = message.getValue("realm");
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_AUTH_REQUEST);
}
+ else if (message_name == "file_download")
+ {
+ mFileDownloadFilename = message.getValue("filename");
+ mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_FILE_DOWNLOAD);
+ }
else if(message_name == "debug_message")
{
mDebugMessageText = message.getValue("message_text");
@@ -1101,7 +1121,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mNavigateResultString = message.getValue("result_string");
mHistoryBackAvailable = message.getValueBoolean("history_back_available");
mHistoryForwardAvailable = message.getValueBoolean("history_forward_available");
-
+
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE);
}
else if(message_name == "progress")
@@ -1156,7 +1176,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mGeometryY = message.getValueS32("y");
mGeometryWidth = message.getValueS32("width");
mGeometryHeight = message.getValueS32("height");
-
+
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_GEOMETRY_CHANGE);
}
else if(message_name == "link_hovered")
@@ -1165,7 +1185,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
mHoverLink = message.getValue("link");
mHoverText = message.getValue("title");
// message.getValue("text");
-
+
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LINK_HOVERED);
}
else
@@ -1181,7 +1201,7 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
// if(message_name == "message_name")
// {
// }
-// else
+// else
{
LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL;
}
@@ -1189,13 +1209,13 @@ void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message)
}
-/* virtual */
+/* virtual */
void LLPluginClassMedia::pluginLaunchFailed()
{
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED_LAUNCH);
}
-/* virtual */
+/* virtual */
void LLPluginClassMedia::pluginDied()
{
mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED);
@@ -1235,7 +1255,7 @@ void LLPluginClassMedia::focus(bool focused)
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus");
message.setValueBoolean("focused", focused);
-
+
sendMessage(message);
}
@@ -1262,7 +1282,7 @@ void LLPluginClassMedia::clear_cookies()
void LLPluginClassMedia::set_cookies(const std::string &cookies)
{
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_cookies");
- message.setValue("cookies", cookies);
+ message.setValue("cookies", cookies);
sendMessage(message);
}
@@ -1295,7 +1315,7 @@ void LLPluginClassMedia::browse_reload(bool ignore_cache)
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload");
message.setValueBoolean("ignore_cache", ignore_cache);
-
+
sendMessage(message);
}
@@ -1415,7 +1435,7 @@ void LLPluginClassMedia::seek(float time)
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek");
message.setValueReal("time", time);
-
+
sendMessage(message);
}
@@ -1433,11 +1453,11 @@ void LLPluginClassMedia::setVolume(float volume)
if(volume != mRequestedVolume)
{
mRequestedVolume = volume;
-
+
LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume");
message.setValueReal("volume", volume);
-
+
sendMessage(message);
}
}
@@ -1456,4 +1476,3 @@ void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history)
LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL;
}
-
diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h
index 96d577f43c..fc27b7bea3 100644
--- a/indra/llplugin/llpluginclassmedia.h
+++ b/indra/llplugin/llpluginclassmedia.h
@@ -133,6 +133,8 @@ public:
// Text may be unicode (utf8 encoded)
bool textInput(const std::string &text, MASK modifiers, LLSD native_key_data);
+ void setCookie(std::string uri, std::string name, std::string value, std::string domain, std::string path, bool httponly, bool secure);
+
void loadURI(const std::string &uri);
// "Loading" means uninitialized or any state prior to fully running (processing commands)
@@ -191,7 +193,7 @@ public:
bool canPaste() const { return mCanPaste; };
// These can be called before init(), and they will be queued and sent before the media init message.
- void setUserDataPath(const std::string &user_data_path);
+ void setUserDataPath(const std::string &user_data_path_cache, const std::string &user_data_path_cookies);
void setLanguageCode(const std::string &language_code);
void setPluginsEnabled(const bool enabled);
void setJavascriptEnabled(const bool enabled);
@@ -277,6 +279,10 @@ public:
std::string getHoverText() const { return mHoverText; };
std::string getHoverLink() const { return mHoverLink; };
+ // these are valid during MEDIA_EVENT_LINK_HOVERED
+ std::string getFileDownloadFilename() const { return mFileDownloadFilename; }
+
+
const std::string& getMediaName() const { return mMediaName; };
std::string getMediaDescription() const { return mMediaDescription; };
@@ -372,7 +378,7 @@ protected:
int mPadding;
- LLPluginProcessParent *mPlugin;
+ LLPluginProcessParent::ptr_t mPlugin;
LLRect mDirtyRect;
@@ -424,6 +430,7 @@ protected:
std::string mAuthRealm;
std::string mHoverText;
std::string mHoverLink;
+ std::string mFileDownloadFilename;
/////////////////////////////////////////
// media_time class
diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h
index 2f3edba7f3..391c23d883 100644
--- a/indra/llplugin/llpluginclassmediaowner.h
+++ b/indra/llplugin/llpluginclassmediaowner.h
@@ -64,6 +64,8 @@ public:
MEDIA_EVENT_AUTH_REQUEST, // The plugin wants to display an auth dialog
+ MEDIA_EVENT_FILE_DOWNLOAD, // the plugin wants to download a file
+
MEDIA_EVENT_DEBUG_MESSAGE, // plugin sending back debug information for host to process
MEDIA_EVENT_LINK_HOVERED // Got a "link hovered" event from the plugin
diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp
index f8a282184e..be80d38305 100644
--- a/indra/llplugin/llpluginprocesschild.cpp
+++ b/indra/llplugin/llpluginprocesschild.cpp
@@ -33,6 +33,7 @@
#include "llpluginmessagepipe.h"
#include "llpluginmessageclasses.h"
+static const F32 GOODBYE_SECONDS = 20.0f;
static const F32 HEARTBEAT_SECONDS = 1.0f;
static const F32 PLUGIN_IDLE_SECONDS = 1.0f / 100.0f; // Each call to idle will give the plugin this much time.
@@ -194,33 +195,43 @@ void LLPluginProcessChild::idle(void)
}
}
// receivePluginMessage will transition to STATE_UNLOADING
- break;
+ break;
+
+ case STATE_SHUTDOWNREQ:
+ if (mInstance != NULL)
+ {
+ sendMessageToPlugin(LLPluginMessage("base", "cleanup"));
+ delete mInstance;
+ mInstance = NULL;
+ }
+ setState(STATE_UNLOADING);
+ mWaitGoodbye.setTimerExpirySec(GOODBYE_SECONDS);
+ break;
case STATE_UNLOADING:
- if(mInstance != NULL)
- {
- sendMessageToPlugin(LLPluginMessage("base", "cleanup"));
- delete mInstance;
- mInstance = NULL;
- }
- setState(STATE_UNLOADED);
- break;
+ // waiting for goodbye from plugin.
+ if (mWaitGoodbye.hasExpired())
+ {
+ LL_WARNS() << "Wait for goodbye expired. Advancing to UNLOADED" << LL_ENDL;
+ setState(STATE_UNLOADED);
+ }
+ break;
case STATE_UNLOADED:
killSockets();
setState(STATE_DONE);
- break;
+ break;
case STATE_ERROR:
// Close the socket to the launcher
killSockets();
// TODO: Where do we go from here? Just exit()?
setState(STATE_DONE);
- break;
+ break;
case STATE_DONE:
// just sit here.
- break;
+ break;
}
} while (idle_again);
@@ -350,6 +361,10 @@ void LLPluginProcessChild::receiveMessageRaw(const std::string &message)
mPluginFile = parsed.getValue("file");
mPluginDir = parsed.getValue("dir");
}
+ else if (message_name == "shutdown_plugin")
+ {
+ setState(STATE_SHUTDOWNREQ);
+ }
else if(message_name == "shm_add")
{
std::string name = parsed.getValue("name");
@@ -495,6 +510,10 @@ void LLPluginProcessChild::receivePluginMessage(const std::string &message)
// Let the parent know it's loaded and initialized.
sendMessageToParent(new_message);
}
+ else if (message_name == "goodbye")
+ {
+ setState(STATE_UNLOADED);
+ }
else if(message_name == "shm_remove_response")
{
// Don't pass this message up to the parent
diff --git a/indra/llplugin/llpluginprocesschild.h b/indra/llplugin/llpluginprocesschild.h
index 531422e792..b916cc9528 100644
--- a/indra/llplugin/llpluginprocesschild.h
+++ b/indra/llplugin/llpluginprocesschild.h
@@ -80,6 +80,7 @@ private:
STATE_PLUGIN_LOADED, // plugin library has been loaded
STATE_PLUGIN_INITIALIZING, // plugin is processing init message
STATE_RUNNING, // steady state (processing messages)
+ STATE_SHUTDOWNREQ, // Parent has requested a shutdown.
STATE_UNLOADING, // plugin has sent shutdown_response and needs to be unloaded
STATE_UNLOADED, // plugin has been unloaded
STATE_ERROR, // generic bailout state
@@ -101,12 +102,12 @@ private:
sharedMemoryRegionsType mSharedMemoryRegions;
LLTimer mHeartbeat;
- F64 mSleepTime;
- F64 mCPUElapsed;
+ F64 mSleepTime;
+ F64 mCPUElapsed;
bool mBlockingRequest;
bool mBlockingResponseReceived;
std::queue<std::string> mMessageQueue;
-
+ LLTimer mWaitGoodbye;
void deliverQueuedMessages();
};
diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp
index b5a2588e1e..0a8e58ac90 100644
--- a/indra/llplugin/llpluginprocessparent.cpp
+++ b/indra/llplugin/llpluginprocessparent.cpp
@@ -46,7 +46,7 @@ bool LLPluginProcessParent::sUseReadThread = false;
apr_pollset_t *LLPluginProcessParent::sPollSet = NULL;
bool LLPluginProcessParent::sPollsetNeedsRebuild = false;
LLMutex *LLPluginProcessParent::sInstancesMutex;
-std::list<LLPluginProcessParent*> LLPluginProcessParent::sInstances;
+LLPluginProcessParent::mapInstances_t LLPluginProcessParent::sInstances;
LLThread *LLPluginProcessParent::sReadThread = NULL;
@@ -104,27 +104,12 @@ LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner):
// Don't start the timer here -- start it when we actually launch the plugin process.
mHeartbeat.stop();
- // Don't add to the global list until fully constructed.
- {
- LLMutexLock lock(sInstancesMutex);
- sInstances.push_back(this);
- }
}
LLPluginProcessParent::~LLPluginProcessParent()
{
LL_DEBUGS("Plugin") << "destructor" << LL_ENDL;
- // Remove from the global list before beginning destruction.
- {
- // Make sure to get the global mutex _first_ here, to avoid a possible deadlock against LLPluginProcessParent::poll()
- LLMutexLock lock(sInstancesMutex);
- {
- LLMutexLock lock2(&mIncomingQueueMutex);
- sInstances.remove(this);
- }
- }
-
// Destroy any remaining shared memory regions
sharedMemoryRegionsType::iterator iter;
while((iter = mSharedMemoryRegions.begin()) != mSharedMemoryRegions.end())
@@ -139,9 +124,109 @@ LLPluginProcessParent::~LLPluginProcessParent()
}
LLProcess::kill(mProcess);
- killSockets();
+ if (!LLApp::isQuitting())
+ { // If we are quitting, the network sockets will already have been destroyed.
+ killSockets();
+ }
+}
+
+/*static*/
+LLPluginProcessParent::ptr_t LLPluginProcessParent::create(LLPluginProcessParentOwner *owner)
+{
+ ptr_t that(new LLPluginProcessParent(owner));
+
+ // Don't add to the global list until fully constructed.
+ {
+ LLMutexLock lock(sInstancesMutex);
+ sInstances.insert(mapInstances_t::value_type(that.get(), that));
+ }
+
+ return that;
+}
+
+/*static*/
+void LLPluginProcessParent::shutdown()
+{
+ LLMutexLock lock(sInstancesMutex);
+
+ mapInstances_t::iterator it;
+ for (it = sInstances.begin(); it != sInstances.end(); ++it)
+ {
+ (*it).second->setState(STATE_GOODBYE);
+ (*it).second->idle();
+ }
+ sInstances.clear();
+}
+
+
+void LLPluginProcessParent::requestShutdown()
+{
+ setState(STATE_GOODBYE);
+ mOwner = NULL;
+
+ if (LLApp::isQuitting())
+ { // if we're quitting, run the idle once more
+ idle();
+ removeFromProcessing();
+ return;
+ }
+
+ static uint32_t count = 0;
+ std::stringstream namestream;
+
+ namestream << "LLPluginProcessParentListener" << ++count;
+
+ //*HACK!*//
+ // After requestShutdown has been called our previous owner will no longer call
+ // our idle() method. Tie into the event loop here to do that until we are good
+ // and finished.
+ LL_DEBUGS("LLPluginProcessParent") << "listening on \"mainloop\"" << LL_ENDL;
+ mPolling = LLEventPumps::instance().obtain("mainloop")
+ .listen(namestream.str(), boost::bind(&LLPluginProcessParent::pollTick, this));
+
+}
+
+bool LLPluginProcessParent::pollTick()
+{
+ if (isDone())
+ {
+ ptr_t that;
+ {
+ // this grabs a copy of the smart pointer to ourselves to ensure that we do not
+ // get destroyed until after this method returns.
+ LLMutexLock lock(sInstancesMutex);
+ mapInstances_t::iterator it = sInstances.find(this);
+ if (it != sInstances.end())
+ that = (*it).second;
+ }
+
+ removeFromProcessing();
+ return true;
+ }
+
+ idle();
+ return false;
}
+void LLPluginProcessParent::removeFromProcessing()
+{
+ // Remove from the global list before beginning destruction.
+ {
+ // Make sure to get the global mutex _first_ here, to avoid a possible deadlock against LLPluginProcessParent::poll()
+ LLMutexLock lock(sInstancesMutex);
+ {
+ LLMutexLock lock2(&mIncomingQueueMutex);
+ sInstances.erase(this);
+ }
+ }
+}
+
+bool LLPluginProcessParent::wantsPolling() const
+{
+ return (mPollFD.client_data && (mState != STATE_DONE));
+}
+
+
void LLPluginProcessParent::killSockets(void)
{
{
@@ -371,48 +456,48 @@ void LLPluginProcessParent::idle(void)
break;
case STATE_LISTENING:
- {
- // Launch the plugin process.
+ {
+ // Launch the plugin process.
- // Only argument to the launcher is the port number we're listening on
- mProcessParams.args.add(stringize(mBoundPort));
- if (! (mProcess = LLProcess::create(mProcessParams)))
- {
- errorState();
- }
- else
- {
- if(mDebug)
- {
- #if LL_DARWIN
- // 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.
+ // Only argument to the launcher is the port number we're listening on
+ mProcessParams.args.add(stringize(mBoundPort));
+ if (! (mProcess = LLProcess::create(mProcessParams)))
+ {
+ errorState();
+ }
+ else
+ {
+ if(mDebug)
+ {
+#if LL_DARWIN
+ // 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.
- // The command we're constructing would look like this on the command line:
- // osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell'
-
- LLProcess::Params params;
- params.executable = "/usr/bin/osascript";
- params.args.add("-e");
- params.args.add("tell application \"Terminal\"");
- params.args.add("-e");
- params.args.add(STRINGIZE("set win to do script \"gdb -pid "
- << mProcess->getProcessID() << "\""));
- params.args.add("-e");
- params.args.add("do script \"continue\" in win");
- params.args.add("-e");
- params.args.add("end tell");
- mDebugger = LLProcess::create(params);
-
- #endif
- }
+ // The command we're constructing would look like this on the command line:
+ // osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell'
+
+ LLProcess::Params params;
+ params.executable = "/usr/bin/osascript";
+ params.args.add("-e");
+ params.args.add("tell application \"Terminal\"");
+ params.args.add("-e");
+ params.args.add(STRINGIZE("set win to do script \"gdb -pid "
+ << mProcess->getProcessID() << "\""));
+ params.args.add("-e");
+ params.args.add("do script \"continue\" in win");
+ params.args.add("-e");
+ params.args.add("end tell");
+ mDebugger = LLProcess::create(params);
+
+#endif
+ }
- // This will allow us to time out if the process never starts.
- mHeartbeat.start();
- mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout);
- setState(STATE_LAUNCHED);
- }
- }
- break;
+ // This will allow us to time out if the process never starts.
+ mHeartbeat.start();
+ mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout);
+ setState(STATE_LAUNCHED);
+ }
+ }
+ break;
case STATE_LAUNCHED:
// waiting for the plugin to connect
@@ -430,7 +515,7 @@ void LLPluginProcessParent::idle(void)
setState(STATE_CONNECTED);
}
}
- break;
+ break;
case STATE_CONNECTED:
// waiting for hello message from the plugin
@@ -439,7 +524,7 @@ void LLPluginProcessParent::idle(void)
{
errorState();
}
- break;
+ break;
case STATE_HELLO:
LL_DEBUGS("Plugin") << "received hello message" << LL_ENDL;
@@ -453,7 +538,7 @@ void LLPluginProcessParent::idle(void)
}
setState(STATE_LOADING);
- break;
+ break;
case STATE_LOADING:
// The load_plugin_response message will kick us from here into STATE_RUNNING
@@ -461,15 +546,23 @@ void LLPluginProcessParent::idle(void)
{
errorState();
}
- break;
+ break;
case STATE_RUNNING:
if(pluginLockedUpOrQuit())
{
errorState();
}
- break;
+ break;
+ case STATE_GOODBYE:
+ {
+ LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shutdown_plugin");
+ sendMessage(message);
+ }
+ setState(STATE_EXITING);
+ break;
+
case STATE_EXITING:
if (! LLProcess::isRunning(mProcess))
{
@@ -480,7 +573,7 @@ void LLPluginProcessParent::idle(void)
LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << LL_ENDL;
errorState();
}
- break;
+ break;
case STATE_LAUNCH_FAILURE:
if(mOwner != NULL)
@@ -488,7 +581,7 @@ void LLPluginProcessParent::idle(void)
mOwner->pluginLaunchFailed();
}
setState(STATE_CLEANUP);
- break;
+ break;
case STATE_ERROR:
if(mOwner != NULL)
@@ -496,19 +589,18 @@ void LLPluginProcessParent::idle(void)
mOwner->pluginDied();
}
setState(STATE_CLEANUP);
- break;
+ break;
case STATE_CLEANUP:
LLProcess::kill(mProcess);
killSockets();
setState(STATE_DONE);
- break;
-
+ dirtyPollSet();
+ break;
case STATE_DONE:
// just sit here.
- break;
-
+ break;
}
} while (idle_again);
@@ -651,14 +743,14 @@ void LLPluginProcessParent::updatePollset()
sPollSet = NULL;
}
- std::list<LLPluginProcessParent*>::iterator iter;
+ mapInstances_t::iterator iter;
int count = 0;
// Count the number of instances that want to be in the pollset
for(iter = sInstances.begin(); iter != sInstances.end(); iter++)
{
- (*iter)->mPolledInput = false;
- if((*iter)->mPollFD.client_data)
+ (*iter).second->mPolledInput = false;
+ if ((*iter).second->wantsPolling())
{
// This instance has a socket that needs to be polled.
++count;
@@ -686,12 +778,12 @@ void LLPluginProcessParent::updatePollset()
// Pollset was created, add all instances to it.
for(iter = sInstances.begin(); iter != sInstances.end(); iter++)
{
- if((*iter)->mPollFD.client_data)
+ if ((*iter).second->wantsPolling())
{
- status = apr_pollset_add(sPollSet, &((*iter)->mPollFD));
+ status = apr_pollset_add(sPollSet, &((*iter).second->mPollFD));
if(status == APR_SUCCESS)
{
- (*iter)->mPolledInput = true;
+ (*iter).second->mPolledInput = true;
}
else
{
@@ -756,45 +848,27 @@ void LLPluginProcessParent::poll(F64 timeout)
if(status == APR_SUCCESS)
{
// One or more of the descriptors signalled. Call them.
- for(int i = 0; i < count; i++)
- {
- LLPluginProcessParent *self = (LLPluginProcessParent *)(descriptors[i].client_data);
- // NOTE: the descriptor returned here is actually a COPY of the original (even though we create the pollset with APR_POLLSET_NOCOPY).
- // This means that even if the parent has set its mPollFD.client_data to NULL, the old pointer may still there in this descriptor.
- // It's even possible that the old pointer no longer points to a valid LLPluginProcessParent.
- // This means that we can't safely dereference the 'self' pointer here without some extra steps...
- if(self)
- {
- // Make sure this pointer is still in the instances list
- bool valid = false;
- {
- LLMutexLock lock(sInstancesMutex);
- for(std::list<LLPluginProcessParent*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
- {
- if(*iter == self)
- {
- // Lock the instance's mutex before unlocking the global mutex.
- // This avoids a possible race condition where the instance gets deleted between this check and the servicePoll() call.
- self->mIncomingQueueMutex.lock();
- valid = true;
- break;
- }
- }
- }
-
- if(valid)
- {
- // The instance is still valid.
- // Pull incoming messages off the socket
- self->servicePoll();
- self->mIncomingQueueMutex.unlock();
- }
- else
- {
- LL_DEBUGS("PluginPoll") << "detected deleted instance " << self << LL_ENDL;
- }
+ for (int i = 0; i < count; i++)
+ {
+ void *thatId = descriptors[i].client_data;
+
+ ptr_t that;
+ mapInstances_t::iterator it;
+
+ {
+ LLMutexLock lock(sInstancesMutex);
+ it = sInstances.find(thatId);
+ if (it != sInstances.end())
+ that = (*it).second;
+ }
+
+ if (that)
+ {
+ that->mIncomingQueueMutex.lock();
+ that->servicePoll();
+ that->mIncomingQueueMutex.unlock();
+ }
- }
}
}
else if(APR_STATUS_IS_TIMEUP(status))
@@ -812,6 +886,16 @@ void LLPluginProcessParent::poll(F64 timeout)
LL_WARNS("PluginPoll") << "apr_pollset_poll failed with status " << status << LL_ENDL;
}
}
+
+ // Remove instances in the done state from the sInstances map.
+ mapInstances_t::iterator itClean = sInstances.begin();
+ while (itClean != sInstances.end())
+ {
+ if ((*itClean).second->isDone())
+ sInstances.erase(itClean++);
+ else
+ ++itClean;
+ }
}
void LLPluginProcessParent::servicePoll()
diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h
index 24be7eb148..df1630255c 100644
--- a/indra/llplugin/llpluginprocessparent.h
+++ b/indra/llplugin/llpluginprocessparent.h
@@ -30,6 +30,7 @@
#define LL_LLPLUGINPROCESSPARENT_H
#include <queue>
+#include <boost/enable_shared_from_this.hpp>
#include "llapr.h"
#include "llprocess.h"
@@ -40,8 +41,9 @@
#include "lliosocket.h"
#include "llthread.h"
#include "llsd.h"
+#include "llevents.h"
-class LLPluginProcessParentOwner
+class LLPluginProcessParentOwner : public boost::enable_shared_from_this < LLPluginProcessParentOwner >
{
public:
virtual ~LLPluginProcessParentOwner();
@@ -55,8 +57,11 @@ public:
class LLPluginProcessParent : public LLPluginMessagePipeOwner
{
LOG_CLASS(LLPluginProcessParent);
+
+ LLPluginProcessParent(LLPluginProcessParentOwner *owner);
public:
- LLPluginProcessParent(LLPluginProcessParentOwner *owner);
+ typedef boost::shared_ptr<LLPluginProcessParent> ptr_t;
+
~LLPluginProcessParent();
void init(const std::string &launcher_filename,
@@ -89,7 +94,10 @@ public:
void sendMessage(const LLPluginMessage &message);
void receiveMessage(const LLPluginMessage &message);
-
+
+ static ptr_t create(LLPluginProcessParentOwner *owner);
+ void requestShutdown();
+
// Inherited from LLPluginMessagePipeOwner
/*virtual*/ void receiveMessageRaw(const std::string &message);
/*virtual*/ void receiveMessageEarly(const LLPluginMessage &message);
@@ -121,7 +129,10 @@ public:
static bool canPollThreadRun() { return (sPollSet || sPollsetNeedsRebuild || sUseReadThread); };
static void setUseReadThread(bool use_read_thread);
static bool getUseReadThread() { return sUseReadThread; };
+
+ static void shutdown();
private:
+ typedef std::map<void *, ptr_t> mapInstances_t;
enum EState
{
@@ -133,6 +144,7 @@ private:
STATE_HELLO, // first message from the plugin process has been received
STATE_LOADING, // process has been asked to load the plugin
STATE_RUNNING, //
+ STATE_GOODBYE,
STATE_LAUNCH_FAILURE, // Failure before plugin loaded
STATE_ERROR, // generic bailout state
STATE_CLEANUP, // clean everything up
@@ -143,6 +155,9 @@ private:
EState mState;
void setState(EState state);
+ bool wantsPolling() const;
+ void removeFromProcessing();
+
bool pluginLockedUp();
bool pluginLockedUpOrQuit();
@@ -185,12 +200,15 @@ private:
static apr_pollset_t *sPollSet;
static bool sPollsetNeedsRebuild;
static LLMutex *sInstancesMutex;
- static std::list<LLPluginProcessParent*> sInstances;
+ static mapInstances_t sInstances;
static void dirtyPollSet();
static void updatePollset();
void servicePoll();
static LLThread *sReadThread;
-
+
+ LLTempBoundListener mPolling;
+ bool pollTick();
+
LLMutex mIncomingQueueMutex;
std::queue<LLPluginMessage> mIncomingQueue;
};
diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp
index 6c9ba0ae52..684bcf1207 100644
--- a/indra/llplugin/slplugin/slplugin.cpp
+++ b/indra/llplugin/slplugin/slplugin.cpp
@@ -310,4 +310,3 @@ int main(int argc, char **argv)
return 0;
}
-