-
Notifications
You must be signed in to change notification settings - Fork 71
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
Provide access to errno #244
Comments
Hey @dominikh, you can use dlsym to get the address of errno. The uinx / syscall package also allows you to convert them into into string or whatever. Is that what you are looking for? package main
import (
"fmt"
"unsafe"
"github.com/ebitengine/purego"
"golang.org/x/sys/unix"
)
func main() {
libc, err := purego.Dlopen("libc.so.6", purego.RTLD_LAZY)
if err != nil {
panic(err)
}
var fopen func(filename, mode string) unsafe.Pointer
purego.RegisterLibFunc(&fopen, libc, "fopen")
errno, err := purego.Dlsym(libc, "errno")
file := fopen("this file does not exist!", "r")
if file == nil {
if err != nil {
panic(err)
}
// using &errno prevents go vet yelling "possible misuse of unsafe.Pointer"
fmt.Println((*(**unix.Errno)(unsafe.Pointer(&errno))).Error())
}
} [jupiterrider@pc42 demo]$ go run .
no such file or directory |
What happens if between the call to fopen and the read of errno Go moves the goroutine to a different thread? At that point we'd be reading errno of the wrong thread. I also don't believe that this is portable across different libc implementations. While this seems to work for glibc, it doesn't for musl (node-ffi/node-ffi#273). What about macOS or the BSDs? I don't actually know if the portability issue is solvable without the use of C. |
Regarding portability, here are two ways in which the Rust ecosystem is handling access to errno on Unix systems, both of which boil down to "hard-code per-platform options". It seems that on Linux, the various libcs agree to provide |
Dlsym is the recommended way. Use runtime.LockOSThread to ensure the thread doesn't change. I don't believe musl is even supported. There were some messages on the discord about having issues. Dlsym should work on macOS |
With the usage of the What is even the need of having this feature in purego? |
I don't see how
Even if that wasn't the case, and
Are you asking why this has to be in purego itself, or why any purego user would need to access errno? |
@dominikh
Why it has to be in purego itself. purego is kind of the cgo-free Version of dlfcn.h. |
In terms of necessity, I was hoping that purego could avoid the cost of calling LockOSThread by reading and storing errno in the same cgocall as calling the C function. I don't know if that is feasible, however. In terms of API design, it makes sense to me that purego would offer some help with getting errno, as that is the interface with which the majority of functions do error reporting. Otherwise, every user will have to rediscover on their own that every platform needs a different way of accessing errno, and be aware of the multithreading caveat. Or more likely they will find a way of accessing errno that works on their system (such as #244 (comment)), not be aware of the need for LockOSThread, and write code that doesn't work reliably. Users of cgo, or C users of dlfcn.h, do not face this problem, as in both cases they get automatic access to errno. Cgo turns errno into an |
Is this cost actually significant in any profiles? I'm not against this feature. |
Looking into this more (golang/go#21827), most of the cost of LockOSThread is for locked goroutines that communicate with other goroutines (e.g. via channels.) The raw cost of calling LockOSThread is a handful of atomic reads and writes, so not that noteworthy in isolation.
You could allow Go function types with an |
Operating System
What feature would you like to be added?
In cgo, C function calls can optionally return an additional value, the value of errno after returning from the function (in the form of an
error
). Purego should provide something similar.Why is this needed?
Being able to read errno is important to get useful error information. errno is thread-local, which means we cannot read it ourselves without locking the goroutine to its thread. Furthermore, errno is allowed to be a macro, so there is no straightforward, non-cgo way of reading it.
The text was updated successfully, but these errors were encountered: