diff options
Diffstat (limited to 'indra/llplugin')
-rw-r--r-- | indra/llplugin/CMakeLists.txt | 3 | ||||
-rw-r--r-- | indra/llplugin/llpluginclassmedia.cpp | 279 | ||||
-rw-r--r-- | indra/llplugin/llpluginclassmedia.h | 11 | ||||
-rw-r--r-- | indra/llplugin/llpluginclassmediaowner.h | 2 | ||||
-rw-r--r-- | indra/llplugin/llpluginprocesschild.cpp | 43 | ||||
-rw-r--r-- | indra/llplugin/llpluginprocesschild.h | 7 | ||||
-rw-r--r-- | indra/llplugin/llpluginprocessparent.cpp | 308 | ||||
-rw-r--r-- | indra/llplugin/llpluginprocessparent.h | 28 | ||||
-rw-r--r-- | indra/llplugin/slplugin/slplugin.cpp | 1 |
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; } - |