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

sdl.PushEvent(&sdl.UserEvent) produces "Cgo argument has Go pointer to Go pointer" for non-nil Data1 or Data2 #534

Open
iBug opened this issue Aug 20, 2022 · 3 comments

Comments

@iBug
Copy link

iBug commented Aug 20, 2022

This was originally asked on Stack Overflow, but I later discovered that Data1 and Data2 are completely unusable.

The code snippet is:

package main

import (
    "unsafe"

    "github.com/veandco/go-sdl2/sdl"
)

type MyType struct {
    A int
}

func main() {
    if err := sdl.Init(sdl.INIT_EVENTS); err != nil {
        panic(err)
    }

    ty := sdl.RegisterEvents(1)
    sdl.PushEvent(&sdl.UserEvent{
        Type:      ty,
        Timestamp: sdl.GetTicks(),
        Data1:     unsafe.Pointer(&MyType{}),
    })
}

In fact, Data1 can't be anything non-nil, so even this gives the "Go pointer to Go pointer" error:

var t int
sdl.PushEvent(&sdl.UserEvent{
    Type:      sdl.USEREVENT,
    Timestamp: sdl.GetTicks(),
    Data1:     unsafe.Pointer(&t),
})

Am I missing something? What is the correct way to pass extra data using Data1 and Data2 pointers?

iBug added a commit to iBug/Squares-go that referenced this issue Aug 20, 2022
@veeableful
Copy link
Contributor

Hi @iBug, thanks for submitting the question! I believe due to Go's garbage collector default behavior of disallowing having Go pointer within the object another Go pointer is pointing to, it is not possible to pass data to SDL2 which is using C runtime using Go-allocated pointers.

However if you would like to experiment with passing Go-allocated pointer to SDL2, you can disable the check by disabling the check using the command export GODEBUG=cgocheck=0 before building. After that, try building and running the program again.

Another, more long-winded way which satisfies Go's default behavior is that you can allocate data using C and pass C-allocated pointer instead like the following example:

package main

/*
#include <stdlib.h>
typedef struct MyType {
    int A;
} MyType;

static inline MyType* NewMyType(int A)
{
    MyType* myType = (MyType*) malloc(sizeof(MyType));
    myType->A = A;
    return myType;
}
*/
import "C"
import (
    "fmt"
    "unsafe"

    "github.com/veandco/go-sdl2/sdl"
)

type MyType struct {
    A int
}

func main() {
    if err := sdl.Init(sdl.INIT_EVENTS); err != nil {
        panic(err)
    }

    ty := sdl.RegisterEvents(1)

    running := true
    for running {
        sdl.PushEvent(&sdl.UserEvent{
            Type:      ty,
            Timestamp: sdl.GetTicks(),
            Data1:     unsafe.Pointer(C.NewMyType(37)),
        })
        for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
            switch ev := event.(type) {
            case *sdl.QuitEvent:
                running = false
            case *sdl.UserEvent:
                if ev.Type == ty {
                    data1 := (*C.MyType)(unsafe.Pointer(ev.Data1))
                    fmt.Println("UserEvent with type and value:", ev.Type, data1.A)
		    C.free(ev.Data1)
                }
            }
        }

        sdl.Delay(1000)
    }
}

Since I allocated using C, I also needed to free using C at some point. In this case, I chose to free immediately after processing it.

@iBug
Copy link
Author

iBug commented Aug 21, 2022

Thank you for your response. I'm not familiar with Cgo so I'd rather not touch that part with my application.

I ended up make(chan MyData, 16) and use PushEvent(UserEvent) as a notification for "data ready" so I don't have to create a separate select statement, which also enabled me to incorporate my custom events into the main sdl.PollEvent loop. This workaround was satisfactory for me as only an extra chan<- MyData needs to be carried around.

@veeableful
Copy link
Contributor

Oh that's really smart! I'm glad that you found a better solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants