| // SPDX-License-Identifier: LGPL-2.1 | |
| /* | |
| * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <ykaradzhov@vmware.com> | |
| */ | |
| /** | |
| * @file KsUtils.cpp | |
| * @brief KernelShark Utils. | |
| */ | |
| // KernelShark | |
| #include "KsUtils.hpp" | |
| #include "KsWidgetsLib.hpp" | |
| namespace KsUtils { | |
| /** @brief Get a sorted vector of Task's Pids. */ | |
| QVector<int> getPidList() | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| int nTasks, *tempPids; | |
| QVector<int> pids; | |
| if (!kshark_instance(&kshark_ctx)) | |
| return pids; | |
| nTasks = kshark_get_task_pids(kshark_ctx, &tempPids); | |
| for (int r = 0; r < nTasks; ++r) { | |
| pids.append(tempPids[r]); | |
| } | |
| free(tempPids); | |
| qSort(pids); | |
| return pids; | |
| } | |
| /** @brief Get a sorted vector of Id values of a filter. */ | |
| QVector<int> getFilterIds(tracecmd_filter_id *filter) | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| int *cpuFilter, n; | |
| QVector<int> v; | |
| if (!kshark_instance(&kshark_ctx)) | |
| return v; | |
| cpuFilter = tracecmd_filter_ids(filter); | |
| n = filter->count; | |
| for (int i = 0; i < n; ++i) | |
| v.append(cpuFilter[i]); | |
| qSort(v); | |
| free(cpuFilter); | |
| return v; | |
| } | |
| /** | |
| * Set the bit of the filter mask of the kshark session context responsible | |
| * for the visibility of the events in the Table View. | |
| */ | |
| void listFilterSync(bool state) | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| if (!kshark_instance(&kshark_ctx)) | |
| return; | |
| if (state) { | |
| kshark_ctx->filter_mask |= KS_TEXT_VIEW_FILTER_MASK; | |
| } else { | |
| kshark_ctx->filter_mask &= ~KS_TEXT_VIEW_FILTER_MASK; | |
| } | |
| } | |
| /** | |
| * Set the bit of the filter mask of the kshark session context responsible | |
| * for the visibility of the events in the Graph View. | |
| */ | |
| void graphFilterSync(bool state) | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| if (!kshark_instance(&kshark_ctx)) | |
| return; | |
| if (state) { | |
| kshark_ctx->filter_mask |= KS_GRAPH_VIEW_FILTER_MASK; | |
| kshark_ctx->filter_mask |= KS_EVENT_VIEW_FILTER_MASK; | |
| } else { | |
| kshark_ctx->filter_mask &= ~KS_GRAPH_VIEW_FILTER_MASK; | |
| kshark_ctx->filter_mask &= ~KS_EVENT_VIEW_FILTER_MASK; | |
| } | |
| } | |
| /** | |
| * @brief Add a checkbox to a menu. | |
| * | |
| * @param menu: Input location for the menu object, to which the checkbox will be added. | |
| * @param name: The name of the checkbox. | |
| * | |
| * @returns The checkbox object; | |
| */ | |
| QCheckBox *addCheckBoxToMenu(QMenu *menu, QString name) | |
| { | |
| QWidget *containerWidget = new QWidget(menu); | |
| containerWidget->setLayout(new QHBoxLayout()); | |
| containerWidget->layout()->setContentsMargins(FONT_WIDTH, FONT_HEIGHT/5, | |
| FONT_WIDTH, FONT_HEIGHT/5); | |
| QCheckBox *checkBox = new QCheckBox(name, menu); | |
| containerWidget->layout()->addWidget(checkBox); | |
| QWidgetAction *action = new QWidgetAction(menu); | |
| action->setDefaultWidget(containerWidget); | |
| menu->addAction(action); | |
| return checkBox; | |
| } | |
| /** | |
| * @brief Simple CPU matching function to be user for data collections. | |
| * | |
| * @param kshark_ctx: Input location for the session context pointer. | |
| * @param e: kshark_entry to be checked. | |
| * @param cpu: Matching condition value. | |
| * | |
| * @returns True if the CPU of the entry matches the value of "cpu" and | |
| * the entry is visibility in Graph. Otherwise false. | |
| */ | |
| bool matchCPUVisible(struct kshark_context *kshark_ctx, | |
| struct kshark_entry *e, int cpu) | |
| { | |
| return (e->cpu == cpu && (e->visible & KS_GRAPH_VIEW_FILTER_MASK)); | |
| } | |
| /** | |
| * @brief Check if the application runs from its installation location. | |
| */ | |
| bool isInstalled() | |
| { | |
| QString appPath = QCoreApplication::applicationDirPath(); | |
| QString installPath(_INSTALL_PREFIX); | |
| installPath += "/bin"; | |
| installPath = QDir::cleanPath(installPath); | |
| return appPath == installPath; | |
| } | |
| static QString getFileDialog(QWidget *parent, | |
| const QString &windowName, | |
| const QString &filter, | |
| QString &lastFilePath, | |
| bool forSave) | |
| { | |
| QString fileName; | |
| if (lastFilePath.isEmpty()) { | |
| lastFilePath = isInstalled() ? QDir::homePath() : | |
| QDir::currentPath(); | |
| } | |
| if (forSave) { | |
| fileName = QFileDialog::getSaveFileName(parent, | |
| windowName, | |
| lastFilePath, | |
| filter); | |
| } else { | |
| fileName = QFileDialog::getOpenFileName(parent, | |
| windowName, | |
| lastFilePath, | |
| filter); | |
| } | |
| if (!fileName.isEmpty()) | |
| lastFilePath = QFileInfo(fileName).path(); | |
| return fileName; | |
| } | |
| static QStringList getFilesDialog(QWidget *parent, | |
| const QString &windowName, | |
| const QString &filter, | |
| QString &lastFilePath) | |
| { | |
| QStringList fileNames; | |
| if (lastFilePath.isEmpty()) { | |
| lastFilePath = isInstalled() ? QDir::homePath() : | |
| QDir::currentPath(); | |
| } | |
| fileNames = QFileDialog::getOpenFileNames(parent, | |
| windowName, | |
| lastFilePath, | |
| filter); | |
| if (!fileNames.isEmpty()) | |
| lastFilePath = QFileInfo(fileNames[0]).path(); | |
| return fileNames; | |
| } | |
| /** | |
| * @brief Open a standard Qt getFileName dialog and return the name of the | |
| * selected file. Only one file can be selected. | |
| */ | |
| QString getFile(QWidget *parent, | |
| const QString &windowName, | |
| const QString &filter, | |
| QString &lastFilePath) | |
| { | |
| return getFileDialog(parent, windowName, filter, lastFilePath, false); | |
| } | |
| /** | |
| * @brief Open a standard Qt getFileName dialog and return the names of the | |
| * selected files. Multiple files can be selected. | |
| */ | |
| QStringList getFiles(QWidget *parent, | |
| const QString &windowName, | |
| const QString &filter, | |
| QString &lastFilePath) | |
| { | |
| return getFilesDialog(parent, windowName, filter, lastFilePath); | |
| } | |
| /** | |
| * @brief Open a standard Qt getFileName dialog and return the name of the | |
| * selected file. Only one file can be selected. | |
| */ | |
| QString getSaveFile(QWidget *parent, | |
| const QString &windowName, | |
| const QString &filter, | |
| const QString &extension, | |
| QString &lastFilePath) | |
| { | |
| QString fileName = getFileDialog(parent, | |
| windowName, | |
| filter, | |
| lastFilePath, | |
| true); | |
| if (!fileName.isEmpty() && !fileName.endsWith(extension)) { | |
| fileName += extension; | |
| if (QFileInfo(fileName).exists()) { | |
| if (!KsWidgetsLib::fileExistsDialog(fileName)) | |
| fileName.clear(); | |
| } | |
| } | |
| return fileName; | |
| } | |
| }; // KsUtils | |
| /** A stream operator for converting QColor into KsPlot::Color. */ | |
| KsPlot::Color& operator <<(KsPlot::Color &thisColor, const QColor &c) | |
| { | |
| thisColor.set(c.red(), c.green(), c.blue()); | |
| return thisColor; | |
| } | |
| /** Create a default (empty) KsDataStore. */ | |
| KsDataStore::KsDataStore(QWidget *parent) | |
| : QObject(parent), | |
| _tep(nullptr), | |
| _rows(nullptr), | |
| _dataSize(0) | |
| {} | |
| /** Destroy the KsDataStore object. */ | |
| KsDataStore::~KsDataStore() | |
| {} | |
| /** Load trace data for file. */ | |
| void KsDataStore::loadDataFile(const QString &file) | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| if (!kshark_instance(&kshark_ctx)) | |
| return; | |
| clear(); | |
| if (!kshark_open(kshark_ctx, file.toStdString().c_str())) { | |
| qCritical() << "ERROR Loading file " << file; | |
| return; | |
| } | |
| _tep = kshark_ctx->pevent; | |
| if (kshark_ctx->event_handlers == nullptr) | |
| kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_INIT); | |
| else | |
| kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_UPDATE); | |
| _dataSize = kshark_load_data_entries(kshark_ctx, &_rows); | |
| } | |
| void KsDataStore::_freeData() | |
| { | |
| if (_dataSize > 0) { | |
| for (ssize_t r = 0; r < _dataSize; ++r) | |
| free(_rows[r]); | |
| free(_rows); | |
| } | |
| _rows = nullptr; | |
| _dataSize = 0; | |
| } | |
| /** Reload the trace data. */ | |
| void KsDataStore::reload() | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| if (!kshark_instance(&kshark_ctx)) | |
| return; | |
| _freeData(); | |
| _dataSize = kshark_load_data_entries(kshark_ctx, &_rows); | |
| _tep = kshark_ctx->pevent; | |
| emit updateWidgets(this); | |
| } | |
| /** Free the loaded trace data and close the file. */ | |
| void KsDataStore::clear() | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| _freeData(); | |
| _tep = nullptr; | |
| if (kshark_instance(&kshark_ctx) && kshark_ctx->handle) | |
| kshark_close(kshark_ctx); | |
| } | |
| /** Update the visibility of the entries (filter). */ | |
| void KsDataStore::update() | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| if (!kshark_instance(&kshark_ctx)) | |
| return; | |
| _unregisterCPUCollections(); | |
| if (kshark_filter_is_set(kshark_ctx)) { | |
| kshark_filter_entries(kshark_ctx, _rows, _dataSize); | |
| emit updateWidgets(this); | |
| } | |
| registerCPUCollections(); | |
| } | |
| /** Register a collection of visible entries for each CPU. */ | |
| void KsDataStore::registerCPUCollections() | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| if (!kshark_instance(&kshark_ctx) || | |
| !kshark_filter_is_set(kshark_ctx)) | |
| return; | |
| int nCPUs = tep_get_cpus(_tep); | |
| for (int cpu = 0; cpu < nCPUs; ++cpu) { | |
| kshark_register_data_collection(kshark_ctx, | |
| _rows, _dataSize, | |
| KsUtils::matchCPUVisible, | |
| cpu, | |
| 0); | |
| } | |
| } | |
| void KsDataStore::_unregisterCPUCollections() | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| if (!kshark_instance(&kshark_ctx)) | |
| return; | |
| int nCPUs = tep_get_cpus(_tep); | |
| for (int cpu = 0; cpu < nCPUs; ++cpu) { | |
| kshark_unregister_data_collection(&kshark_ctx->collections, | |
| KsUtils::matchCPUVisible, | |
| cpu); | |
| } | |
| } | |
| void KsDataStore::_applyIdFilter(int filterId, QVector<int> vec) | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| if (!kshark_instance(&kshark_ctx)) | |
| return; | |
| switch (filterId) { | |
| case KS_SHOW_EVENT_FILTER: | |
| case KS_HIDE_EVENT_FILTER: | |
| kshark_filter_clear(kshark_ctx, KS_SHOW_EVENT_FILTER); | |
| kshark_filter_clear(kshark_ctx, KS_HIDE_EVENT_FILTER); | |
| break; | |
| case KS_SHOW_TASK_FILTER: | |
| case KS_HIDE_TASK_FILTER: | |
| kshark_filter_clear(kshark_ctx, KS_SHOW_TASK_FILTER); | |
| kshark_filter_clear(kshark_ctx, KS_HIDE_TASK_FILTER); | |
| break; | |
| case KS_SHOW_CPU_FILTER: | |
| case KS_HIDE_CPU_FILTER: | |
| kshark_filter_clear(kshark_ctx, KS_SHOW_CPU_FILTER); | |
| kshark_filter_clear(kshark_ctx, KS_HIDE_CPU_FILTER); | |
| break; | |
| default: | |
| return; | |
| } | |
| for (auto &&val: vec) | |
| kshark_filter_add_id(kshark_ctx, filterId, val); | |
| if (!_tep) | |
| return; | |
| _unregisterCPUCollections(); | |
| /* | |
| * If the advanced event filter is set, the data has to be reloaded, | |
| * because the advanced filter uses tep_records. | |
| */ | |
| if (kshark_ctx->advanced_event_filter->filters) | |
| reload(); | |
| else | |
| kshark_filter_entries(kshark_ctx, _rows, _dataSize); | |
| registerCPUCollections(); | |
| emit updateWidgets(this); | |
| } | |
| /** Apply Show Task filter. */ | |
| void KsDataStore::applyPosTaskFilter(QVector<int> vec) | |
| { | |
| _applyIdFilter(KS_SHOW_TASK_FILTER, vec); | |
| } | |
| /** Apply Hide Task filter. */ | |
| void KsDataStore::applyNegTaskFilter(QVector<int> vec) | |
| { | |
| _applyIdFilter(KS_HIDE_TASK_FILTER, vec); | |
| } | |
| /** Apply Show Event filter. */ | |
| void KsDataStore::applyPosEventFilter(QVector<int> vec) | |
| { | |
| _applyIdFilter(KS_SHOW_EVENT_FILTER, vec); | |
| } | |
| /** Apply Hide Event filter. */ | |
| void KsDataStore::applyNegEventFilter(QVector<int> vec) | |
| { | |
| _applyIdFilter(KS_HIDE_EVENT_FILTER, vec); | |
| } | |
| /** Apply Show CPU filter. */ | |
| void KsDataStore::applyPosCPUFilter(QVector<int> vec) | |
| { | |
| _applyIdFilter(KS_SHOW_CPU_FILTER, vec); | |
| } | |
| /** Apply Hide CPU filter. */ | |
| void KsDataStore::applyNegCPUFilter(QVector<int> vec) | |
| { | |
| _applyIdFilter(KS_HIDE_CPU_FILTER, vec); | |
| } | |
| /** Disable all filters. */ | |
| void KsDataStore::clearAllFilters() | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| if (!kshark_instance(&kshark_ctx) || !_tep) | |
| return; | |
| _unregisterCPUCollections(); | |
| kshark_filter_clear(kshark_ctx, KS_SHOW_TASK_FILTER); | |
| kshark_filter_clear(kshark_ctx, KS_HIDE_TASK_FILTER); | |
| kshark_filter_clear(kshark_ctx, KS_SHOW_EVENT_FILTER); | |
| kshark_filter_clear(kshark_ctx, KS_HIDE_EVENT_FILTER); | |
| kshark_filter_clear(kshark_ctx, KS_SHOW_CPU_FILTER); | |
| kshark_filter_clear(kshark_ctx, KS_HIDE_CPU_FILTER); | |
| tep_filter_reset(kshark_ctx->advanced_event_filter); | |
| kshark_clear_all_filters(kshark_ctx, _rows, _dataSize); | |
| emit updateWidgets(this); | |
| } | |
| /** | |
| * @brief Create Plugin Manager. Use list of plugins declared in the | |
| * CMake-generated header file. | |
| */ | |
| KsPluginManager::KsPluginManager(QWidget *parent) | |
| : QObject(parent) | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| _parsePluginList(); | |
| if (!kshark_instance(&kshark_ctx)) | |
| return; | |
| registerFromList(kshark_ctx); | |
| } | |
| /** Parse the plugin list declared in the CMake-generated header file. */ | |
| void KsPluginManager::_parsePluginList() | |
| { | |
| _ksPluginList = KsUtils::getPluginList(); | |
| int nPlugins = _ksPluginList.count(); | |
| _registeredKsPlugins.resize(nPlugins); | |
| for (int i = 0; i < nPlugins; ++i) { | |
| if (_ksPluginList[i].contains(" default", Qt::CaseInsensitive)) { | |
| _ksPluginList[i].remove(" default", Qt::CaseInsensitive); | |
| _registeredKsPlugins[i] = true; | |
| } else { | |
| _registeredKsPlugins[i] = false; | |
| } | |
| } | |
| } | |
| /** | |
| * Register the plugins by using the information in "_ksPluginList" and | |
| * "_registeredKsPlugins". | |
| */ | |
| void KsPluginManager::registerFromList(kshark_context *kshark_ctx) | |
| { | |
| auto lamRegBuiltIn = [&kshark_ctx, this](const QString &plugin) | |
| { | |
| char *lib; | |
| int n; | |
| lib = _pluginLibFromName(plugin, n); | |
| if (n <= 0) | |
| return; | |
| kshark_register_plugin(kshark_ctx, lib); | |
| free(lib); | |
| }; | |
| auto lamRegUser = [&kshark_ctx](const QString &plugin) | |
| { | |
| std::string lib = plugin.toStdString(); | |
| kshark_register_plugin(kshark_ctx, lib.c_str()); | |
| }; | |
| _forEachInList(_ksPluginList, | |
| _registeredKsPlugins, | |
| lamRegBuiltIn); | |
| _forEachInList(_userPluginList, | |
| _registeredUserPlugins, | |
| lamRegUser); | |
| } | |
| /** | |
| * Unegister the plugins by using the information in "_ksPluginList" and | |
| * "_registeredKsPlugins". | |
| */ | |
| void KsPluginManager::unregisterFromList(kshark_context *kshark_ctx) | |
| { | |
| auto lamUregBuiltIn = [&kshark_ctx, this](const QString &plugin) | |
| { | |
| char *lib; | |
| int n; | |
| lib = _pluginLibFromName(plugin, n); | |
| if (n <= 0) | |
| return; | |
| kshark_unregister_plugin(kshark_ctx, lib); | |
| free(lib); | |
| }; | |
| auto lamUregUser = [&kshark_ctx](const QString &plugin) | |
| { | |
| std::string lib = plugin.toStdString(); | |
| kshark_unregister_plugin(kshark_ctx, lib.c_str()); | |
| }; | |
| _forEachInList(_ksPluginList, | |
| _registeredKsPlugins, | |
| lamUregBuiltIn); | |
| _forEachInList(_userPluginList, | |
| _registeredUserPlugins, | |
| lamUregUser); | |
| } | |
| char *KsPluginManager::_pluginLibFromName(const QString &plugin, int &n) | |
| { | |
| QString appPath = QCoreApplication::applicationDirPath(); | |
| QString libPath = appPath + "/../../kernel-shark/lib"; | |
| std::string pluginStr = plugin.toStdString(); | |
| char *lib; | |
| libPath = QDir::cleanPath(libPath); | |
| if (!KsUtils::isInstalled() && QDir(libPath).exists()) { | |
| std::string pathStr = libPath.toStdString(); | |
| n = asprintf(&lib, "%s/plugin-%s.so", | |
| pathStr.c_str(), pluginStr.c_str()); | |
| } else { | |
| n = asprintf(&lib, "%s/plugin-%s.so", | |
| KS_PLUGIN_INSTALL_PREFIX, pluginStr.c_str()); | |
| } | |
| return lib; | |
| } | |
| /** | |
| * @brief Register a Plugin. | |
| * | |
| * @param plugin: provide here the name of the plugin (as in the CMake-generated | |
| * header file) of a name of the plugin's library file (.so). | |
| */ | |
| void KsPluginManager::registerPlugin(const QString &plugin) | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| char *lib; | |
| int n; | |
| if (!kshark_instance(&kshark_ctx)) | |
| return; | |
| for (int i = 0; i < _ksPluginList.count(); ++i) { | |
| if (_ksPluginList[i] == plugin) { | |
| /* | |
| * The argument is the name of the plugin. From the | |
| * name get the library .so file. | |
| */ | |
| lib = _pluginLibFromName(plugin, n); | |
| if (n > 0) { | |
| kshark_register_plugin(kshark_ctx, lib); | |
| _registeredKsPlugins[i] = true; | |
| free(lib); | |
| } | |
| return; | |
| } else if (plugin.contains("/lib/plugin-" + _ksPluginList[i], | |
| Qt::CaseInsensitive)) { | |
| /* | |
| * The argument is the name of the library .so file. | |
| */ | |
| n = asprintf(&lib, "%s", plugin.toStdString().c_str()); | |
| if (n > 0) { | |
| kshark_register_plugin(kshark_ctx, lib); | |
| _registeredKsPlugins[i] = true; | |
| free(lib); | |
| } | |
| return; | |
| } | |
| } | |
| /* No plugin with this name in the list. Try to add it anyway. */ | |
| if (plugin.endsWith(".so") && QFileInfo::exists(plugin)) { | |
| kshark_register_plugin(kshark_ctx, | |
| plugin.toStdString().c_str()); | |
| _userPluginList.append(plugin); | |
| _registeredUserPlugins.append(true); | |
| } else { | |
| qCritical() << "ERROR: " << plugin << "cannot be registered!"; | |
| } | |
| } | |
| /** @brief Unregister a Built in KernelShark plugin. | |
| *<br> | |
| * WARNING: Do not use this function to unregister User plugins. | |
| * Instead use directly kshark_unregister_plugin(). | |
| * | |
| * @param plugin: provide here the name of the plugin (as in the CMake-generated | |
| * header file) or a name of the plugin's library file (.so). | |
| * | |
| */ | |
| void KsPluginManager::unregisterPlugin(const QString &plugin) | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| char *lib; | |
| int n; | |
| if (!kshark_instance(&kshark_ctx)) | |
| return; | |
| for (int i = 0; i < _ksPluginList.count(); ++i) { | |
| if (_ksPluginList[i] == plugin) { | |
| /* | |
| * The argument is the name of the plugin. From the | |
| * name get the library .so file. | |
| */ | |
| lib = _pluginLibFromName(plugin, n); | |
| if (n > 0) { | |
| kshark_unregister_plugin(kshark_ctx, lib); | |
| _registeredKsPlugins[i] = false; | |
| free(lib); | |
| } | |
| return; | |
| } else if (plugin.contains("/lib/plugin-" + | |
| _ksPluginList[i], Qt::CaseInsensitive)) { | |
| /* | |
| * The argument is the name of the library .so file. | |
| */ | |
| n = asprintf(&lib, "%s", plugin.toStdString().c_str()); | |
| if (n > 0) { | |
| kshark_unregister_plugin(kshark_ctx, lib); | |
| _registeredKsPlugins[i] = false; | |
| free(lib); | |
| } | |
| return; | |
| } | |
| } | |
| } | |
| /** @brief Add to the list and initialize user-provided plugins. All other | |
| * previously loaded plugins will be reinitialized and the data will be | |
| * reloaded. | |
| * | |
| * @param fileNames: the library files (.so) of the plugins. | |
| */ | |
| void KsPluginManager::addPlugins(const QStringList &fileNames) | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| if (!kshark_instance(&kshark_ctx)) | |
| return; | |
| kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_CLOSE); | |
| for (auto const &p: fileNames) | |
| registerPlugin(p); | |
| kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_INIT); | |
| emit dataReload(); | |
| } | |
| /** Unload all plugins. */ | |
| void KsPluginManager::unloadAll() | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| if (!kshark_instance(&kshark_ctx)) | |
| return; | |
| kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_CLOSE); | |
| kshark_free_plugin_list(kshark_ctx->plugins); | |
| kshark_ctx->plugins = nullptr; | |
| kshark_free_event_handler_list(kshark_ctx->event_handlers); | |
| unregisterFromList(kshark_ctx); | |
| } | |
| /** @brief Update (change) the Plugins. | |
| * | |
| * @param pluginIds: The indexes of the plugins to be loaded. | |
| */ | |
| void KsPluginManager::updatePlugins(QVector<int> pluginIds) | |
| { | |
| kshark_context *kshark_ctx(nullptr); | |
| if (!kshark_instance(&kshark_ctx)) | |
| return; | |
| auto register_plugins = [&] (QVector<int> ids) | |
| { | |
| int nKsPlugins = _registeredKsPlugins.count(); | |
| /* First clear all registered plugins. */ | |
| for (auto &p: _registeredKsPlugins) | |
| p = false; | |
| for (auto &p: _registeredUserPlugins) | |
| p = false; | |
| /* The vector contains the indexes of those to register. */ | |
| for (auto const &p: ids) { | |
| if (p < nKsPlugins) | |
| _registeredKsPlugins[p] = true; | |
| else | |
| _registeredUserPlugins[p - nKsPlugins] = true; | |
| } | |
| registerFromList(kshark_ctx); | |
| }; | |
| if (!kshark_ctx->pevent) { | |
| kshark_free_plugin_list(kshark_ctx->plugins); | |
| kshark_ctx->plugins = nullptr; | |
| /* | |
| * No data is loaded. For the moment, just register the | |
| * plugins. Handling of the plugins will be done after | |
| * we load a data file. | |
| */ | |
| register_plugins(pluginIds); | |
| return; | |
| } | |
| /* Clean up all old plugins first. */ | |
| unloadAll(); | |
| /* Now load. */ | |
| register_plugins(pluginIds); | |
| kshark_handle_plugins(kshark_ctx, KSHARK_PLUGIN_INIT); | |
| emit dataReload(); | |
| } |