Skip to content

Instantly share code, notes, and snippets.

@ateleshev
Created May 17, 2017 11:56
Show Gist options
  • Save ateleshev/f4a91df6b3e094719e257b8f751d3689 to your computer and use it in GitHub Desktop.
Save ateleshev/f4a91df6b3e094719e257b8f751d3689 to your computer and use it in GitHub Desktop.
Check if Go channel is closed without touching/reading it.
package main
import (
"fmt"
"unsafe"
"reflect"
)
func isChanClosed(ch interface{}) bool {
if reflect.TypeOf(ch).Kind() != reflect.Chan {
panic("only channels!")
}
// get interface value pointer, from cgo_export
// typedef struct { void *t; void *v; } GoInterface;
// then get channel real pointer
cptr := *(*uintptr)(unsafe.Pointer(
unsafe.Pointer(uintptr(unsafe.Pointer(&ch)) + unsafe.Sizeof(uint(0))),
))
// this function will return true if chan.closed > 0
// see hchan on https://github.com/golang/go/blob/master/src/runtime/chan.go
// type hchan struct {
// qcount uint // total data in the queue
// dataqsiz uint // size of the circular queue
// buf unsafe.Pointer // points to an array of dataqsiz elements
// elemsize uint16
// closed uint32
// **
cptr += unsafe.Sizeof(uint(0))*2
cptr += unsafe.Sizeof(unsafe.Pointer(uintptr(0)))
cptr += unsafe.Sizeof(uint16(0))
return *(*uint32)(unsafe.Pointer(cptr)) > 0
}
func main() {
ch := make(chan int64)
fmt.Println(isChanClosed(ch)) // -> false
close(ch)
fmt.Println(isChanClosed(ch)) // -> true
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment