]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/module: basic Go runtime, support for libgo bootstrap
authorMarek Vavruša <marek.vavrusa@nic.cz>
Wed, 4 Mar 2015 18:31:42 +0000 (19:31 +0100)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Wed, 4 Mar 2015 18:31:42 +0000 (19:31 +0100)
lib/module.c
modules/gostats/gostats.go
modules/modules.mk

index 15b465e8d964fe1a47161f0a9692498c68d0dcff..109f16ad98142b5c726505cb45ba3c1190af458b 100644 (file)
@@ -1,5 +1,7 @@
 #include <stdlib.h>
 #include <dlfcn.h>
+#include <pthread.h>
+#include <unistd.h>
 
 #include "lib/defines.h"
 #include "lib/utils.h"
@@ -19,7 +21,7 @@ static inline const char *library_ext(void)
 
 static void *load_symbol(void *lib, const char *prefix, const char *name)
 {
-       auto_free char *symbol = kr_strcatdup(3, prefix, "_", name);
+       auto_free char *symbol = kr_strcatdup(2, prefix, name);
        return dlsym(lib, symbol);
 }
 
@@ -44,6 +46,58 @@ static int load_library(struct kr_module *module, const char *name, const char *
        return kr_error(ENOENT);
 }
 
+static int bootstrap_libgo(struct kr_module *module)
+{
+       /* Check if linked against compatible libgo */
+       void (*go_check)(void) = dlsym(module->lib, "runtime_check");
+       void (*go_args)(int, void*) = dlsym(module->lib, "runtime_args");
+       void (*go_init_os)(void) = dlsym(module->lib, "runtime_osinit");
+       void (*go_init_sched)(void) = dlsym(module->lib, "runtime_schedinit");
+       void (*go_init_main)(void) = dlsym(module->lib, "__go_init_main");
+       if ((go_check && go_args && go_init_os && go_init_sched && go_init_main) == false) {
+               return kr_error(EINVAL);
+       }
+
+       /*
+        * Bootstrap runtime - this is minimal runtime, we would need a running scheduler
+        * and gc for coroutines and memory allocation. That would require a custom "world loop",
+        * message passing, and either runtime sharing or module isolation.
+        * https://github.com/gcc-mirror/gcc/blob/gcc-4_9_2-release/libgo/runtime/proc.c#L457
+        */
+       char *fake_argv[2] = {
+               getenv("_"),
+               NULL
+       };
+       go_check();
+       go_args(1, fake_argv);
+       go_init_os();
+       go_init_sched();
+       go_init_main();
+
+       return kr_ok();
+}
+
+
+static int load_libgo(struct kr_module *module, module_api_cb **module_api)
+{
+       /* Bootstrap libgo */
+       int ret = bootstrap_libgo(module);
+       if (ret != 0) {
+               return ret;
+       }
+
+       /* Enforced prefix for now. */
+       const char *module_prefix = "main.";
+       
+       *(void **) (module_api)      = load_symbol(module->lib, module_prefix, "Api");
+       *(void **) (&module->init)   = load_symbol(module->lib, module_prefix, "Init");
+       *(void **) (&module->deinit) = load_symbol(module->lib, module_prefix, "Deinit");
+       *(void **) (&module->config) = load_symbol(module->lib, module_prefix, "Config");
+       *(void **) (&module->layer)  = load_symbol(module->lib, module_prefix, "Layer");
+
+       return kr_ok();
+}
+
 int kr_module_load(struct kr_module *module, const char *name, const char *path)
 {
        if (module == NULL || name == NULL) {
@@ -68,20 +122,29 @@ int kr_module_load(struct kr_module *module, const char *name, const char *path)
 
        /* Load all symbols. */
        module_api_cb *module_api = NULL;
-       *(void **) (&module_api)     = load_symbol(module->lib, name, "api");
-       *(void **) (&module->init)   = load_symbol(module->lib, name, "init");
-       *(void **) (&module->deinit) = load_symbol(module->lib, name, "deinit");
-       *(void **) (&module->config) = load_symbol(module->lib, name, "config");
-       *(void **) (&module->layer)  = load_symbol(module->lib, name, "layer");
+       auto_free char *module_prefix = kr_strcatdup(2, name, "_");
+       *(void **) (&module_api)     = load_symbol(module->lib, module_prefix, "api");
+       *(void **) (&module->init)   = load_symbol(module->lib, module_prefix, "init");
+       *(void **) (&module->deinit) = load_symbol(module->lib, module_prefix, "deinit");
+       *(void **) (&module->config) = load_symbol(module->lib, module_prefix, "config");
+       *(void **) (&module->layer)  = load_symbol(module->lib, module_prefix, "layer");
+
+       /* Module initializer not found, attempt to load as Go shared library. */
+       if (module_api == NULL) {
+               int ret = load_libgo(module, &module_api);
+               if (ret != 0) {
+                       return ret;
+               }
+       }
 
        /* Check module API version (if declared). */
-       if (module_api && module_api() > KR_MODULE_API) {
+       if (module_api && module_api() != KR_MODULE_API) {
                return kr_error(ENOTSUP);
        }
 
        /* Initialize module */
        if (module->init) {
-               return module->init(module);
+               module->init(module);
        }
 
        return kr_ok();
@@ -96,4 +159,4 @@ void kr_module_unload(struct kr_module *module)
        if (module->lib && module->lib != RTLD_DEFAULT) {
                dlclose(module->lib);
        }
-}
\ No newline at end of file
+}
index f4d73c162930527f77ab7de732abf5209e181900..e4aa4f188bbc9b922b48128f411d9b44528e7500 100644 (file)
@@ -1,15 +1,15 @@
-package gostats
+package main
 
 /*
 #include "lib/layer.h"
 #include "lib/module.h"
-extern int gostats_begin(knot_layer_t *, void *);
-extern int gostats_finish(knot_layer_t *);
+extern int begin(knot_layer_t *, void *) __asm__ ("main.Begin");
+extern int finish(knot_layer_t *) __asm__ ("main.Finish");
 static inline const knot_layer_api_t *_gostats_layer(void)
 {
        static const knot_layer_api_t _module = {
-               .begin = &gostats_begin,
-               .finish = &gostats_finish
+               .begin = &begin,
+               .finish = &finish
        };
        return &_module;
 }
@@ -18,31 +18,30 @@ import "C"
 import "unsafe"
 import "fmt"
 
-//export gostats_init
-func gostats_init(module *C.struct_kr_module) C.int {
-       fmt.Println("go_init()")
+func Api() C.uint32_t {
+       return C.KR_MODULE_API
+}
+
+func Init(module *C.struct_kr_module) C.int {
+       fmt.Printf("go_init(%s)\n", C.GoString((*C.char)(module.data)))
        return 0
 }
 
-//export gostats_deinit
-func gostats_deinit(module *C.struct_kr_module) C.int {
+func Deinit(module *C.struct_kr_module) C.int {
        fmt.Println("go_deinit()")
        return 0
 }
 
-//export gostats_begin
-func gostats_begin(ctx *C.knot_layer_t, param unsafe.Pointer) C.int {
+func Begin(ctx *C.knot_layer_t, param unsafe.Pointer) C.int {
        fmt.Println("go_begin()")
        return 0
 }
 
-//export gostats_finish
-func gostats_finish(ctx *C.knot_layer_t) C.int {
+func Finish(ctx *C.knot_layer_t) C.int {
        fmt.Println("go_finish()")
        return 0
 }
 
-//export gostats_layer
-func gostats_layer() *C.knot_layer_api_t {
+func Layer() *C.knot_layer_api_t {
        return C._gostats_layer()
 }
\ No newline at end of file
index 7fdcace955ab001cbd58221ae639bf6138d42a14..b4fdcda4ae9b0e2be8cc571a6987b5d38d78e6a0 100644 (file)
@@ -14,14 +14,16 @@ endef
 
 # Go target definition
 define go_target
-$(1): $(2)/$(1)$(LIBEXT)
-$(2)/_obj/_cgo_.o: $$($(1)_SOURCES)
-       $(INSTALL) -d $(2)/_obj
+$(1)_OBJS := $(addprefix $(2)/_obj/,_cgo_defun.o _cgo_export.o $(subst /,_,$(2))_$(1).cgo2.o)
+$(1)_GOBJS := $(addprefix $(2)/_obj/,_cgo_gotypes.go $(subst /,_,$(2))_$(1).cgo1.go)
+$(2)/_obj/_cgo_export.h: $$($(1)_SOURCES)
+       @$(INSTALL) -d $(2)/_obj
        $(call quiet,CGO,$$^) -gccgo=true -objdir=$(2)/_obj -- $(CFLAGS) $$^
-$(2)/_obj/$(1).o: $(2)/_obj/_cgo_.o
-       $(call quiet,GCCGO,$$@) -fPIC -c $(2)/_obj/*.go
-$(2)/$(1)$(LIBEXT): $(2)/_obj/$(1).o $$($(1)_DEPEND)
-       $(call quiet,GCCGO,$$@) $(CFLAGS) -$(LIBTYPE) -fPIC -Wno-return-type -o $$@ $(2)/_obj/*.o $(2)/_obj/*.c -lgcc $$($(1)_LIBS)
+$(2)/$(1).o: $(2)/_obj/_cgo_export.h $$($(1)_GOBJS)
+       $(call quiet,GCCGO,$$@) -I$(2)/_obj -c -fPIC $$($(1)_GOBJS) -o $$@
+$(2)/$(1)$(LIBEXT): $(2)/_obj/_cgo_export.h $(2)/$(1).o $$($(1)_OBJS) $$($(1)_DEPEND)
+       $(call quiet,GCCGO,$$@) -g -fPIC -I$(2)/_obj $(2)/$(1).o $$($(1)_OBJS) -o $$@ -$(LIBTYPE) -lgcc -lgo $$($(1)_LIBS)
+$(1): $(2)/_obj/_cgo_export.h $(2)/$(1)$(LIBEXT)
 $(1)-clean:
        $(RM) -r $(2)/_obj $(2)/$(1)$(LIBEXT)
 $(1)-install: $(2)/$(1)$(LIBEXT)