Introduce get_ioengine for external engines
authorDaniel Gollub <daniel.gollub@t-online.de>
Thu, 13 Feb 2014 04:23:31 +0000 (21:23 -0700)
committerJens Axboe <axboe@fb.com>
Thu, 13 Feb 2014 04:23:31 +0000 (21:23 -0700)
This makes life easier for plugins written in C++
since they do not need to deal with struct initilization issues
with the ioengine_ops symbol.

With g++ a non-static ioengine_ops in global scope like this:

struct ioengine_ops ioengine = {
        .name           = "null",
        .version        = FIO_IOOPS_VERSION,
        .queue          = fio_null_queue,
        .commit         = fio_null_commit,
};

Results in:

cpp_null2.cc: At global scope:
cpp_null2.cc:112:1: error: C99 designator ‘name’ outside aggregate initializer
cpp_null2.cc:112:1: sorry, unimplemented: non-trivial designated initializers not supported
cpp_null2.cc:112:1: sorry, unimplemented: non-trivial designated initializers not supported
cpp_null2.cc:112:1: sorry, unimplemented: non-trivial designated initializers not supported
cpp_null2.cc:112:1: sorry, unimplemented: non-trivial designated initializers not supported
$

Example get_iongine() symbol usage:

---8<---
extern "C" {
void get_ioengine(struct ioengine_ops **ioengine_ptr) {
        struct ioengine_ops *ioengine;
        *ioengine_ptr = (struct ioengine_ops *) malloc(sizeof(struct ioengine_ops));
        ioengine = *ioengine_ptr;

        strcpy(ioengine->name, "cpp_null");
        ioengine->version        = FIO_IOOPS_VERSION;
        ioengine->queue          = fio_null_queue;
        ioengine->commit         = fio_null_commit;
        ioengine->getevents      = fio_null_getevents;
        ioengine->event          = fio_null_event;
        ioengine->init           = fio_null_init;
        ioengine->cleanup        = fio_null_cleanup;
        ioengine->open_file      = fio_null_open;
        ioengine->flags          = FIO_DISKLESSIO;
}
}
--->8---

Signed-off-by: Daniel Gollub <d.gollub@telekom.de>
Moved get_ioengine_t typedef to ioengine.h.

Signed-off-by: Jens Axboe <axboe@fb.com>
ioengine.h
ioengines.c

index 19ed10bf7a5401dd13fafe5cef97cb2d32748bd0..abf2b464d8dfcef30a4b4693536da89723c8ba08 100644 (file)
@@ -167,6 +167,11 @@ enum fio_ioengine_flags {
        FIO_BIT_BASED   = 1 << 10,      /* engine uses a bit base (e.g. uses Kbit as opposed to KB) */
 };
 
        FIO_BIT_BASED   = 1 << 10,      /* engine uses a bit base (e.g. uses Kbit as opposed to KB) */
 };
 
+/*
+ * External engine defined symbol to fill in the engine ops structure
+ */
+typedef void (*get_ioengine_t)(struct ioengine_ops **);
+
 /*
  * io engine entry points
  */
 /*
  * io engine entry points
  */
index d71e372048112e19010c1dd494a7a4b2872eb5fa..3c75fa6bfed6812e9027e832ff0d26505034b7d9 100644 (file)
@@ -107,6 +107,20 @@ static struct ioengine_ops *dlopen_ioengine(struct thread_data *td,
        ops = dlsym(dlhandle, engine_lib);
        if (!ops)
                ops = dlsym(dlhandle, "ioengine");
        ops = dlsym(dlhandle, engine_lib);
        if (!ops)
                ops = dlsym(dlhandle, "ioengine");
+
+       /*
+        * For some external engines (like C++ ones) it is not that trivial
+        * to provide a non-static ionengine structure that we can reference.
+        * Instead we call a method which allocates the required ioengine
+        * structure.
+        */
+       if (!ops) {
+               get_ioengine_t get_ioengine = dlsym(dlhandle, "get_ioengine");
+
+               if (get_ioengine)
+                       get_ioengine(&ops);
+       }
+
        if (!ops) {
                td_vmsg(td, -1, dlerror(), "dlsym");
                dlclose(dlhandle);
        if (!ops) {
                td_vmsg(td, -1, dlerror(), "dlsym");
                dlclose(dlhandle);