Skip to content
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/cgo: deadlock during daemons in _cgo_wait_runtime_init_done #31860

Closed
eancc opened this issue May 6, 2019 · 3 comments
Closed

runtime/cgo: deadlock during daemons in _cgo_wait_runtime_init_done #31860

eancc opened this issue May 6, 2019 · 3 comments

Comments

@eancc
Copy link

eancc commented May 6, 2019

What version of Go are you using (go version)?

$ go version
go version go1.12.4 linux/amd64

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/data/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build504982591=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I am developing a static library with GO for use in C/C++
Here is an example:

shell>cat demo.c 

/**
 *  
 *  bulid:gcc -g ./demo.c -I./ -L./ -lcdemo -lpthread -o demo
 * 
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "libcdemo.h"

GoString toGoString(const char *str)
{
    int len = strlen(str);
    GoString gostr = {str, len};
    return gostr;
}
int init_daemon(void) 
{ 
        int pid; 
        int i; 

        signal(SIGTTOU,SIG_IGN);
        signal(SIGTTIN,SIG_IGN);
        signal(SIGTSTP,SIG_IGN);
        signal(SIGHUP,SIG_IGN);

        pid = fork();
        if(pid > 0) {
                exit(0); //exit parent
        }
        else if(pid < 0) { 
                return -1;
        }

        setsid();

        pid=fork();
        if( pid > 0) {
                exit(0);
        }
        else if( pid< 0) {
                return -1;
        }
 
        for(i=0;i< NOFILE;close(i++));
 
        chdir("/data/demo/");

        umask(0);

        signal(SIGCHLD,SIG_IGN); 

        return 0;
}
int main()
{
    printf("demo start... \r\n");

    //TODO todo something
    // ...
    //sleep(3);
    //call daemon
    init_daemon();
    sleep(3);
    //-----------------------call go function--------------------
    openlog("testlogs", LOG_CONS | LOG_PID, 0);  
    syslog(LOG_USER | LOG_INFO ,"This is a syslog test message generated by program \n");  
    //TODO todo something
    //Bar();
    syslog(LOG_USER | LOG_INFO ,"bar2:%s \n",Bar2());
    syslog(LOG_USER | LOG_INFO ,"bar2:%s \n","Hello C");

    // ...
    sleep(3);
    closelog();  
    return 0;
}

The go code:

shell>cat cdemo.go 

package main

import "C"
import (
        "fmt"
)

func main() {
        fmt.Println(Bar2())
        return
}

//export Bar2
func Bar2() *C.char {
        return C.CString("Hello World From Go!")
}

Compile the static library and use it

shell>go build -x -v -gcflags "-N -l" -buildmode=c-archive -o libcdemo.a .
shell>ls
cdemo.go  libcdemo.a  libcdemo.h
shell>mv libcdemo* cdemo_test
shell>cd cdemo_test
shell>ls
demo.c  libcdemo.a  libcdemo.h
shell>gcc -g ./demo.c -I./ -L./ -lcdemo -lpthread -o demo
shell>ls
demo  demo.c  libcdemo.a  libcdemo.h
shell>./demo
demo start...
shell>pstack 16968
#0  0x0000003dfe80b68c in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#1  0x0000000000401583 in _cgo_wait_runtime_init_done ()
#2  0x000000000040149c in Bar2 ()
#3  0x00000000004013d4 in main ()

What did you expect to see?

Hello World From Go!

What did you see instead?

The cgo blocked!

What do I need to do?

@ianlancetaylor ianlancetaylor changed the title runtime/cgo:deadlock during daemons in _cgo_wait_runtime_init_done runtime/cgo: deadlock during daemons in _cgo_wait_runtime_init_done May 6, 2019
@ianlancetaylor
Copy link
Contributor

I don't think there is any safe way to daemonize a program once the Go runtime has started, since the daemonization process copies only one thread, not all existing ones. When there are other threads running during daemonization, the daemonized process is starting with inconsistent memory. That is most likely the cause of the problem you are seeing. See the discussion in #227.

The only reasonable fix I know of is to make sure the daemonization happens before the Go runtime starts, either by doing it in a separate program or by doing it as a high priority initializer.

@eancc
Copy link
Author

eancc commented May 7, 2019

Thanks for your reply.
I am looking for a way to advance the daemon. Can you provide an example? Thanks

@ianlancetaylor
Copy link
Contributor

The simplest way is to use a separate program. It should do what your init_daemon function does, except that after the second fork it should execve the program you want to run as a daemon.

You may get a better answer on a forum: see https://golang.org/wiki/Questions .

I'm going to close this issue because we aren't to make any changes to the Go project to fix this.

@golang golang locked and limited conversation to collaborators May 6, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants