New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime: make it possible to know the go initialization in shared libraries is finished without calling a go function #11768

Open
hnakamur opened this Issue Jul 17, 2015 · 2 comments

Comments

Projects
None yet
3 participants
@hnakamur

hnakamur commented Jul 17, 2015

Please see golang-nuts › How to export C variables from Go shared libraries? for discussion.

I tried to write a Go shared library to make Apache or nginx modules.
What I would like to do is exporting a C struct variable, not a C function, from a Go shared library.
#1. What version of Go are you using (go version)?

1.5beta2

$ go version
go version go1.5beta2 linux/amd64

#2. What operating system and processor architecture are you using?

Ubuntu Linux trusty amd64

$ uname -a
Linux vagrant-ubuntu-trusty-64 3.13.0-55-generic #92-Ubuntu SMP Sun Jun 14 18:32:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

#3. What did you do?

Open a Go shared library written from a C main program. Please refer to the commit https://github.com/hnakamur/export_c_variable_from_go_dll_experiment/tree/0972d57461b091aed35c9ed083af0edae0c885cc for source codes.

runtime_load.c

#include <stdio.h>
#include <dlfcn.h>

int main(int argc, char **argv) {
    printf("runtime_load started\n");
    void *handle = dlopen("libgodll.so", RTLD_LAZY);
    if (!handle) {
        printf("dlopen failed\n");
        return 1;
    }
    printf("after dlopen. handle=%llx\n", (long long unsigned)handle);
    int *i_ptr = dlsym(handle, "i");
    printf("i=%d\n", *i_ptr);
#ifndef NO_DLCLOSE
    printf("calling dlclose\n");
    dlclose(handle);
    printf("after dlclose\n");
#endif
    return 0;
}

libgodll.go

package main

// int i;
import "C"

func init() {
    C.i = 1
}

//export libInit
func libInit() {}

func main() {}

Makefile

test_runtime: runtime_load libgodll.so
    LD_LIBRARY_PATH=. ./runtime_load
    echo status=$$?

test_compiletime: compiletime_load libgodll.so
    LD_LIBRARY_PATH=. ./compiletime_load
    echo status=$$?

runtime_load: runtime_load.c
    $(CC) -o runtime_load runtime_load.c $(CFLAGS) -ldl

compiletime_load: libgodll.so compiletime_load.c
    $(CC) -o compiletime_load compiletime_load.c -L. -lgodll

libgodll.so: libgodll.go
    go build -buildmode=c-shared -o libgodll.so libgodll.go

clean:
    -rm runtime_load compileitme_load core libgodll.h libgodll.so

With these source codes above, I ran make test_runtime
#4. What did you expect to see?

I expect to see i=1 is printed at https://github.com/hnakamur/export_c_variable_from_go_dll_experiment/blob/0972d57461b091aed35c9ed083af0edae0c885cc/runtime_load.c#L13
#5. What did you see instead?

Actually i=0 is printed at https://github.com/hnakamur/export_c_variable_from_go_dll_experiment/blob/0972d57461b091aed35c9ed083af0edae0c885cc/runtime_load.c#L13
Please see https://github.com/hnakamur/export_c_variable_from_go_dll_experiment/tree/0972d57461b091aed35c9ed083af0edae0c885cc#load-a-shared-library-at-runtime-using-dlopen for the whole output.

When I added usleep(1000 * 1000) between dlopen and referencing i, i=1 is printed at https://github.com/hnakamur/export_c_variable_from_go_dll_experiment/blob/1951dfb411dcff8986687ca98f801505397fc6cf/runtime_load.c#L14
Please see https://github.com/hnakamur/export_c_variable_from_go_dll_experiment/tree/1951dfb411dcff8986687ca98f801505397fc6cf#load-a-shared-library-at-runtime-using-dlopen for the whole output.

Please refer to the commit https://github.com/hnakamur/export_c_variable_from_go_dll_experiment/tree/1951dfb411dcff8986687ca98f801505397fc6cf for source codes.

runtime_load.c

#include <stdio.h>
#include <dlfcn.h>

int main(int argc, char **argv) {
    printf("runtime_load started\n");
    void *handle = dlopen("libgodll.so", RTLD_LAZY);
    if (!handle) {
        printf("dlopen failed\n");
        return 1;
    }
    printf("after dlopen. handle=%llx\n", (long long unsigned)handle);
    usleep(1000 * 1000);
    int *i_ptr = dlsym(handle, "i");
    printf("i=%d\n", *i_ptr);
#ifndef NO_DLCLOSE
    printf("calling dlclose\n");
    dlclose(handle);
    printf("after dlclose\n");
#endif
    return 0;
}

I would like to know when the Go initialization of shared libraries is finished without calling a Go function.

Ideally, I would like to set values of C variables at Go shared library compile time, instead of updating values of C variables with init() in a Go shared library.

@ianlancetaylor ianlancetaylor added this to the Go1.6 milestone Jul 18, 2015

@ianlancetaylor ianlancetaylor changed the title from Make it possible to know the go initialization in shared libraries is finished without calling a go function to runtime: Make it possible to know the go initialization in shared libraries is finished without calling a go function Jul 18, 2015

@ianlancetaylor ianlancetaylor self-assigned this Jul 18, 2015

@rsc

This comment has been minimized.

Contributor

rsc commented Nov 5, 2015

What's wrong with calling a Go function?

@rsc rsc changed the title from runtime: Make it possible to know the go initialization in shared libraries is finished without calling a go function to runtime: make it possible to know the go initialization in shared libraries is finished without calling a go function Nov 5, 2015

@ianlancetaylor

This comment has been minimized.

Contributor

ianlancetaylor commented Nov 5, 2015

This is -buildmode=c-shared, so we are writing a library that can operate as a plugin for an existing program. That program doesn't know that it needs to call a function. It doesn't know that the plugin is written in Go. The program thinks that after it loads the library it can freely refer to variables defined by the plugin.

@rsc rsc modified the milestones: Unplanned, Go1.6 Dec 5, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment