[PATCH] Link in known io engines
authorJens Axboe <jens.axboe@oracle.com>
Tue, 7 Nov 2006 14:20:59 +0000 (15:20 +0100)
committerJens Axboe <jens.axboe@oracle.com>
Tue, 7 Nov 2006 14:20:59 +0000 (15:20 +0100)
No real point in using dlopen() to find engines we know about. We still
support loading external modules, just give the name as the full path
to such a file.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
13 files changed:
Makefile
engines/Makefile [deleted file]
engines/fio-engine-cpu.c
engines/fio-engine-libaio.c
engines/fio-engine-mmap.c
engines/fio-engine-posixaio.c
engines/fio-engine-sg.c
engines/fio-engine-splice.c
engines/fio-engine-sync.c
fio.h
init.c
ioengines.c
list.h

index ad9aa3bd3f94586366213f99af4f514819cb464d..1ebad6af78ca7e0292096855b5f9ea8e09a0d97f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -5,6 +5,14 @@ SCRIPTS = fio_generate_plots
 OBJS = fio.o ioengines.o init.o stat.o log.o time.o md5.o crc32.o \
        filesetup.o eta.o verify.o memory.o io_u.o parse.o
 
 OBJS = fio.o ioengines.o init.o stat.o log.o time.o md5.o crc32.o \
        filesetup.o eta.o verify.o memory.o io_u.o parse.o
 
+OBJS += engines/fio-engine-cpu.o
+OBJS += engines/fio-engine-libaio.o
+OBJS += engines/fio-engine-mmap.o
+OBJS += engines/fio-engine-posixaio.o
+OBJS += engines/fio-engine-sg.o
+OBJS += engines/fio-engine-splice.o
+OBJS += engines/fio-engine-sync.o
+
 INSTALL = install
 prefix = /usr/local
 bindir = $(prefix)/bin
 INSTALL = install
 prefix = /usr/local
 bindir = $(prefix)/bin
@@ -15,10 +23,9 @@ FIO_INST_DIR = $(subst ','\'',$(prefix))
 CFLAGS += '-D_INST_PREFIX="$(FIO_INST_DIR)"'
 
 all: depend $(PROGS) $(SCRIPTS)
 CFLAGS += '-D_INST_PREFIX="$(FIO_INST_DIR)"'
 
 all: depend $(PROGS) $(SCRIPTS)
-       @$(MAKE) -C engines
 
 fio: $(OBJS)
 
 fio: $(OBJS)
-       $(CC) $(CFLAGS) -o $@ $(filter %.o,$^) -lpthread -lm -ldl
+       $(CC) $(CFLAGS) -o $@ $(filter %.o,$^) -lpthread -lm -ldl -laio -lrt
 
 clean:
        -rm -f *.o .depend cscope.out $(PROGS) engines/*.o
 
 clean:
        -rm -f *.o .depend cscope.out $(PROGS) engines/*.o
@@ -33,7 +40,6 @@ install: $(PROGS) $(SCRIPTS)
        $(INSTALL) -m755 -d $(DESTDIR)$(bindir)
        $(INSTALL) $(PROGS) $(SCRIPTS) $(DESTDIR)$(bindir)
        $(INSTALL) -m755 -d $(DESTDIR) $(libdir)
        $(INSTALL) -m755 -d $(DESTDIR)$(bindir)
        $(INSTALL) $(PROGS) $(SCRIPTS) $(DESTDIR)$(bindir)
        $(INSTALL) -m755 -d $(DESTDIR) $(libdir)
-       $(INSTALL) engines/*.o $(libdir)
 
 ifneq ($(wildcard .depend),)
 include .depend
 
 ifneq ($(wildcard .depend),)
 include .depend
diff --git a/engines/Makefile b/engines/Makefile
deleted file mode 100644 (file)
index 963a93e..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-CC     = gcc
-CFLAGS = -W -Wall -O2 -g -shared -rdynamic -fPIC
-ALL_CFLAGS = $(CFLAGS) -I.. -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
-OBJS   = fio-engine-sync.o fio-engine-splice.o fio-engine-mmap.o fio-engine-libaio.o fio-engine-posixaio.o fio-engine-sg.o fio-engine-cpu.o
-
-all: depend $(OBJS)
-
-depend:
-       @$(CC) -MM $(ALL_CFLAGS) *.c 1> .depend
-
-clean:
-       -rm -f *.o $(OBJS) .depend
-
-%.o: %.c
-       $(CC) $(ALL_CFLAGS) -o $*.o $<
-
-fio-engine-libaio.o: fio-engine-libaio.c
-       $(CC) $(ALL_CFLAGS) -laio -o $*.o $<
-
-fio-engine-posixaio.o: fio-engine-posixaio.c
-       $(CC) $(ALL_CFLAGS) -lrt -o $*.o $<
-
-ifneq ($(wildcard .depend),)
-include .depend
-endif
index 4ba12c64563f3b7bc3bd47ab8cb3a571d8b4f079..f65f91d9e0f988e17e7d426bdde81f778a7bf14b 100644 (file)
@@ -1,5 +1,5 @@
-#include "fio.h"
-#include "os.h"
+#include "../fio.h"
+#include "../os.h"
 
 static int fio_cpuio_setup(struct thread_data fio_unused *td)
 {
 
 static int fio_cpuio_setup(struct thread_data fio_unused *td)
 {
@@ -19,10 +19,20 @@ static int fio_cpuio_init(struct thread_data *td)
        return 0;
 }
 
        return 0;
 }
 
-struct ioengine_ops ioengine = {
+static struct ioengine_ops ioengine = {
        .name           = "cpuio",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_cpuio_init,
        .setup          = fio_cpuio_setup,
        .flags          = FIO_CPUIO,
 };
        .name           = "cpuio",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_cpuio_init,
        .setup          = fio_cpuio_setup,
        .flags          = FIO_CPUIO,
 };
+
+static void fio_init fio_cpuio_register(void)
+{
+       register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_cpuio_unregister(void)
+{
+       unregister_ioengine(&ioengine);
+}
index 12ddc98b26ac800d86ed78e15cefa21513cb32ff..45e69e90b600704df35dfb1d2f23a91857531c7f 100644 (file)
@@ -7,8 +7,9 @@
 #include <unistd.h>
 #include <errno.h>
 #include <assert.h>
 #include <unistd.h>
 #include <errno.h>
 #include <assert.h>
-#include "fio.h"
-#include "os.h"
+
+#include "../fio.h"
+#include "../os.h"
 
 #ifdef FIO_HAVE_LIBAIO
 
 
 #ifdef FIO_HAVE_LIBAIO
 
@@ -130,7 +131,7 @@ static int fio_libaio_init(struct thread_data *td)
        return 0;
 }
 
        return 0;
 }
 
-struct ioengine_ops ioengine = {
+static struct ioengine_ops ioengine = {
        .name           = "libaio",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_libaio_init,
        .name           = "libaio",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_libaio_init,
@@ -155,10 +156,20 @@ static int fio_libaio_init(struct thread_data fio_unused *td)
        return 1;
 }
 
        return 1;
 }
 
-struct ioengine_ops ioengine = {
+static struct ioengine_ops ioengine = {
        .name           = "libaio",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_libaio_init,
 };
 
 #endif
        .name           = "libaio",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_libaio_init,
 };
 
 #endif
+
+static void fio_init fio_libaio_register(void)
+{
+       register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_libaio_unregister(void)
+{
+       unregister_ioengine(&ioengine);
+}
index 483a704eb19bfa45c37c4b6a772032a03481f95f..20dcfd2264cb3afc981e371c9c89aa2c28c1a447 100644 (file)
@@ -8,8 +8,9 @@
 #include <errno.h>
 #include <assert.h>
 #include <sys/mman.h>
 #include <errno.h>
 #include <assert.h>
 #include <sys/mman.h>
-#include "fio.h"
-#include "os.h"
+
+#include "../fio.h"
+#include "../os.h"
 
 struct mmapio_data {
        struct io_u *last_io_u;
 
 struct mmapio_data {
        struct io_u *last_io_u;
@@ -88,7 +89,7 @@ static int fio_mmapio_init(struct thread_data *td)
        return 0;
 }
 
        return 0;
 }
 
-struct ioengine_ops ioengine = {
+static struct ioengine_ops ioengine = {
        .name           = "mmap",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_mmapio_init,
        .name           = "mmap",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_mmapio_init,
@@ -98,3 +99,13 @@ struct ioengine_ops ioengine = {
        .cleanup        = fio_mmapio_cleanup,
        .flags          = FIO_SYNCIO | FIO_MMAPIO,
 };
        .cleanup        = fio_mmapio_cleanup,
        .flags          = FIO_SYNCIO | FIO_MMAPIO,
 };
+
+static void fio_init fio_mmapio_register(void)
+{
+       register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_mmapio_unregister(void)
+{
+       unregister_ioengine(&ioengine);
+}
index 894a410a459117571518c00b66abe2d790a81183..ef4d78ebe8a58c03465eb33cdc58aa7f90b52d7c 100644 (file)
@@ -7,8 +7,9 @@
 #include <unistd.h>
 #include <errno.h>
 #include <assert.h>
 #include <unistd.h>
 #include <errno.h>
 #include <assert.h>
-#include "fio.h"
-#include "os.h"
+
+#include "../fio.h"
+#include "../os.h"
 
 #ifdef FIO_HAVE_POSIXAIO
 
 
 #ifdef FIO_HAVE_POSIXAIO
 
@@ -179,7 +180,7 @@ static int fio_posixaio_init(struct thread_data *td)
        return 0;
 }
 
        return 0;
 }
 
-struct ioengine_ops ioengine = {
+static struct ioengine_ops ioengine = {
        .name           = "posixaio",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_posixaio_init,
        .name           = "posixaio",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_posixaio_init,
@@ -204,10 +205,20 @@ static int fio_posixaio_init(struct thread_data fio_unused *td)
        return 1;
 }
 
        return 1;
 }
 
-struct ioengine_ops ioengine = {
+static struct ioengine_ops ioengine = {
        .name           = "posixaio",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_posixaio_init,
 };
 
 #endif
        .name           = "posixaio",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_posixaio_init,
 };
 
 #endif
+
+static void fio_init fio_posixaio_register(void)
+{
+       register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_posixaio_unregister(void)
+{
+       unregister_ioengine(&ioengine);
+}
index 2762e0bac3b25783f02ccdf6366327eb42d98583..9c5037f5d11fb0391cc25eda994a44366e3297ce 100644 (file)
@@ -8,8 +8,9 @@
 #include <errno.h>
 #include <assert.h>
 #include <sys/poll.h>
 #include <errno.h>
 #include <assert.h>
 #include <sys/poll.h>
-#include "fio.h"
-#include "os.h"
+
+#include "../fio.h"
+#include "../os.h"
 
 #ifdef FIO_HAVE_SGIO
 
 
 #ifdef FIO_HAVE_SGIO
 
@@ -313,7 +314,7 @@ err:
        return 1;
 }
 
        return 1;
 }
 
-struct ioengine_ops ioengine = {
+static struct ioengine_ops ioengine = {
        .name           = "sg",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_sgio_init,
        .name           = "sg",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_sgio_init,
@@ -338,10 +339,20 @@ static int fio_sgio_init(struct thread_data fio_unused *td)
        return 1;
 }
 
        return 1;
 }
 
-struct ioengine_ops ioengine = {
+static struct ioengine_ops ioengine = {
        .name           = "sgio",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_sgio_init,
 };
 
 #endif
        .name           = "sgio",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_sgio_init,
 };
 
 #endif
+
+static void fio_init fio_sgio_register(void)
+{
+       register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_sgio_unregister(void)
+{
+       unregister_ioengine(&ioengine);
+}
index 3b02fbfdbb83c45906810e0126f1d2d65cc74cb0..fa4a6ee1db21ff192d811f1a95dfacc05de35483 100644 (file)
@@ -8,8 +8,9 @@
 #include <errno.h>
 #include <assert.h>
 #include <sys/poll.h>
 #include <errno.h>
 #include <assert.h>
 #include <sys/poll.h>
-#include "fio.h"
-#include "os.h"
+
+#include "../fio.h"
+#include "../os.h"
 
 #ifdef FIO_HAVE_SPLICE
 
 
 #ifdef FIO_HAVE_SPLICE
 
@@ -181,7 +182,7 @@ static int fio_spliceio_init(struct thread_data *td)
        return 0;
 }
 
        return 0;
 }
 
-struct ioengine_ops ioengine = {
+static struct ioengine_ops ioengine = {
        .name           = "splice",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_spliceio_init,
        .name           = "splice",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_spliceio_init,
@@ -205,10 +206,20 @@ static int fio_spliceio_init(struct thread_data fio_unused *td)
        return 1;
 }
 
        return 1;
 }
 
-struct ioengine_ops ioengine = {
+static struct ioengine_ops ioengine = {
        .name           = "splice",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_spliceio_init,
 };
 
 #endif
        .name           = "splice",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_spliceio_init,
 };
 
 #endif
+
+static void fio_init fio_spliceio_register(void)
+{
+       register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_spliceio_unregister(void)
+{
+       unregister_ioengine(&ioengine);
+}
index 43f42ca2ffcace7068656a0ebd4453453af69d7b..5919830edcc6cf0a4fe91e57d20fbabad6e7d4bc 100644 (file)
@@ -7,8 +7,9 @@
 #include <unistd.h>
 #include <errno.h>
 #include <assert.h>
 #include <unistd.h>
 #include <errno.h>
 #include <assert.h>
-#include "fio.h"
-#include "os.h"
+
+#include "../fio.h"
+#include "../os.h"
 
 struct syncio_data {
        struct io_u *last_io_u;
 
 struct syncio_data {
        struct io_u *last_io_u;
@@ -97,7 +98,7 @@ static int fio_syncio_init(struct thread_data *td)
        return 0;
 }
 
        return 0;
 }
 
-struct ioengine_ops ioengine = {
+static struct ioengine_ops ioengine = {
        .name           = "sync",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_syncio_init,
        .name           = "sync",
        .version        = FIO_IOOPS_VERSION,
        .init           = fio_syncio_init,
@@ -108,3 +109,13 @@ struct ioengine_ops ioengine = {
        .cleanup        = fio_syncio_cleanup,
        .flags          = FIO_SYNCIO,
 };
        .cleanup        = fio_syncio_cleanup,
        .flags          = FIO_SYNCIO,
 };
+
+static void fio_init fio_syncio_register(void)
+{
+       register_ioengine(&ioengine);
+}
+
+static void fio_exit fio_syncio_unregister(void)
+{
+       unregister_ioengine(&ioengine);
+}
diff --git a/fio.h b/fio.h
index f859608c32114a5c520253b5a3ade9ac55c2d2f3..9f5201b657ec219f078fde8c5a1a39354e84d88c 100644 (file)
--- a/fio.h
+++ b/fio.h
@@ -565,6 +565,7 @@ static inline void fio_sem_up(volatile int *sem)
        } while (0)
 
 struct ioengine_ops {
        } while (0)
 
 struct ioengine_ops {
+       struct list_head list;
        char name[16];
        int version;
        int flags;
        char name[16];
        int version;
        int flags;
@@ -583,12 +584,16 @@ struct ioengine_ops {
 #define FIO_IOOPS_VERSION      3
 
 extern struct ioengine_ops *load_ioengine(struct thread_data *, const char *);
 #define FIO_IOOPS_VERSION      3
 
 extern struct ioengine_ops *load_ioengine(struct thread_data *, const char *);
+extern int register_ioengine(struct ioengine_ops *);
+extern void unregister_ioengine(struct ioengine_ops *);
 extern void close_ioengine(struct thread_data *);
 
 /*
  * Mark unused variables passed to ops functions as unused, to silence gcc
  */
 #define fio_unused     __attribute((__unused__))
 extern void close_ioengine(struct thread_data *);
 
 /*
  * Mark unused variables passed to ops functions as unused, to silence gcc
  */
 #define fio_unused     __attribute((__unused__))
+#define fio_init       __attribute__((constructor))
+#define fio_exit       __attribute__((destructor))
 
 #define for_each_td(td, i)     \
        for ((i) = 0, (td) = &threads[0]; (i) < (int) thread_number; (i)++, (td)++)
 
 #define for_each_td(td, i)     \
        for ((i) = 0, (td) = &threads[0]; (i) < (int) thread_number; (i)++, (td)++)
diff --git a/init.c b/init.c
index 3749c9625976c77955c87213dbebbc0c181d7a4d..00f957651bc1ae65164c476665d73f863d1787ee 100644 (file)
--- a/init.c
+++ b/init.c
@@ -849,6 +849,7 @@ static int str_ioengine_cb(void *data, const char *str)
                return 0;
 
        log_err("fio: ioengine: { linuxaio, aio, libaio }, posixaio, sync, mmap, sgio, splice, cpu\n");
                return 0;
 
        log_err("fio: ioengine: { linuxaio, aio, libaio }, posixaio, sync, mmap, sgio, splice, cpu\n");
+       log_err("fio: or specify path to dynamic ioengine module\n");
        return 1;
 }
 
        return 1;
 }
 
index 96a96360750038ea87909c8fdfd45f36a89c9d13..a71357c67ddce9002b97f5d1afa4749a1e49100d 100644 (file)
 #include "fio.h"
 #include "os.h"
 
 #include "fio.h"
 #include "os.h"
 
+static LIST_HEAD(engine_list);
+
 static int check_engine_ops(struct ioengine_ops *ops)
 {
 static int check_engine_ops(struct ioengine_ops *ops)
 {
+       if (ops->version != FIO_IOOPS_VERSION) {
+               log_err("bad ioops version %d (want %d)\n", ops->version, FIO_IOOPS_VERSION);
+               return 1;
+       }
+
        /*
         * cpu thread doesn't need to provide anything
         */
        /*
         * cpu thread doesn't need to provide anything
         */
@@ -42,21 +49,48 @@ static int check_engine_ops(struct ioengine_ops *ops)
        return 0;
 }
 
        return 0;
 }
 
-struct ioengine_ops *load_ioengine(struct thread_data *td, const char *name)
+void unregister_ioengine(struct ioengine_ops *ops)
 {
 {
-       char engine[16], engine_lib[256];
-       struct ioengine_ops *ops, *ret;
-       void *dlhandle;
+       list_del(&ops->list);
+       INIT_LIST_HEAD(&ops->list);
+}
+
+int register_ioengine(struct ioengine_ops *ops)
+{
+       if (check_engine_ops(ops))
+               return 1;
+
+       INIT_LIST_HEAD(&ops->list);
+       list_add_tail(&ops->list, &engine_list);
+       return 0;
+}
+
+static struct ioengine_ops *find_ioengine(const char *name)
+{
+       struct ioengine_ops *ops;
+       struct list_head *entry;
+       char engine[16];
 
        strncpy(engine, name, sizeof(engine) - 1);
 
 
        strncpy(engine, name, sizeof(engine) - 1);
 
-       /*
-        * linux libaio has alias names, so convert to what we want
-        */
        if (!strncmp(engine, "linuxaio", 8) || !strncmp(engine, "aio", 3))
                strcpy(engine, "libaio");
 
        if (!strncmp(engine, "linuxaio", 8) || !strncmp(engine, "aio", 3))
                strcpy(engine, "libaio");
 
-       sprintf(engine_lib, "%s/lib/fio/fio-engine-%s.o", fio_inst_prefix, engine);
+       list_for_each(entry, &engine_list) {
+               ops = list_entry(entry, struct ioengine_ops, list);
+               if (!strcmp(engine, ops->name))
+                       return ops;
+       }
+
+       return NULL;
+}
+
+static struct ioengine_ops *dlopen_ioengine(struct thread_data *td,
+                                           const char *engine_lib)
+{
+       struct ioengine_ops *ops;
+       void *dlhandle;
+
        dlerror();
        dlhandle = dlopen(engine_lib, RTLD_LAZY);
        if (!dlhandle) {
        dlerror();
        dlhandle = dlopen(engine_lib, RTLD_LAZY);
        if (!dlhandle) {
@@ -71,24 +105,41 @@ struct ioengine_ops *load_ioengine(struct thread_data *td, const char *name)
                return NULL;
        }
 
                return NULL;
        }
 
-       if (ops->version != FIO_IOOPS_VERSION) {
-               log_err("bad ioops version %d (want %d)\n", ops->version, FIO_IOOPS_VERSION);
-               dlclose(dlhandle);
+       ops->dlhandle = dlhandle;
+       return ops;
+}
+
+struct ioengine_ops *load_ioengine(struct thread_data *td, const char *name)
+{
+       struct ioengine_ops *ops, *ret;
+       char engine[16];
+
+       strncpy(engine, name, sizeof(engine) - 1);
+
+       /*
+        * linux libaio has alias names, so convert to what we want
+        */
+       if (!strncmp(engine, "linuxaio", 8) || !strncmp(engine, "aio", 3))
+               strcpy(engine, "libaio");
+
+       ops = find_ioengine(engine);
+       if (!ops)
+               ops = dlopen_ioengine(td, name);
+
+       if (!ops) {
+               log_err("fio: engine %s not loadable\n", name);
                return NULL;
        }
 
        /*
         * Check that the required methods are there.
         */
                return NULL;
        }
 
        /*
         * Check that the required methods are there.
         */
-       if (check_engine_ops(ops)) {
-               dlclose(dlhandle);
+       if (check_engine_ops(ops))
                return NULL;
                return NULL;
-       }
 
        ret = malloc(sizeof(*ret));
        memcpy(ret, ops, sizeof(*ret));
        ret->data = NULL;
 
        ret = malloc(sizeof(*ret));
        memcpy(ret, ops, sizeof(*ret));
        ret->data = NULL;
-       ret->dlhandle = dlhandle;
 
        return ret;
 }
 
        return ret;
 }
@@ -98,7 +149,9 @@ void close_ioengine(struct thread_data *td)
        if (td->io_ops->cleanup)
                td->io_ops->cleanup(td);
 
        if (td->io_ops->cleanup)
                td->io_ops->cleanup(td);
 
-       dlclose(td->io_ops->dlhandle);
+       if (td->io_ops->dlhandle)
+               dlclose(td->io_ops->dlhandle);
+
        free(td->io_ops);
        td->io_ops = NULL;
 }
        free(td->io_ops);
        td->io_ops = NULL;
 }
diff --git a/list.h b/list.h
index 2e0a7ad7eae671a3b0d20706dc9d741f549ab4eb..cedbafaae022de9267bcfd02296410a0b42c3465 100644 (file)
--- a/list.h
+++ b/list.h
@@ -28,6 +28,9 @@ struct list_head {
 
 #define LIST_HEAD_INIT(name) { &(name), &(name) }
 
 
 #define LIST_HEAD_INIT(name) { &(name), &(name) }
 
+#define LIST_HEAD(name) \
+       struct list_head name = LIST_HEAD_INIT(name)
+
 #define INIT_LIST_HEAD(ptr) do { \
        (ptr)->next = (ptr); (ptr)->prev = (ptr); \
 } while (0)
 #define INIT_LIST_HEAD(ptr) do { \
        (ptr)->next = (ptr); (ptr)->prev = (ptr); \
 } while (0)