qemu-devel
[Top][All Lists]
Advanced

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

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


From: Anthony Liguori
Subject: Re: [Qemu-devel] RFC: DSO (dynamic shared objects) support
Date: Tue, 18 Jun 2013 07:42:11 -0500

Hi,

On Tue, Jun 18, 2013 at 6:37 AM, Michael Tokarev <address@hidden> wrote:
> 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.

As it turns out, this is an area of interest of mine too.  I put up a
quick page describing some ideas a few weeks ago.

http://wiki.qemu.org/Features/Modules

> 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.

Ack.  Really critical and important distinction.

> 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.

Ack.

> 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.

I wouldn't worry about this.  There are a lot of things that can be
made modules today that don't export any symbols at all.  The other
case to consider is things that expose QMP commands.  We'll need to
adjust how commands are registered such that the QMP commands are
registered as part of modules.

But that doesn't have to be in the initial implementation.

> 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.

https://developer.gnome.org/glib/stable/glib-Dynamic-Loading-of-Modules.html

glib has a nice interface for modules that is cross platform.

> 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.

We ought to start out by loading modules *before* doing any module
init calls.  That will keep things nice and simple.  In the long term,
we'll need to look at each subsystem and see what it takes to load
modules after init.

> 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?

GSoC just kicked off yesterday.  Paolo can perhaps shed some light on
what the plans are.

> 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.

We also need a way to define the module targets.  My Makefile-fu is
not all that great but I suspect we can do something like:

libqemu-%.ko: $(eval $(obj-%-m))

I don't think that works but that's the rough idea.  We would then
need to define each module target by hand but that's probably
reasonable in the short term until we have kconfig.

>  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?

You don't really need to touch configure to start with.  We can just
rely on people modifying the config*.mak file.  We can wait for a
proper menuconfig via kconfig.

>
>  o modules installing
>
>  o switching some modules to allow building them modular

Pretty much any device is a candidate here.

Regards,

Anthony Liguori

>  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]