qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] RFC: DSO (dynamic shared objects) support


From: Michael Tokarev
Subject: [Qemu-devel] RFC: DSO (dynamic shared objects) support
Date: Tue, 18 Jun 2013 15:37:21 +0400
User-agent: Mozilla/5.0 (X11; Linux i686 on x86_64; rv:17.0) Gecko/17.0 Icedove/17.0

Hello.

I looked at what's needed to support DSO (dynamic shared objects)
in qemu, in order to be able to split functionality into loadable
"plugins".  It isn't exactly difficult, but a few steps are needed
still.

The whole thing is about splitting the functionality into plugins
from one, single, qemu build, for now, not about allowing 3rd-party
plugins to be distributed outside of qemu.

The plan is to keep the plugins in a single directory (or several
subdirectories, by type of plugins - for block, machine and other),
and load them during startup.


First of all, we need a global config switch/check for this kind of
service.  On a POSIX system this should make the executable to be
linked with -rdynamic option, in order to make all symbols in the
executable to be available to plugins.

This is an interesting case.  We may end up in some symbols from
qemu libraries not linked in when building the executable, but
that symbol may be used in some plugin.  Such situations, if will
happen, will need to be deal with on a case-by-case basis somehow.


Next, the executable should be linked with -ldl (again, for a POSIX
system), to be able to dynamically load anything.  This goes on the
same line as -rdynamic -- once we enable plugins, both linker options
are enabled.


Next, the module loading support.  On POSIX it is <dlfcn.h> and
dlopen(3), this one is trivial.

I think the best is to hook up into util/module.c.  Currently,
we explicitly call modue_call_init(type) for module types the
executable is interested with.  So in that call we may also
load all plugins of the given type just before running all the
module init functions.

For modules themselves, nothing changes -- __attribute__((constructor))
does the same thing be it in a DSO or statically linked into
executable.


Next, and this is the most complex part.  The build system for
modules, and configuring it.   I heard there were plans to use
something like kbuild system for that, has anything been done
in this context?

With current config/build system, the following changes are
needed:

 o split individual libs from libs_softmmu into their own
   variables.

 o allow obj-m (and similar) in addition to obj-y, with build
   flags and rules to produce an .so.

 o ./configure --{enable,disable}-foo -- in addition to
   that, I think --module-foo will be ok.  If not, well,
   any suggestion how to name it?

 o modules installing

 o switching some modules to allow building them modular

 o adding more types of modules, for example a new DISPLAY
   type.


Below is a sample implementation of the loading part (without
configure checks, just POC).

Thanks,

/mjt

--- a/util/module.c
+++ b/util/module.c
@@ -17,6 +17,62 @@
 #include "qemu/queue.h"
 #include "qemu/module.h"

+#define CONFIG_DSO_POSIX
+
+#ifdef CONFIG_DSO_POSIX
+
+#include <dlfcn.h>
+#include <dirent.h>
+
+static const char *plugins_dir = "plugins";
+
+static const char *module_init_types[MODULE_INIT_MAX] = {
+   "block", "machine", "qapi", "qom"
+};
+
+static void load_modules(module_init_type type)
+{
+    DIR *dir;
+    struct dirent *de;
+    char path[PATH_MAX];
+
+    const char *typestr = module_init_types[type];
+    const size_t typelen = strlen(typestr);
+
+fprintf(stderr, "loading modules of type %s\n", typestr);
+
+    dir = opendir(plugins_dir);
+    if (!dir)
+    {
+        return;
+    }
+    while((de = readdir(dir)) != NULL)
+    {
+        size_t len = strlen(de->d_name);
+        if (len <= typelen
+            || memcmp(de->d_name, typestr, typelen) != 0
+            || de->d_name[typelen] != '_'
+            || strcmp(de->d_name + len - 3, ".so") != 0)
+        {
+            continue;
+        }
+        snprintf(path, sizeof(path), "%s/%s", plugins_dir, de->d_name);
+        if (dlopen(path, RTLD_NOW) == NULL)
+        {
+            fprintf(stderr, "warning: unable to load plugin %s\n", path);
+            continue;
+        }
+        fprintf(stderr, "loaded %s\n", path);
+    }
+    closedir(dir);
+}
+
+#else
+
+static void load_modules(module_init_type type) {}
+
+#endif
+
 typedef struct ModuleEntry
 {
     void (*init)(void);
@@ -74,6 +130,7 @@ void module_call_init(module_init_type type)
     ModuleEntry *e;

     l = find_type(type);
+    load_modules(type);

     QTAILQ_FOREACH(e, l, node) {
         e->init();



reply via email to

[Prev in Thread] Current Thread [Next in Thread]