Current Connect implementation deadlocks on Darwin (https://github.com/go-ble/ble/blob/master/gatt.go#L126-L149):
func Connect(ctx context.Context, f AdvFilter) (Client, error) {
ctx2, cancel := context.WithCancel(ctx)
go func() {
select {
case <-ctx.Done():
cancel()
case <-ctx2.Done():
}
}()
ch := make(chan Advertisement)
fn := func(a Advertisement) {
cancel()
ch <- a
}
if err := Scan(ctx2, false, fn, f); err != nil {
if err != context.Canceled {
return nil, errors.Wrap(err, "can't scan")
}
}
cln, err := Dial(ctx, (<-ch).Addr())
return cln, errors.Wrap(err, "can't dial")
}
Note that ch is unbuffered. This means when fn is executed, the caller will block until a reader is ready; the only reader is the call to Dial in the above snippet. Therefore if Scan ends up blocking while fn tries to write to the channel, we have a deadlock.
Sure enough, in the Darwin Scan implementation, we have the following code:
// Begin processing responses from ch (events received by DidDiscoverPeripheral).
go func() {
for r := range ch {
h(r)
wg.Done()
}
}()
The handler h in this snippet is either fn or a wrapper around fn, depending on whether or not the call to Connect includes a filter. Therefore h blocks until the call to Dial, and the call to wg.Done() never executes. Since the waitgroup never unblocks, Scan never finishes and Dial is never called.
Current Connect implementation deadlocks on Darwin (https://github.com/go-ble/ble/blob/master/gatt.go#L126-L149):
Note that
chis unbuffered. This means whenfnis executed, the caller will block until a reader is ready; the only reader is the call toDialin the above snippet. Therefore ifScanends up blocking whilefntries to write to the channel, we have a deadlock.Sure enough, in the Darwin
Scanimplementation, we have the following code:The handler
hin this snippet is eitherfnor a wrapper aroundfn, depending on whether or not the call to Connect includes a filter. Thereforehblocks until the call to Dial, and the call towg.Done()never executes. Since the waitgroup never unblocks,Scannever finishes andDialis never called.