diff --git a/lib/module.c b/lib/module.c index 15b465e8d964fe1a47161f0a9692498c68d0dcff..109f16ad98142b5c726505cb45ba3c1190af458b 100644 --- a/lib/module.c +++ b/lib/module.c @@ -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 +} diff --git a/modules/gostats/gostats.go b/modules/gostats/gostats.go index f4d73c162930527f77ab7de732abf5209e181900..e4aa4f188bbc9b922b48128f411d9b44528e7500 100644 --- a/modules/gostats/gostats.go +++ b/modules/gostats/gostats.go @@ -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 diff --git a/modules/modules.mk b/modules/modules.mk index 7fdcace955ab001cbd58221ae639bf6138d42a14..b4fdcda4ae9b0e2be8cc571a6987b5d38d78e6a0 100644 --- a/modules/modules.mk +++ b/modules/modules.mk @@ -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)