Skip to content
Snippets Groups Projects
Commit 9079db0b authored by Marek Vavruša's avatar Marek Vavruša
Browse files

lib/module: basic Go runtime, support for libgo bootstrap

parent eaaa2683
Branches
Tags
No related merge requests found
#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
}
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
......@@ -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)
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment