linux-trace-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Steven Rostedt <rostedt@goodmis.org>
To: "Yordan Karadzhov (VMware)" <y.karadz@gmail.com>
Cc: linux-trace-devel@vger.kernel.org
Subject: Re: [PATCH 1/7] kernel-shark-qt: Add plugin infrastructure to be used by the Qt-baset KS.
Date: Wed, 29 Aug 2018 16:32:53 -0400	[thread overview]
Message-ID: <20180829163253.7ba150f5@gandalf.local.home> (raw)
In-Reply-To: <20180829164224.20677-2-y.karadz@gmail.com>

On Wed, 29 Aug 2018 19:42:18 +0300
"Yordan Karadzhov (VMware)" <y.karadz@gmail.com> wrote:
> diff --git a/kernel-shark-qt/src/libkshark-plugin.c b/kernel-shark-qt/src/libkshark-plugin.c
> new file mode 100644
> index 0000000..7d9c5a0
> --- /dev/null
> +++ b/kernel-shark-qt/src/libkshark-plugin.c
> @@ -0,0 +1,292 @@
> +// SPDX-License-Identifier: LGPL-2.1
> +
> +/*
> + * Copyright (C) 2017 VMware Inc, Yordan Karadzhov <y.karadz@gmail.com>
> + */
> +
> + /**
> +  *  @file    libkshark-plugin.c
> +  *  @brief   KernelShark plugins.
> +  */
> +
> +// C
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/stat.h>
> +#include <dlfcn.h>
> +
> +// KernelShark
> +#include "libkshark-plugin.h"
> +#include "libkshark.h"
> +
> +static struct kshark_event_handler *
> +gui_event_handler_alloc(int event_id,
> +			kshark_plugin_event_handler_func evt_func,
> +			kshark_plugin_draw_handler_func dw_func)
> +{
> +	struct kshark_event_handler *handler = malloc(sizeof(*handler));
> +
> +	if (!handler) {
> +		fprintf(stderr,
> +			"failed to allocate memory for gui eventhandler");
> +		return NULL;
> +	}
> +
> +	handler->next = NULL;
> +	handler->id = event_id;
> +	handler->event_func = evt_func;
> +	handler->draw_func = dw_func;
> +
> +	return handler;
> +}
> +
> +/**
> + * @brief Search the list of event handlers for a handle associated with a given event type.
> + *
> + * @param handlers: Input location for the Event handler list.
> + * @param event_id: Event Id to search for.
> + */
> +struct kshark_event_handler *
> +find_event_handler(struct kshark_event_handler *handlers, int event_id)
> +{
> +	while (handlers) {

Note, I prefer these to be for loops. Whenever there's a simple
iteration, a for loop is best to use (note this is what is expected in
the kernel too).

	for (; handlers; handles = handles->next) {

> +		if (handlers->id == event_id)
> +			return handlers;

	}

	return NULL;

> +
> +		handlers = handlers->next;
> +	}
> +
> +	return NULL;
> +}
> +
> +/**
> + * @brief Add new event handler to an existing list of handlers.
> + *
> + * @param handlers: Input location for the Event handler list.
> + * @param event_id: Event Id.
> + * @param evt_func: Input location for an Event action provided by the plugin.
> + * @param dw_func: Input location for a Draw action provided by the plugin.
> + */
> +void kshark_register_event_handler(struct kshark_event_handler **handlers,

This should return 0 on success and negative on error (failed malloc).


> +				   int event_id,
> +				   kshark_plugin_event_handler_func evt_func,
> +				   kshark_plugin_draw_handler_func dw_func)
> +{
> +	struct kshark_event_handler *handler =
> +		gui_event_handler_alloc(event_id, evt_func, dw_func);
> +
> +	if(!handler)
> +		return;
> +
> +	handler->next = *handlers;
> +	*handlers = handler;
> +}
> +
> +/**
> + * @brief Search the list for a specific plugin handle. If such a plugin handle
> + *	  exists, unregister (remove and free) this handle from the list.
> + *
> + * @param handlers: Input location for the Event handler list.
> + * @param event_id: Event Id of the plugin handler to be unregistered.
> + * @param evt_func: Event action function of the handler to be unregistered.
> + * @param dw_func: Draw action function of the handler to be unregistered.
> + */
> +void
> +kshark_unregister_event_handler(struct kshark_event_handler **handlers,
> +				int event_id,
> +				kshark_plugin_event_handler_func evt_func,
> +				kshark_plugin_draw_handler_func dw_func)
> +{
> +	struct kshark_event_handler **last = handlers;
> +	struct kshark_event_handler *list;
> +
> +	for (list = *handlers; list; list = list->next) {

You can simplify this to:

	for (last = handlers; *last; last = &(*last)->next) {
		list = *last;

> +		if (list->id == event_id &&
> +		    list->event_func == evt_func &&
> +		    list->draw_func == dw_func) {
> +			*last = list->next;
> +			free(list);
> +			return;
> +		}
> +


> +		last = &list->next;

Then you can remove the above line.

> +	}
> +}
> +
> +/**
> + * @brief Free all Event handlers in a given list.
> + *
> + * @param handlers: Input location for the Event handler list.
> + */
> +void kshark_free_event_handler_list(struct kshark_event_handler *handlers)
> +{
> +	struct kshark_event_handler *last;
> +
> +	while (handlers) {
> +		last = handlers;
> +		handlers = handlers->next;
> +		free(last);
> +	}
> +}
> +
> +/**
> + * @brief Allocate memory for a new plugin. Add this plugin to the list of
> + *	  plugins used by the session.
> + *
> + * @param kshark_ctx: Input location for the session context pointer.
> + * @param file: The plugin object file to load.
> + */
> +void kshark_register_plugin(struct kshark_context *kshark_ctx,
> +			    const char *file)

Should return zero on success, and a negative on failure to add.

> +{
> +	struct kshark_plugin_list *plugin = kshark_ctx->plugins;
> +	struct stat st;
> +	int ret;
> +
> +	while (plugin) {
> +		if (strcmp(plugin->file, file) == 0)
> +			return;

			return -EEXIST;

> +
> +		plugin = plugin->next;
> +	}
> +
> +	ret = stat(file, &st);
> +	if (ret < 0) {
> +		fprintf(stderr, "plugin %s not found\n", file);
> +		return;

		return -ENODEV;

> +	}
> +
> +	plugin = calloc(sizeof(struct kshark_plugin_list), 1);
> +	if (!plugin) {
> +		fprintf(stderr, "failed to allocate memory for plugin\n");
> +		return;

		return -ENOMEM;

> +	}
> +
> +	asprintf(&plugin->file, "%s", file);
> +	plugin->handle = NULL;
> +
> +	plugin->next = kshark_ctx->plugins;
> +	kshark_ctx->plugins = plugin;

	return 0;

> +}
> +
> +/**
> + * @brief Register a new plugin..
> + *
> + * @param kshark_ctx: Input location for context pointer.
> + * @param file: The plugin object file to load.
> + */
> +void kshark_unregister_plugin(struct kshark_context *kshark_ctx,
> +			      const char *file)
> +{
> +	struct kshark_plugin_list **last = &kshark_ctx->plugins;
> +	struct kshark_plugin_list *list;
> +
> +	for (list = kshark_ctx->plugins; list; list = list->next) {

Same simplification can be done here.

> +		if (strcmp(list->file, file) == 0) {
> +			*last = list->next;
> +			free(list->file);
> +			free(list);
> +			return;
> +		}
> +
> +		last = &list->next;
> +	}
> +}
> +
> +/**
> + * @brief Free all plugins in a given list.
> + *
> + * @param plugins: Input location for the plugins list.
> + */
> +void kshark_free_plugin_list(struct kshark_plugin_list *plugins)
> +{
> +	struct kshark_plugin_list *last;
> +
> +	while (plugins) {
> +		last = plugins;
> +		plugins = plugins->next;
> +		free(last->file);
> +		free(last);
> +	}
> +}
> +
> +/**
> + * @brief Use this function to load/reload/unload all registered plugins.
> + *
> + * @param kshark_ctx: Input location for context pointer.
> + * @param task_id: Action identifier specifying the action to be executed.
> + */
> +void kshark_handle_plugins(struct kshark_context *kshark_ctx,

Should return 0 on success, negative on error.

> +			   int task_id)
> +{
> +	kshark_plugin_load_func func;
> +	struct kshark_plugin_list *plugin;
> +	char* func_name;
> +	int fn_size = 0;
> +
> +	switch (task_id) {
> +		case KSHARK_PLUGIN_LOAD:
> +			fn_size = asprintf(&func_name,
> +					   KSHARK_PLUGIN_LOADER_NAME);
> +			break;
> +
> +		case KSHARK_PLUGIN_RELOAD:
> +			fn_size = asprintf(&func_name,
> +					   KSHARK_PLUGIN_RELOADER_NAME);
> +			break;
> +
> +		case KSHARK_PLUGIN_UNLOAD:
> +			fn_size = asprintf(&func_name,
> +					   KSHARK_PLUGIN_UNLOADER_NAME);
> +			break;
> +
> +		default:
> +			return;

			return -EINVAL;

> +	}
> +
> +	if (fn_size <= 0) {
> +		fprintf(stderr,
> +			"failed to allocate memory for plugin function name");
> +		return;

		return -ENOMEM;

> +	}
> +
> +	for (plugin = kshark_ctx->plugins; plugin; plugin = plugin->next) {
> +		if (task_id == KSHARK_PLUGIN_LOAD) {
> +			plugin->handle =
> +				dlopen(plugin->file, RTLD_NOW | RTLD_GLOBAL);
> +
> +			if (!plugin->handle) {
> +				fprintf(stderr,
> +					"cannot load plugin '%s'\n%s\n",
> +					plugin->file,
> +					dlerror());
> +
> +				continue;
> +			}
> +		}
> +
> +		func = dlsym(plugin->handle, func_name);
> +		if (!func) {
> +			fprintf(stderr,
> +				"cannot find func '%s' in plugin '%s'\n%s\n",
> +				func_name,
> +				plugin->file,
> +				dlerror());
> +
> +			dlclose(plugin->handle);
> +			plugin->handle = NULL;
> +			continue;
> +		}
> +
> +		func();
> +
> +		if (task_id == KSHARK_PLUGIN_UNLOAD && plugin->handle) {
> +			dlclose(plugin->handle);
> +			plugin->handle = NULL;
> +		}
> +	}
> +
> +	free(func_name);

Hmm, perhaps we should return the number of successful operations?

-- Steve

> +}
> diff --git a/kernel-shark-qt/src/libkshark-plugin.h b/kernel-shark-qt/src/libkshark-plugin.h
> new file mode 100644
> index 0000000..7328197

  parent reply	other threads:[~2018-08-30  0:31 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-08-29 16:42 [PATCH 0/7] The infrastructure for plugins used by the Qt-based Yordan Karadzhov (VMware)
2018-08-29 16:42 ` [PATCH 1/7] kernel-shark-qt: Add plugin infrastructure to be used by the Qt-baset KS Yordan Karadzhov (VMware)
2018-08-29 20:12   ` Steven Rostedt
2018-08-29 20:17   ` Steven Rostedt
2018-08-29 20:32   ` Steven Rostedt [this message]
2018-08-30 11:45     ` Yordan Karadzhov (VMware)
2018-08-30 16:17       ` Steven Rostedt
2018-08-29 16:42 ` [PATCH 2/7] kernel-shark-qt: Add Plugin event handlers to session Yordan Karadzhov (VMware)
2018-08-30  2:08   ` Steven Rostedt
2018-08-29 16:42 ` [PATCH 3/7] kernel-shark-qt: Add C++/C conversion for args of a plugin draw function Yordan Karadzhov (VMware)
2018-08-29 16:42 ` [PATCH 4/7] kernel-shark-qt: Make kshark_read_at() non-static Yordan Karadzhov (VMware)
2018-08-29 16:42 ` [PATCH 5/7] kernel-shark-qt: Add src/plugins dir. to hold the source code of the plugins Yordan Karadzhov (VMware)
2018-08-29 16:42 ` [PATCH 6/7] kernel-shark-qt: Tell Doxygen to enter ../src/plugins/ Yordan Karadzhov (VMware)
2018-08-29 16:42 ` [PATCH 7/7] kernel-shark-qt: Add a plugin for sched events Yordan Karadzhov (VMware)
2018-08-30  2:43   ` Steven Rostedt
2018-08-30 11:48     ` Yordan Karadzhov (VMware)
2018-08-30 11:49       ` Yordan Karadzhov (VMware)
2018-08-30 14:12       ` Steven Rostedt
2018-08-30 11:51     ` Yordan Karadzhov (VMware)
2018-08-30 14:13       ` Steven Rostedt
2018-08-30 14:50     ` Steven Rostedt
2018-08-30 17:38   ` Steven Rostedt
2018-08-29 16:49 ` [PATCH 0/7] Add infrastructure for plugins Yordan Karadzhov (VMware)
  -- strict thread matches above, loose matches on Subject: below --
2018-09-04 15:52 Yordan Karadzhov (VMware)
2018-09-04 15:52 ` [PATCH 1/7] kernel-shark-qt: Add plugin infrastructure to be used by the Qt-baset KS Yordan Karadzhov (VMware)
2018-09-05  2:09   ` Steven Rostedt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180829163253.7ba150f5@gandalf.local.home \
    --to=rostedt@goodmis.org \
    --cc=linux-trace-devel@vger.kernel.org \
    --cc=y.karadz@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).