cgoopenmpicgopetsc

Use Petsc-Library in Go


I am trying to use the PETSc (Portable, Extensible Toolkit for Scientific Computation) library in Go over cgo. After the call of PetscInitialize, the program will crash at a random point with the error:

[0]PETSC ERROR: ------------------------------------------------------------------------
[0]PETSC ERROR: Caught signal
[0]PETSC ERROR: Try option -start_in_debugger or -on_error_attach_debugger
[0]PETSC ERROR: or see https://petsc.org/release/faq/#valgrind and https://petsc.org/release/faq/
[0]PETSC ERROR: ---------------------  Stack Frames ------------------------------------
SIGABRT: abort
PC=0x732cd809eb2c m=0 sigcode=18446744073709551610

Every command that I use works and I also get the correct result, if it does not crash before... The simplified code looks something like this:

func main() {
    runtime.LockOSThread()
    defer runtime.UnlockOSThread()
    if err := PetscInitialize(os.Args, "", ""); err != nil {
        panic("could not initialize petsc")
    }
    doSomeNonPetscRelatedStuff()
}

where PetscInitialize is an interface to C.PetscInitialize.

I tried compiling Petsc in the debug mode without OpenMPI, but it still crashes. When I do everything in pure C, it works.

Edit: More Code Details:

import ...

func doSomeNonPetscRelatedStuff() {
    // some things, that take time.
    // The crash happens more consistently, if one goes slowly line by line in a debugger.
}

func PetscInitialize(args []string, file string, help string) error {
    cArgc, cArgv := argsToC(args)
    //defer c_freeArray_string(cArgv, c_size_t(cArgc))

    var cFile *c_char
    if file != "" {
        cFile = c_CString(file)
        defer c_free(unsafe.Pointer(cFile))
    }
    var cHelp *c_char
    if help != "" {
        cHelp = c_CString(help)
        defer c_free(unsafe.Pointer(cHelp))
    }

    if cIerr := c_PetscInitialize(&cArgc, &cArgv, cFile, cHelp); cIerr != 0 {
        return errors.New(fmt.Sprintf("PetscInitialize failed with errorcode: %v", int(cIerr)))
    }
    return nil
}

func argsToC(args []string) (argc c_int, argv **c_char) {
    argc = c_int(len(args))
    argv = c_makeArray_string(c_size_t(argc))
    for i, args_i := range args {
        cArgs_i := c_CString(args_i)
        c_writeArray_string(argv, cArgs_i, c_size_t(i))
    }
    return
}

This is a separate file, to have all C-stuff in one file and no import "C" in other files:

/*
#cgo CFLAGS: ...
#cgo LDFLAGS: ...

#include <slepceps.h>
#include <slepcnep.h>
#include <stdlib.h>

static void writeArray_string(char **arr, char *s, size_t n) {
    arr[n] = s;
}
static char**makeArray_string(size_t size) {
    return calloc(sizeof(char*), size);
}
*/
import "C"


type c_int = C.int
type c_char = C.char
type c_void = C.void
type c_size_t = C.size_t

func c_CString(str string) *c_char {
    return C.CString(str)
}

func c_writeArray_string(arr **c_char, s *c_char, n c_size_t) {
    C.writeArray_string(arr, s, n)
}

func c_makeArray_string(size c_size_t) **c_char {
    return C.makeArray_string(size)
}

func c_free(ptr unsafe.Pointer) {
    C.free(ptr)
}

func c_PetscInitialize(argc *c_int, args ***c_char, file *c_char, help *c_char) c_PetscErrorCode {
    return C.PetscInitialize(argc, args, file, help)
}

Notes:


Solution

  • The solution thanks to @kostix:

    I added before PetscInitialize:

    if err := PetscOptionsSetValue(nil, "-no_signal_handler", "true"); err != nil {
        panic("could not set option")
    }
    

    with

    func PetscOptionsSetValue(options c_PetscOptions, name, value string) error {
        c_name := c_CString(name)
        defer c_free(unsafe.Pointer(c_name))
        c_value := c_CString(value)
        defer c_free(unsafe.Pointer(c_value))
        if cIerr := c_PetscOptionsSetValue(options, c_name, c_value); cIerr != 0 {
            return errors.New("Could not PetscOptionsSetValue, error-code: " + strconv.Itoa(int(cIerr)) + "\n")
        }
        return nil
    }
    

    and

    type c_PetscOptions = C.PetscOptions
    
    func c_PetscOptionsSetValue(options c_PetscOptions, name *c_char, value *c_char) c_PetscErrorCode {
        return C.PetscOptionsSetValue(options, name, value)
    }
    

    It also seems working when I moved the setting of the option and the initialization in func init() and remove runtime.LockOSThread().