Introduce xferMap, avoid passing Go pointer into the C code.

Weirdness with memory barriers.
This commit is contained in:
Sebastian Zagrodzki
2017-04-26 21:32:49 +02:00
parent dacae32d83
commit 550fe8d1f2

View File

@@ -18,6 +18,7 @@ import (
"fmt"
"log"
"reflect"
"sync"
"time"
"unsafe"
)
@@ -138,9 +139,9 @@ type libusbIntf interface {
setAlt(*libusbDevHandle, uint8, uint8) error
// transfer
alloc(*libusbDevHandle, *EndpointInfo, time.Duration, int, []byte) (*libusbTransfer, error)
alloc(*libusbDevHandle, *EndpointInfo, time.Duration, int, []byte, chan struct{}) (*libusbTransfer, error)
cancel(*libusbTransfer) error
submit(*libusbTransfer, chan struct{}) error
submit(*libusbTransfer) error
data(*libusbTransfer) (int, TransferStatus)
free(*libusbTransfer)
setIsoPacketLengths(*libusbTransfer, uint32)
@@ -371,7 +372,7 @@ func (libusbImpl) setAlt(d *libusbDevHandle, iface, setup uint8) error {
return fromErrNo(C.libusb_set_interface_alt_setting((*C.libusb_device_handle)(d), C.int(iface), C.int(setup)))
}
func (libusbImpl) alloc(d *libusbDevHandle, ep *EndpointInfo, timeout time.Duration, isoPackets int, buf []byte) (*libusbTransfer, error) {
func (libusbImpl) alloc(d *libusbDevHandle, ep *EndpointInfo, timeout time.Duration, isoPackets int, buf []byte, done chan struct{}) (*libusbTransfer, error) {
xfer := C.libusb_alloc_transfer(C.int(isoPackets))
if xfer == nil {
return nil, fmt.Errorf("libusb_alloc_transfer(%d) failed", isoPackets)
@@ -381,17 +382,20 @@ func (libusbImpl) alloc(d *libusbDevHandle, ep *EndpointInfo, timeout time.Durat
xfer.timeout = C.uint(timeout / time.Millisecond)
xfer._type = C.uchar(ep.TransferType)
xfer.num_iso_packets = C.int(isoPackets)
xfer.buffer = (*C.uchar)((unsafe.Pointer)(&buf[0]))
xfer.buffer = (*C.uchar)(unsafe.Pointer(&buf[0]))
xfer.length = C.int(len(buf))
return (*libusbTransfer)(xfer), nil
ret := (*libusbTransfer)(xfer)
xferDoneMap.Lock()
xferDoneMap.m[ret] = done
xferDoneMap.Unlock()
return ret, nil
}
func (libusbImpl) cancel(t *libusbTransfer) error {
return fromErrNo(C.libusb_cancel_transfer((*C.struct_libusb_transfer)(t)))
}
func (libusbImpl) submit(t *libusbTransfer, done chan struct{}) error {
t.user_data = (unsafe.Pointer)(&done)
func (libusbImpl) submit(t *libusbTransfer) error {
return fromErrNo(C.submit((*C.struct_libusb_transfer)(t)))
}
@@ -406,6 +410,9 @@ func (libusbImpl) data(t *libusbTransfer) (int, TransferStatus) {
func (libusbImpl) free(t *libusbTransfer) {
C.libusb_free_transfer((*C.struct_libusb_transfer)(t))
xferDoneMap.Lock()
delete(xferDoneMap.m, t)
xferDoneMap.Unlock()
}
func (libusbImpl) setIsoPacketLengths(t *libusbTransfer, length uint32) {
@@ -420,10 +427,20 @@ var (
libusbIsoOffset = unsafe.Offsetof(C.struct_libusb_transfer{}.iso_packet_desc)
)
// xferDoneMap keeps a map of done callback channels for all allocated transfers.
var xferDoneMap = struct {
m map[*libusbTransfer]chan struct{}
sync.RWMutex
}{
m: make(map[*libusbTransfer]chan struct{}),
}
//export xferCallback
func xferCallback(cptr unsafe.Pointer) {
ch := *(*chan struct{})(cptr)
close(ch)
func xferCallback(xfer *C.struct_libusb_transfer) {
xferDoneMap.RLock()
ch := xferDoneMap.m[(*libusbTransfer)(xfer)]
xferDoneMap.RUnlock()
ch <- struct{}{}
}
// for benchmarking and testing