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" "fmt"
"log" "log"
"reflect" "reflect"
"sync"
"time" "time"
"unsafe" "unsafe"
) )
@@ -138,9 +139,9 @@ type libusbIntf interface {
setAlt(*libusbDevHandle, uint8, uint8) error setAlt(*libusbDevHandle, uint8, uint8) error
// transfer // transfer
alloc(*libusbDevHandle, *EndpointInfo, time.Duration, int, []byte) (*libusbTransfer, error) alloc(*libusbDevHandle, *EndpointInfo, time.Duration, int, []byte, chan struct{}) (*libusbTransfer, error)
cancel(*libusbTransfer) error cancel(*libusbTransfer) error
submit(*libusbTransfer, chan struct{}) error submit(*libusbTransfer) error
data(*libusbTransfer) (int, TransferStatus) data(*libusbTransfer) (int, TransferStatus)
free(*libusbTransfer) free(*libusbTransfer)
setIsoPacketLengths(*libusbTransfer, uint32) 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))) 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)) xfer := C.libusb_alloc_transfer(C.int(isoPackets))
if xfer == nil { if xfer == nil {
return nil, fmt.Errorf("libusb_alloc_transfer(%d) failed", isoPackets) 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.timeout = C.uint(timeout / time.Millisecond)
xfer._type = C.uchar(ep.TransferType) xfer._type = C.uchar(ep.TransferType)
xfer.num_iso_packets = C.int(isoPackets) 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)) 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 { func (libusbImpl) cancel(t *libusbTransfer) error {
return fromErrNo(C.libusb_cancel_transfer((*C.struct_libusb_transfer)(t))) return fromErrNo(C.libusb_cancel_transfer((*C.struct_libusb_transfer)(t)))
} }
func (libusbImpl) submit(t *libusbTransfer, done chan struct{}) error { func (libusbImpl) submit(t *libusbTransfer) error {
t.user_data = (unsafe.Pointer)(&done)
return fromErrNo(C.submit((*C.struct_libusb_transfer)(t))) 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) { func (libusbImpl) free(t *libusbTransfer) {
C.libusb_free_transfer((*C.struct_libusb_transfer)(t)) C.libusb_free_transfer((*C.struct_libusb_transfer)(t))
xferDoneMap.Lock()
delete(xferDoneMap.m, t)
xferDoneMap.Unlock()
} }
func (libusbImpl) setIsoPacketLengths(t *libusbTransfer, length uint32) { func (libusbImpl) setIsoPacketLengths(t *libusbTransfer, length uint32) {
@@ -420,10 +427,20 @@ var (
libusbIsoOffset = unsafe.Offsetof(C.struct_libusb_transfer{}.iso_packet_desc) 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 //export xferCallback
func xferCallback(cptr unsafe.Pointer) { func xferCallback(xfer *C.struct_libusb_transfer) {
ch := *(*chan struct{})(cptr) xferDoneMap.RLock()
close(ch) ch := xferDoneMap.m[(*libusbTransfer)(xfer)]
xferDoneMap.RUnlock()
ch <- struct{}{}
} }
// for benchmarking and testing // for benchmarking and testing