/** * processItem * - If this is a TclCommand - flush all the consolidations and output. * - If there's already a consolidation for this type if the message is the * same just count it, otherwise flush and set a new consolidation. * - If there's not an existing consolidation, make one. * - free storage associated with the action item's payload. * * @param action - action message. */ void Actions::COutputThread::processItem(Actions::ActionItem item) { Actions::ActionType type = item.s_type; std::string msg = item.s_pMessage; free(item.s_pMessage); // Free storage!' if (type == Actions::TclCommand) { flushMessages(); // Flush All messages before commanding. outputItem(type, msg); } else { // Message, not an actual 'action'. std::map<Actions::ActionType, ActionInfo>::iterator p = m_ConsolidatedActions.find(type); if (p == m_ConsolidatedActions.end()) { // No prior message. createConsolidation(type, msg); } else { if(msg == p->second.s_message) { // If repetition p->second.s_messageCount++; // count. } else { flushItem(type); // otherwise flush that item. createConsolidation(type, msg); // start a new one. } } } }
/** * operator() * This is the entry point of the code. * - Save the current time in s_lastAdded * - Process action items aggregating and flushing as time advances. * * For now we'll just flush as time changes (each second). */ void Actions::COutputThread::operator()() { time_t lastTime = time(NULL); while(1) { // Try to get data from the queue...if not available, wait // for up to a second for data: Actions::ActionItem item; while (!m_pActionQueue->getnow(item)) { // See if we should flush all time_t now = time(NULL); if (now != lastTime) { flushMessages(); // Flush all consolidations. lastTime = now; } m_pActionQueue->wait(1000); } // We have an action item now. processItem(item); } }
CarlaBridgeUI::~CarlaBridgeUI() /*noexcept*/ { carla_debug("CarlaBridgeUI::~CarlaBridgeUI()"); if (fLib != nullptr) { lib_close(fLib); fLib = nullptr; } if (isPipeRunning() && ! fQuitReceived) { const CarlaMutexLocker cml(getPipeLock()); writeMessage("exiting\n", 8); flushMessages(); } if (fToolkit != nullptr) { fToolkit->quit(); delete fToolkit; fToolkit = nullptr; } closePipeClient(); }
~ZynPipeClient() noexcept override { if (fQuitReceived) return; const CarlaMutexLocker cml(getPipeLock()); writeMessage("exiting\n"); flushMessages(); }
void uiNameChanged(const char* const uiName) override { CARLA_SAFE_ASSERT_RETURN(uiName != nullptr && uiName[0] != '\0',); const CarlaMutexLocker cml(getPipeLock()); if (! writeMessage("uiTitle\n", 8)) return; if (! writeAndFixMessage(uiName)) return; flushMessages(); }
bool CarlaBridgeUI::init(const int argc, const char* argv[]) { CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, false); if (argc == 7) { if (! initPipeClient(argv)) return false; fLastMsgTimer = 0; // wait for ui options for (; ++fLastMsgTimer < 50 && ! fGotOptions;) { idlePipe(true); carla_msleep(20); } if (! fGotOptions) { carla_stderr2("CarlaBridgeUI::init() - did not get options on time, quitting..."); { const CarlaMutexLocker cml(getPipeLock()); writeMessage("exiting\n", 8); flushMessages(); } closePipeClient(); return false; } } if (! fToolkit->init(argc, argv)) { if (argc == 7) closePipeClient(); return false; } return true; }
/* virtual */ void LLPluginProcessChild::receivePluginMessage(const std::string &message) { LL_DEBUGS("Plugin") << "Received from plugin: " << message << LL_ENDL; if(mBlockingRequest) { // LL_ERRS("Plugin") << "Can't send a message while already waiting on a blocking request -- aborting!" << LL_ENDL; } // Incoming message from the plugin instance bool passMessage = true; // FIXME: how should we handle queueing here? // Intercept certain base messages (responses to ones sent by this class) { // Decode this message LLPluginMessage parsed; parsed.parse(message); if(parsed.hasValue("blocking_request")) { mBlockingRequest = true; } std::string message_class = parsed.getClass(); if(message_class == "base") { std::string message_name = parsed.getName(); if(message_name == "init_response") { // The plugin has finished initializing. setState(STATE_RUNNING); // Don't pass this message up to the parent passMessage = false; LLPluginMessage new_message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin_response"); LLSD versions = parsed.getValueLLSD("versions"); new_message.setValueLLSD("versions", versions); if(parsed.hasValue("plugin_version")) { std::string plugin_version = parsed.getValue("plugin_version"); new_message.setValueLLSD("plugin_version", plugin_version); } // Let the parent know it's loaded and initialized. sendMessageToParent(new_message); } else if(message_name == "shm_remove_response") { // Don't pass this message up to the parent passMessage = false; std::string name = parsed.getValue("name"); sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); if(iter != mSharedMemoryRegions.end()) { // detach the shared memory region iter->second->detach(); // and remove it from our map mSharedMemoryRegions.erase(iter); // Finally, send the response to the parent. LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove_response"); message.setValue("name", name); sendMessageToParent(message); } else { LL_WARNS("Plugin") << "shm_remove_response for unknown memory segment!" << LL_ENDL; } } } else if (message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) { bool flush = false; std::string message_name = parsed.getName(); if(message_name == "shutdown") { // The plugin is finished. setState(STATE_UNLOADING); flush = true; } else if (message_name == "flush") { flush = true; passMessage = false; } if (flush) { flushMessages(); } } } if(passMessage) { LL_DEBUGS("Plugin") << "Passing through to parent: " << message << LL_ENDL; writeMessageRaw(message); } while(mBlockingRequest) { // The plugin wants to block and wait for a response to this message. sleep(mSleepTime); // this will pump the message pipe and process messages if(mBlockingResponseReceived || mSocketError != APR_SUCCESS || (mMessagePipe == NULL)) { // Response has been received, or we've hit an error state. Stop waiting. mBlockingRequest = false; mBlockingResponseReceived = false; } } }
// This is the SLPlugin process. // This is part of the loaded DSO. // // This function is called from LLPluginInstance::sendMessage // for messages received from the viewer (that are not 'internal'). void FilepickerPlugin::receiveMessage(char const* message_string) { LLPluginMessage message_in; if (message_in.parse(message_string) >= 0) { std::string message_class = message_in.getClass(); std::string message_name = message_in.getName(); if (message_class == LLPLUGIN_MESSAGE_CLASS_BASE) { if (message_name == "init") { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_BASE, "init_response"); LLSD versions = LLSD::emptyMap(); versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; versions[LLPLUGIN_MESSAGE_CLASS_BASIC] = LLPLUGIN_MESSAGE_CLASS_BASIC_VERSION; message.setValueLLSD("versions", versions); std::string plugin_version = "Filepicker Plugin, version 1.0.0.0"; message.setValue("plugin_version", plugin_version); sendMessage(message); } else if (message_name == "cleanup") { // We have no resources that need care. Just do nothing. } else if (message_name == "idle") { // This whole message should not have existed imho -- Aleric } else { std::cerr << "FilepickerPlugin::receiveMessage: unknown base message: " << message_name << std::endl; } } else if (message_class == LLPLUGIN_MESSAGE_CLASS_BASIC) { // This message should be sent at most once per SLPlugin invokation. if (message_name == "initialization") { LLSD dictionary = message_in.getValueLLSD("dictionary"); for (LLSD::map_iterator iter = dictionary.beginMap(); iter != dictionary.endMap(); ++iter) { translation::add(iter->first, iter->second.asString()); } if (message_in.hasValue("window_id")) { unsigned long window_id = strtoul(message_in.getValue("window_id").c_str(), NULL, 16); LLFilePicker::instance().setWindowID(window_id); } } // This message may theoretically be repeated (though currently the plugin is terminated after returning). else if (message_name == "open") { std::string type = message_in.getValue("type"); std::string filter = message_in.getValue("filter"); std::string folder = message_in.getValue("folder"); bool get_directory = (filter == "directory"); // We about to completely block on running the modal File/Dir picker window, so flush any pending messages to the viewer. flushMessages(); bool canceled; if (get_directory) { canceled = !LLDirPicker::instance().getDir(folder); } else if (type == "save") { canceled = !LLFilePicker::instance().getSaveFile(str2savefilter(filter), message_in.getValue("default"), folder); } else if (type == "load") { canceled = !LLFilePicker::instance().getLoadFile(str2loadfilter(filter), folder); } else // type == "load_multiple" { canceled = !LLFilePicker::instance().getMultipleLoadFiles(str2loadfilter(filter), folder); } if (canceled) { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_BASIC, "canceled"); message.setValue("perseus", "unblock"); sendMessage(message); } else { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_BASIC, "done"); message.setValue("perseus", "unblock"); LLSD filenames; if (get_directory) { filenames.append(LLDirPicker::instance().getDirName()); } else { for (std::string filename = LLFilePicker::instance().getFirstFile(); !filename.empty(); filename = LLFilePicker::instance().getNextFile()) { filenames.append(filename); } } message.setValueLLSD("filenames", filenames); sendMessage(message); } // We're done. Exit the whole application. // This first flushes any messages before terminating the plugin. sendShutdownMessage(); } else { std::cerr << "FilepickerPlugin::receiveMessage: unknown basic message: " << message_name << std::endl; } } else { std::cerr << "FilepickerPlugin::receiveMessage: unknown message class: " << message_class << std::endl; } } }