Checks for closed/uninitialized context and devices. (#93)

This commit is contained in:
Sebastian Zagrodzki
2021-01-15 17:25:29 +01:00
committed by GitHub
parent c9efe54672
commit 0eba1b1264
3 changed files with 51 additions and 10 deletions

54
usb.go
View File

@@ -125,11 +125,20 @@ see the excellent "USB in a nutshell" guide: http://www.beyondlogic.org/usbnutsh
*/
package gousb
import (
"errors"
"fmt"
"sync"
)
// Context manages all resources related to USB device handling.
type Context struct {
ctx *libusbContext
done chan struct{}
libusb libusbIntf
mu sync.Mutex
devices map[*Device]bool
}
// Debug changes the debug level. Level 0 means no debug, higher levels
@@ -146,9 +155,10 @@ func newContextWithImpl(impl libusbIntf) *Context {
panic(err)
}
ctx := &Context{
ctx: c,
done: make(chan struct{}),
libusb: impl,
ctx: c,
done: make(chan struct{}),
libusb: impl,
devices: make(map[*Device]bool),
}
go impl.handleEvents(ctx.ctx, ctx.done)
return ctx
@@ -165,6 +175,9 @@ func NewContext() *Context {
// If there are any errors enumerating the devices,
// the final one is returned along with any successfully opened devices.
func (c *Context) OpenDevices(opener func(desc *DeviceDesc) bool) ([]*Device, error) {
if c.ctx == nil {
return nil, errors.New("OpenDevices called on a closed or uninitialized Context")
}
list, err := c.libusb.getDevices(c.ctx)
if err != nil {
return nil, err
@@ -187,7 +200,11 @@ func (c *Context) OpenDevices(opener func(desc *DeviceDesc) bool) ([]*Device, er
reterr = err
continue
}
ret = append(ret, &Device{handle: handle, ctx: c, Desc: desc})
o := &Device{handle: handle, ctx: c, Desc: desc}
ret = append(ret, o)
c.mu.Lock()
c.devices[o] = true
c.mu.Unlock()
} else {
c.libusb.dereference(dev)
}
@@ -219,13 +236,32 @@ func (c *Context) OpenDeviceWithVIDPID(vid, pid ID) (*Device, error) {
return devs[0], nil
}
func (c *Context) closeDev(d *Device) {
c.mu.Lock()
defer c.mu.Unlock()
c.libusb.close(d.handle)
delete(c.devices, d)
}
func (c *Context) checkOpenDevs() error {
c.mu.Lock()
defer c.mu.Unlock()
if l := len(c.devices); l > 0 {
return fmt.Errorf("Context.Close called while %d Devices are still open, Close may be called only after all previously opened devices were successfuly closed.", l)
}
return nil
}
// Close releases the Context and all associated resources.
func (c *Context) Close() error {
var ret error
c.done <- struct{}{}
if c.ctx != nil {
ret = c.libusb.exit(c.ctx)
if c.ctx == nil {
return nil
}
if err := c.checkOpenDevs(); err != nil {
return err
}
c.done <- struct{}{}
err := c.libusb.exit(c.ctx)
c.ctx = nil
return ret
return err
}