Introduce xferMap, avoid passing Go pointer into the C code.
Weirdness with memory barriers.
This commit is contained in:
@@ -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
|
||||
|
Reference in New Issue
Block a user