S32 LLQueuedThread::updateQueue(U32 max_time_ms) { F64 max_time = (F64)max_time_ms * .001; LLTimer timer; S32 pending = 1; // Frame Update if (mThreaded) { pending = getPending(); if(pending > 0) { unpause(); } } else { while (pending > 0) { pending = processNextRequest(); if (max_time && timer.getElapsedTimeF64() > max_time) break; } } return pending; }
// This is the SLPlugin process. // This is not part of a DSO. // // This function is called by SLPlugin to send a message (originating from // SLPlugin itself) to the loaded DSO. It calls LLPluginInstance::sendMessage. void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message) { if (mInstance) { std::string buffer = message.generate(); LL_DEBUGS("Plugin") << "Sending to plugin: " << buffer << LL_ENDL; LLTimer elapsed; mInstance->sendMessage(buffer); mCPUElapsed += elapsed.getElapsedTimeF64(); } else { LL_WARNS("Plugin") << "mInstance == NULL" << LL_ENDL; } }
void LLVertexBuffer::clientCopy(F64 max_time) { if (!sDeleteList.empty()) { size_t num = sDeleteList.size(); glDeleteBuffersARB(sDeleteList.size(), (GLuint*) &(sDeleteList[0])); sDeleteList.clear(); sGLCount -= num; } if (sEnableVBOs) { LLTimer timer; BOOL reset = TRUE; buffer_list_t::iterator iter = sLockedList.begin(); while(iter != sLockedList.end()) { LLVertexBuffer* buffer = *iter; if (buffer->isLocked() && buffer->useVBOs()) { buffer->setBuffer(0); } ++iter; if (reset) { reset = FALSE; timer.reset(); //skip first copy (don't count pipeline stall) } else { if (timer.getElapsedTimeF64() > max_time) { break; } } } sLockedList.erase(sLockedList.begin(), iter); } }
// This is the SLPlugin process (the child process). // This is not part of a DSO. // // This function is called when the serialized message 'message' was received from the viewer. // It parses the message and handles LLPLUGIN_MESSAGE_CLASS_INTERNAL. // Other message classes are passed on to LLPluginInstance::sendMessage. void LLPluginProcessChild::receiveMessageRaw(const std::string &message) { // Incoming message from the TCP Socket LL_DEBUGS("Plugin") << "Received from parent: " << message << LL_ENDL; // Decode this message LLPluginMessage parsed; parsed.parse(message); if(mBlockingRequest) { // We're blocking the plugin waiting for a response. if(parsed.hasValue("blocking_response")) { // This is the message we've been waiting for -- fall through and send it immediately. mBlockingResponseReceived = true; } else { // Still waiting. Queue this message and don't process it yet. mMessageQueue.push(message); return; } } bool passMessage = true; // FIXME: how should we handle queueing here? { std::string message_class = parsed.getClass(); if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) { passMessage = false; std::string message_name = parsed.getName(); if(message_name == "load_plugin") { mPluginFile = parsed.getValue("file"); mPluginDir = parsed.getValue("dir"); } else if(message_name == "shm_add") { std::string name = parsed.getValue("name"); size_t size = (size_t)parsed.getValueS32("size"); sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); if(iter != mSharedMemoryRegions.end()) { // Need to remove the old region first LL_WARNS("Plugin") << "Adding a duplicate shared memory segment!" << LL_ENDL; } else { // This is a new region LLPluginSharedMemory *region = new LLPluginSharedMemory; if(region->attach(name, size)) { mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region)); std::stringstream addr; addr << region->getMappedAddress(); // Send the add notification to the plugin LLPluginMessage message("base", "shm_added"); message.setValue("name", name); message.setValueS32("size", (S32)size); message.setValuePointer("address", region->getMappedAddress()); sendMessageToPlugin(message); // and send the response to the parent message.setMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_add_response"); message.setValue("name", name); sendMessageToParent(message); } else { LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL; delete region; } } } else if(message_name == "shm_remove") { std::string name = parsed.getValue("name"); sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); if(iter != mSharedMemoryRegions.end()) { // forward the remove request to the plugin -- its response will trigger us to detach the segment. LLPluginMessage message("base", "shm_remove"); message.setValue("name", name); sendMessageToPlugin(message); } else { LL_WARNS("Plugin") << "shm_remove for unknown memory segment!" << LL_ENDL; } } else if(message_name == "sleep_time") { mSleepTime = llmax(parsed.getValueReal("time"), 1.0 / 100.0); // clamp to maximum of 100Hz } else if(message_name == "crash") { // Crash the plugin LL_ERRS("Plugin") << "Plugin crash requested." << LL_ENDL; } else if(message_name == "hang") { // Hang the plugin LL_WARNS("Plugin") << "Plugin hang requested." << LL_ENDL; while(1) { // wheeeeeeeee...... } } else { LL_WARNS("Plugin") << "Unknown internal message from parent: " << message_name << LL_ENDL; } } } if(passMessage && mInstance != NULL) { LLTimer elapsed; mInstance->sendMessage(message); mCPUElapsed += elapsed.getElapsedTimeF64(); } }
int main(int argc, char **argv) #endif { ll_init_apr(); // Set up llerror logging { LLError::initForApplication("."); LLError::setDefaultLevel(LLError::LEVEL_INFO); // LLError::setTagLevel("Plugin", LLError::LEVEL_DEBUG); // LLError::logToFile("slplugin.log"); } #if LL_WINDOWS if( strlen( lpCmdLine ) == 0 ) { LL_ERRS("slplugin") << "usage: " << "SLPlugin" << " launcher_port" << LL_ENDL; }; U32 port = 0; if(!LLStringUtil::convertToU32(lpCmdLine, port)) { LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL; }; // Insert our exception handler into the system so this plugin doesn't // display a crash message if something bad happens. The host app will // see the missing heartbeat and log appropriately. initExceptionHandler(); #elif LL_DARWIN || LL_LINUX if(argc < 2) { LL_ERRS("slplugin") << "usage: " << argv[0] << " launcher_port" << LL_ENDL; } U32 port = 0; if(!LLStringUtil::convertToU32(argv[1], port)) { LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL; } // Catch signals that most kinds of crashes will generate, and exit cleanly so the system crash dialog isn't shown. signal(SIGILL, &crash_handler); // illegal instruction # if LL_DARWIN signal(SIGEMT, &crash_handler); // emulate instruction executed # endif // LL_DARWIN signal(SIGFPE, &crash_handler); // floating-point exception signal(SIGBUS, &crash_handler); // bus error signal(SIGSEGV, &crash_handler); // segmentation violation signal(SIGSYS, &crash_handler); // non-existent system call invoked #endif #if LL_DARWIN setupCocoa(); createAutoReleasePool(); #endif LLPluginProcessChild *plugin = new LLPluginProcessChild(); plugin->init(port); #if LL_DARWIN deleteAutoReleasePool(); #endif LLTimer timer; timer.start(); #if LL_WINDOWS checkExceptionHandler(); #endif #if LL_DARWIN // If the plugin opens a new window (such as the Flash plugin's fullscreen player), we may need to bring this plugin process to the foreground. // Use this to track the current frontmost window and bring this process to the front if it changes. WindowRef front_window = NULL; WindowGroupRef layer_group = NULL; int window_hack_state = 0; CreateWindowGroup(kWindowGroupAttrFixedLevel, &layer_group); if(layer_group) { // Start out with a window layer that's way out in front (fixes the problem with the menubar not getting hidden on first switch to fullscreen youtube) SetWindowGroupName(layer_group, CFSTR("SLPlugin Layer")); SetWindowGroupLevel(layer_group, kCGOverlayWindowLevel); } #endif #if LL_DARWIN EventTargetRef event_target = GetEventDispatcherTarget(); #endif while(!plugin->isDone()) { #if LL_DARWIN createAutoReleasePool(); #endif timer.reset(); plugin->idle(); #if LL_DARWIN { // Some plugins (webkit at least) will want an event loop. This qualifies. EventRef event; if(ReceiveNextEvent(0, 0, kEventDurationNoWait, true, &event) == noErr) { SendEventToEventTarget (event, event_target); ReleaseEvent(event); } // Check for a change in this process's frontmost window. if(FrontWindow() != front_window) { ProcessSerialNumber self = { 0, kCurrentProcess }; ProcessSerialNumber parent = { 0, kNoProcess }; ProcessSerialNumber front = { 0, kNoProcess }; Boolean this_is_front_process = false; Boolean parent_is_front_process = false; { // Get this process's parent ProcessInfoRec info; info.processInfoLength = sizeof(ProcessInfoRec); info.processName = NULL; info.processAppSpec = NULL; if(GetProcessInformation( &self, &info ) == noErr) { parent = info.processLauncher; } // and figure out whether this process or its parent are currently frontmost if(GetFrontProcess(&front) == noErr) { (void) SameProcess(&self, &front, &this_is_front_process); (void) SameProcess(&parent, &front, &parent_is_front_process); } } if((FrontWindow() != NULL) && (front_window == NULL)) { // Opening the first window if(window_hack_state == 0) { // Next time through the event loop, lower the window group layer window_hack_state = 1; } if(layer_group) { SetWindowGroup(FrontWindow(), layer_group); } if(parent_is_front_process) { // Bring this process's windows to the front. (void) SetFrontProcess( &self ); } ActivateWindow(FrontWindow(), true); } else if((FrontWindow() == NULL) && (front_window != NULL)) { // Closing the last window if(this_is_front_process) { // Try to bring this process's parent to the front (void) SetFrontProcess(&parent); } } else if(window_hack_state == 1) { if(layer_group) { // Set the window group level back to something less extreme SetWindowGroupLevel(layer_group, kCGNormalWindowLevel); } window_hack_state = 2; } front_window = FrontWindow(); } } #endif F64 elapsed = timer.getElapsedTimeF64(); F64 remaining = plugin->getSleepTime() - elapsed; if(remaining <= 0.0f) { // We've already used our full allotment. // LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, not sleeping" << LL_ENDL; // Still need to service the network... plugin->pump(); } else { // LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, sleeping for " << remaining * 1000.0f << " ms" << LL_ENDL; // timer.reset(); // This also services the network as needed. plugin->sleep(remaining); // LL_INFOS("slplugin") << "slept for "<< timer.getElapsedTimeF64() * 1000.0f << " ms" << LL_ENDL; } #if LL_WINDOWS // More agressive checking of interfering exception handlers. // Doesn't appear to be required so far - even for plugins // that do crash with a single call to the intercept // exception handler such as QuickTime. //checkExceptionHandler(); #endif #if LL_DARWIN deleteAutoReleasePool(); #endif } delete plugin; ll_cleanup_apr(); return 0; }
int main(int argc, char **argv) #endif { ll_init_apr(); // Set up llerror logging { LLError::initForApplication("."); LLError::setDefaultLevel(LLError::LEVEL_INFO); // LLError::setTagLevel("Plugin", LLError::LEVEL_DEBUG); // LLError::logToFile("slplugin.log"); } #if LL_WINDOWS if( strlen( lpCmdLine ) == 0 ) { LL_ERRS("slplugin") << "usage: " << "SLPlugin" << " launcher_port" << LL_ENDL; }; U32 port = 0; if(!LLStringUtil::convertToU32(lpCmdLine, port)) { LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL; }; // Insert our exception handler into the system so this plugin doesn't // display a crash message if something bad happens. The host app will // see the missing heartbeat and log appropriately. initExceptionHandler(); #elif LL_DARWIN || LL_LINUX if(argc < 2) { LL_ERRS("slplugin") << "usage: " << argv[0] << " launcher_port" << LL_ENDL; } U32 port = 0; if(!LLStringUtil::convertToU32(argv[1], port)) { LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL; } // Catch signals that most kinds of crashes will generate, and exit cleanly so the system crash dialog isn't shown. signal(SIGILL, &crash_handler); // illegal instruction # if LL_DARWIN signal(SIGEMT, &crash_handler); // emulate instruction executed # endif // LL_DARWIN signal(SIGFPE, &crash_handler); // floating-point exception signal(SIGBUS, &crash_handler); // bus error signal(SIGSEGV, &crash_handler); // segmentation violation signal(SIGSYS, &crash_handler); // non-existent system call invoked #endif LLPluginProcessChild *plugin = new LLPluginProcessChild(); plugin->init(port); LLTimer timer; timer.start(); #if LL_WINDOWS checkExceptionHandler(); #endif #if LL_DARWIN EventTargetRef event_target = GetEventDispatcherTarget(); #endif while(!plugin->isDone()) { timer.reset(); plugin->idle(); #if LL_DARWIN { // Some plugins (webkit at least) will want an event loop. This qualifies. EventRef event; if(ReceiveNextEvent(0, 0, kEventDurationNoWait, true, &event) == noErr) { SendEventToEventTarget (event, event_target); ReleaseEvent(event); } } #endif F64 elapsed = timer.getElapsedTimeF64(); F64 remaining = plugin->getSleepTime() - elapsed; if(remaining <= 0.0f) { // We've already used our full allotment. // LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, not sleeping" << LL_ENDL; // Still need to service the network... plugin->pump(); } else { // LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, sleeping for " << remaining * 1000.0f << " ms" << LL_ENDL; // timer.reset(); // This also services the network as needed. plugin->sleep(remaining); // LL_INFOS("slplugin") << "slept for "<< timer.getElapsedTimeF64() * 1000.0f << " ms" << LL_ENDL; } #if LL_WINDOWS // More agressive checking of interfering exception handlers. // Doesn't appear to be required so far - even for plugins // that do crash with a single call to the intercept // exception handler such as QuickTime. //checkExceptionHandler(); #endif } delete plugin; ll_cleanup_apr(); return 0; }
// Static // Called from MAIN thread void FLLua::execClientEvents() { if(!sInstance) { llinfos << "LUA isn't running yet." << llendl; return; } if(sInstance->mPendingEvents) { lldebugs << __LINE__ << ": Events pending. Iterating through events." << llendl; sInstance->mPendingEvents=false; sInstance->lockData(); while(!sInstance->mQueuedEvents.empty()) { #ifdef FL_PRI_EVENTS lldebugs << __LINE__ << ": Acquiring highest-priority event." << llendl; CB_Base *cb=sInstance->mQueuedEvents.top(); #else lldebugs << __LINE__ << ": Acquiring first event in queue." << llendl; CB_Base *cb=sInstance->mQueuedEvents.front(); #endif if(!cb) { llwarns << "Invalid pointer to event!" << llendl; } else { lldebugs << __LINE__ << ": Calling event." << llendl; cb->OnCall(); delete cb; } sInstance->mQueuedEvents.pop(); } sInstance->unlockData(); } if(sInstance->isPaused()) { if(sInstance->mAllowPause) //shouldn't ever happen. { sInstance->unpause(); return; } int yields=0; LLTimer timer; timer.setTimerExpirySec(.25); while(!sInstance->mAllowPause)//mAllowPause == true when Lua thread finishes loop. { sInstance->unpause(); yield(); //Hopefully let the Lua thread resume yields++; if(timer.hasExpired()) { LL_WARNS("Lua") << "Aborting critical section after " << timer.getElapsedTimeF64()*(F64)1000.f << "ms " << llendl; sInstance->mAllowPause=true; // NOTE: Lua taking too much time. Force new critical requests // to next frame. break; } } int sec=sInstance->mCriticalSections; if(sec) //Main has resumed with Lua in a critical section. Not thread safe. LL_WARNS("Lua") << sec << " critical sections active. Unsafe resume!" << llendl; LL_INFOS("Lua") << "Finished critical section after " << timer.getElapsedTimeF64()*(F64)1000.f << "ms. Yields=" << yields << llendl; } }