diff mbox series

[RFC,4/4] tcg/plugins: Add example pair of QPP plugins

Message ID 20220901182734.2987337-5-fasano@mit.edu
State New
Headers show
Series Support interactions between TCG plugins | expand

Commit Message

Andrew Fasano Sept. 1, 2022, 6:27 p.m. UTC
The first plugin, qpp_srv exposes two functions and one callback that other
plugins can leverage. These functions are described in the corresponding
header file.

The second plugin, qpp_client, imports this header file, registers its
own function to run on a qpp_srv-provided callback, and directly calls
into the two exposed functions in qpp_srv.

Signed-off-by: Andrew Fasano <fasano@mit.edu>
---
 contrib/plugins/Makefile     |  2 ++
 contrib/plugins/qpp_client.c | 42 ++++++++++++++++++++++++++++++++++++
 contrib/plugins/qpp_client.h |  1 +
 contrib/plugins/qpp_srv.c    | 33 ++++++++++++++++++++++++++++
 contrib/plugins/qpp_srv.h    | 17 +++++++++++++++
 5 files changed, 95 insertions(+)
 create mode 100644 contrib/plugins/qpp_client.c
 create mode 100644 contrib/plugins/qpp_client.h
 create mode 100644 contrib/plugins/qpp_srv.c
 create mode 100644 contrib/plugins/qpp_srv.h

Comments

Alex Bennée Sept. 21, 2022, 3:22 p.m. UTC | #1
Andrew Fasano <fasano@mit.edu> writes:

> The first plugin, qpp_srv exposes two functions and one callback that other
> plugins can leverage. These functions are described in the corresponding
> header file.
>
> The second plugin, qpp_client, imports this header file, registers its
> own function to run on a qpp_srv-provided callback, and directly calls
> into the two exposed functions in qpp_srv.

I'll just sketch out how I would change the API in this example plugin:

>
> Signed-off-by: Andrew Fasano <fasano@mit.edu>
> ---
>  contrib/plugins/Makefile     |  2 ++
>  contrib/plugins/qpp_client.c | 42 ++++++++++++++++++++++++++++++++++++
>  contrib/plugins/qpp_client.h |  1 +
>  contrib/plugins/qpp_srv.c    | 33 ++++++++++++++++++++++++++++
>  contrib/plugins/qpp_srv.h    | 17 +++++++++++++++
>  5 files changed, 95 insertions(+)
>  create mode 100644 contrib/plugins/qpp_client.c
>  create mode 100644 contrib/plugins/qpp_client.h
>  create mode 100644 contrib/plugins/qpp_srv.c
>  create mode 100644 contrib/plugins/qpp_srv.h
>
> diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile
> index b7720fea0f..b7510de89c 100644
> --- a/contrib/plugins/Makefile
> +++ b/contrib/plugins/Makefile
> @@ -21,6 +21,8 @@ NAMES += lockstep
>  NAMES += hwprofile
>  NAMES += cache
>  NAMES += drcov
> +NAMES += qpp_srv
> +NAMES += qpp_client
>  
>  SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
>  
> diff --git a/contrib/plugins/qpp_client.c b/contrib/plugins/qpp_client.c
> new file mode 100644
> index 0000000000..de3335e167
> --- /dev/null
> +++ b/contrib/plugins/qpp_client.c
> @@ -0,0 +1,42 @@
> +#include <stdio.h>
> +#include <qemu-plugin.h>
> +#include <plugin-qpp.h>
> +#include <glib.h>
> +#include "qpp_srv.h"
> +
> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;

QEMU_PLUGIN_EXPORT const char *qemu_plugin_name = "qpp_client";
QEMU_PLUGIN_EXPORT const char *qemu_plugin_uses = "qpp_server";

> +
> +void my_on_exit(int x, bool b)

void my_on_exit(gpointer evdata, gpointer udata)
{
  struct qpp_exit_event *info = (struct qpp_exit_event *) evdata;
  x = info->x;
  b = info->b;

> +{
> +  g_autoptr(GString) report = g_string_new("Client: on_exit runs with args: ");
> +  g_string_append_printf(report, "%d, %d\n", x, b);
> +  qemu_plugin_outs(report->str);
> +
> +  g_string_printf(report, "Client: calls qpp_srv's do_add(1): %d\n",
> +                          qpp_srv_do_add(1));
> +  qemu_plugin_outs(report->str);
> +
> +  g_string_printf(report, "Client: calls qpp_srv's do_sub(1): %d\n",
> +                           qpp_srv_do_sub(1));
> +  qemu_plugin_outs(report->str);
> +}
> +
> +
> +QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
> +                   const qemu_info_t *info, int argc, char **argv) {
> +
> +    /*
> +     * Register our "my_on_exit" function to run on the on_exit QPP-callback
> +     * exported by qpp_srv
> +     */
> +    QPP_REG_CB("qpp_srv", on_exit, my_on_exit);

   qemu_plugin_register_event_listener("qpp_server", "exit", my_on_exit);

> +
> +    g_autoptr(GString) report = g_string_new(CURRENT_PLUGIN ": Call "
> +                                             "qpp_srv's do_add(0) => ");
> +    g_string_append_printf(report, "%d\n", qpp_srv_do_add(0));
> +    qemu_plugin_outs(report->str);
> +
> +    g_string_printf(report, "Client: registered on_exit callback\n");
> +    return 0;
> +}
> +
> diff --git a/contrib/plugins/qpp_client.h b/contrib/plugins/qpp_client.h
> new file mode 100644
> index 0000000000..573923f580
> --- /dev/null
> +++ b/contrib/plugins/qpp_client.h
> @@ -0,0 +1 @@
> +void my_on_exit(int, bool);
> diff --git a/contrib/plugins/qpp_srv.c b/contrib/plugins/qpp_srv.c
> new file mode 100644
> index 0000000000..61a6ab38ed
> --- /dev/null
> +++ b/contrib/plugins/qpp_srv.c
> @@ -0,0 +1,33 @@
> +#include <stdio.h>
> +#include <qemu-plugin.h>
> +#include <plugin-qpp.h>
> +#include <gmodule.h>
> +#include "qpp_srv.h"
> +
> +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;

QEMU_PLUGIN_EXPORT const char *qemu_plugin_name = "qpp_server";

> +
> +QPP_CREATE_CB(on_exit);

void *on_exit;

> +
> +static void plugin_exit(qemu_plugin_id_t id, void *p)
> +{
> +  qemu_plugin_outs(CURRENT_PLUGIN "exit triggered, running all registered"
> +                  " QPP callbacks\n");
> +  QPP_RUN_CB(on_exit, 0, true);

     struct qpp_exit_event *info = g_new0(qpp_exit_event, 1);
     info->x = 0;
     info->b = true;
     qemu_plugin_trigger_event(on_exit, info);

> +}
> +
> +QEMU_PLUGIN_EXPORT int do_add(int x)

QEMU_PLUGIN_EXPORT int qpp_srv_do_add(int x)

> +{
> +  return x + 1;
> +}
> +
> +QEMU_PLUGIN_EXPORT int do_sub(int x)

QEMU_PLUGIN_EXPORT int qpp_srv_do_sub(int x)

> +{
> +  return x - 1;
> +}
> +
> +QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
> +                   const qemu_info_t *info, int argc, char **argv) {
> +    qemu_plugin_outs("qpp_srv loaded\n");
> +    qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
> +    return 0;
> +}
> diff --git a/contrib/plugins/qpp_srv.h b/contrib/plugins/qpp_srv.h
> new file mode 100644
> index 0000000000..ceb26e3d2c
> --- /dev/null
> +++ b/contrib/plugins/qpp_srv.h
> @@ -0,0 +1,17 @@
> +#ifndef QPP_SRV_H
> +#define QPP_SRV_H
> +
> +/*
> + * Prototype for the on_exit callback: callback functions should be
> + * of type `void f(int, bool)`
> + */
> +QPP_CB_PROTOTYPE(void, on_exit, int, bool);

can be dropped.

> +
> +/*
> + * Prototypes for the do_add and do_sub functions. Both return an int and
> + * take an int as an argument.
> + */
> +QPP_FUN_PROTOTYPE(qpp_srv, int, do_add, int);
> +QPP_FUN_PROTOTYPE(qpp_srv, int, do_sub, int);

int qpp_srv_do_add(int);
int qpp_srv_do_sub(int);

the linking is dealt with by loader.

> +
> +#endif /* QPP_SRV_H */
Alex Bennée Sept. 21, 2022, 3:36 p.m. UTC | #2
Andrew Fasano <fasano@mit.edu> writes:

> The first plugin, qpp_srv exposes two functions and one callback that other
> plugins can leverage. These functions are described in the corresponding
> header file.
>
> The second plugin, qpp_client, imports this header file, registers its
> own function to run on a qpp_srv-provided callback, and directly calls
> into the two exposed functions in qpp_srv.
>
> Signed-off-by: Andrew Fasano <fasano@mit.edu>
> ---
>  contrib/plugins/Makefile     |  2 ++
>  contrib/plugins/qpp_client.c | 42 ++++++++++++++++++++++++++++++++++++
>  contrib/plugins/qpp_client.h |  1 +
>  contrib/plugins/qpp_srv.c    | 33 ++++++++++++++++++++++++++++
>  contrib/plugins/qpp_srv.h    | 17 +++++++++++++++

Oh and I forgot this toy case should probably be in test/plugins/qpp with an
explicit test in tests/tcg/multiarch/Makefile to exercise it during
"make check-tcg". This should hopefully avoid having to mess with
PLUGINS in tests/tcg/Makefile.target.

<snip>
Andrew Fasano Sept. 26, 2022, 9:38 p.m. UTC | #3
From: Alex Bennée <alex.bennee@linaro.org>
> Andrew Fasano <fasano@mit.edu> writes:
> 
> > The first plugin, qpp_srv exposes two functions and one callback that other
> > plugins can leverage. These functions are described in the corresponding
> > header file.
> >
> > The second plugin, qpp_client, imports this header file, registers its
> > own function to run on a qpp_srv-provided callback, and directly calls
> > into the two exposed functions in qpp_srv.
> 
> I'll just sketch out how I would change the API in this example plugin:
[snip]
> QEMU_PLUGIN_EXPORT const char *qemu_plugin_name = "qpp_client";

This works. Perhaps plugins could (should?) also specify a version number
that other plugins could check before interacting with:

	QEMU_PLUGIN_EXPORT const int qemu_plugin_version = 1;

> QEMU_PLUGIN_EXPORT const char *qemu_plugin_uses = "qpp_server";

I anticipate plugins could depend on multiple other plugins and they might
want to check the version of these plugins, so perhaps a function call would
be better? Something like:

	int qpp_srv_version = load_qemu_plugin("qpp_server");

Perhaps returning negative values on error, otherwise the plugin version. Or
the version compatability checks could be standardized into the plugin core,
but that seems less important to me for now.
[snip]

> QEMU_PLUGIN_EXPORT int qpp_srv_do_add(int x)

I like the change to keep these with the plugin name as a prefix everywhere.

Thanks,
Andrew
Andrew Fasano Sept. 26, 2022, 9:38 p.m. UTC | #4
From: Alex Bennée <alex.bennee@linaro.org>
> Andrew Fasano <fasano@mit.edu> writes:
> 
> > The first plugin, qpp_srv exposes two functions and one callback that other
> > plugins can leverage. These functions are described in the corresponding
> > header file.
> >
> > The second plugin, qpp_client, imports this header file, registers its
> > own function to run on a qpp_srv-provided callback, and directly calls
> > into the two exposed functions in qpp_srv.
> >
> > Signed-off-by: Andrew Fasano <fasano@mit.edu>
> > ---
> >  contrib/plugins/Makefile     |  2 ++
> >  contrib/plugins/qpp_client.c | 42 ++++++++++++++++++++++++++++++++++++
> >  contrib/plugins/qpp_client.h |  1 +
> >  contrib/plugins/qpp_srv.c    | 33 ++++++++++++++++++++++++++++
> >  contrib/plugins/qpp_srv.h    | 17 +++++++++++++++
> 
> Oh and I forgot this toy case should probably be in test/plugins/qpp with an
> explicit test in tests/tcg/multiarch/Makefile to exercise it during
> "make check-tcg". This should hopefully avoid having to mess with
> PLUGINS in tests/tcg/Makefile.target.

Okay, that makes sense. Thanks so much for all the feedback!

> 
> <snip>
> 
> -- 
> Alex Bennée

Thanks,
Andrew
diff mbox series

Patch

diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile
index b7720fea0f..b7510de89c 100644
--- a/contrib/plugins/Makefile
+++ b/contrib/plugins/Makefile
@@ -21,6 +21,8 @@  NAMES += lockstep
 NAMES += hwprofile
 NAMES += cache
 NAMES += drcov
+NAMES += qpp_srv
+NAMES += qpp_client
 
 SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES)))
 
diff --git a/contrib/plugins/qpp_client.c b/contrib/plugins/qpp_client.c
new file mode 100644
index 0000000000..de3335e167
--- /dev/null
+++ b/contrib/plugins/qpp_client.c
@@ -0,0 +1,42 @@ 
+#include <stdio.h>
+#include <qemu-plugin.h>
+#include <plugin-qpp.h>
+#include <glib.h>
+#include "qpp_srv.h"
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+void my_on_exit(int x, bool b)
+{
+  g_autoptr(GString) report = g_string_new("Client: on_exit runs with args: ");
+  g_string_append_printf(report, "%d, %d\n", x, b);
+  qemu_plugin_outs(report->str);
+
+  g_string_printf(report, "Client: calls qpp_srv's do_add(1): %d\n",
+                          qpp_srv_do_add(1));
+  qemu_plugin_outs(report->str);
+
+  g_string_printf(report, "Client: calls qpp_srv's do_sub(1): %d\n",
+                           qpp_srv_do_sub(1));
+  qemu_plugin_outs(report->str);
+}
+
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+                   const qemu_info_t *info, int argc, char **argv) {
+
+    /*
+     * Register our "my_on_exit" function to run on the on_exit QPP-callback
+     * exported by qpp_srv
+     */
+    QPP_REG_CB("qpp_srv", on_exit, my_on_exit);
+
+    g_autoptr(GString) report = g_string_new(CURRENT_PLUGIN ": Call "
+                                             "qpp_srv's do_add(0) => ");
+    g_string_append_printf(report, "%d\n", qpp_srv_do_add(0));
+    qemu_plugin_outs(report->str);
+
+    g_string_printf(report, "Client: registered on_exit callback\n");
+    return 0;
+}
+
diff --git a/contrib/plugins/qpp_client.h b/contrib/plugins/qpp_client.h
new file mode 100644
index 0000000000..573923f580
--- /dev/null
+++ b/contrib/plugins/qpp_client.h
@@ -0,0 +1 @@ 
+void my_on_exit(int, bool);
diff --git a/contrib/plugins/qpp_srv.c b/contrib/plugins/qpp_srv.c
new file mode 100644
index 0000000000..61a6ab38ed
--- /dev/null
+++ b/contrib/plugins/qpp_srv.c
@@ -0,0 +1,33 @@ 
+#include <stdio.h>
+#include <qemu-plugin.h>
+#include <plugin-qpp.h>
+#include <gmodule.h>
+#include "qpp_srv.h"
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
+
+QPP_CREATE_CB(on_exit);
+
+static void plugin_exit(qemu_plugin_id_t id, void *p)
+{
+  qemu_plugin_outs(CURRENT_PLUGIN "exit triggered, running all registered"
+                  " QPP callbacks\n");
+  QPP_RUN_CB(on_exit, 0, true);
+}
+
+QEMU_PLUGIN_EXPORT int do_add(int x)
+{
+  return x + 1;
+}
+
+QEMU_PLUGIN_EXPORT int do_sub(int x)
+{
+  return x - 1;
+}
+
+QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
+                   const qemu_info_t *info, int argc, char **argv) {
+    qemu_plugin_outs("qpp_srv loaded\n");
+    qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
+    return 0;
+}
diff --git a/contrib/plugins/qpp_srv.h b/contrib/plugins/qpp_srv.h
new file mode 100644
index 0000000000..ceb26e3d2c
--- /dev/null
+++ b/contrib/plugins/qpp_srv.h
@@ -0,0 +1,17 @@ 
+#ifndef QPP_SRV_H
+#define QPP_SRV_H
+
+/*
+ * Prototype for the on_exit callback: callback functions should be
+ * of type `void f(int, bool)`
+ */
+QPP_CB_PROTOTYPE(void, on_exit, int, bool);
+
+/*
+ * Prototypes for the do_add and do_sub functions. Both return an int and
+ * take an int as an argument.
+ */
+QPP_FUN_PROTOTYPE(qpp_srv, int, do_add, int);
+QPP_FUN_PROTOTYPE(qpp_srv, int, do_sub, int);
+
+#endif /* QPP_SRV_H */