Created
May 17, 2017 11:56
-
-
Save ateleshev/f4a91df6b3e094719e257b8f751d3689 to your computer and use it in GitHub Desktop.
Check if Go channel is closed without touching/reading it.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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