Skip to content

Commit

Permalink
Fix Object.Call blocking
Browse files Browse the repository at this point in the history
When used with the FlagNoReplyExpected flag
Object.Call blocks forever
because the returned Call.Done is nil

Returning a Call.Done with a closed channel
(with one reference to a call in it)
means reads to Call.Done won't block.
  • Loading branch information
whytheplatypus committed Aug 29, 2017
1 parent 9764685 commit 204f700
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 3 deletions.
18 changes: 18 additions & 0 deletions conn_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io"
"io/ioutil"
"testing"
"time"
)

func TestSessionBus(t *testing.T) {
Expand Down Expand Up @@ -44,6 +45,23 @@ func TestSend(t *testing.T) {
}
}

func TestFlagNoReplyExpectedSend(t *testing.T) {
bus, err := SessionBus()
if err != nil {
t.Fatal(err)
}
done := make(chan struct{})
go func() {
bus.BusObject().Call("org.freedesktop.DBus.ListNames", FlagNoReplyExpected)
close(done)
}()
select {
case <-done:
case <-time.After(1 * time.Second):
t.Error("Failed to announce that the call was done")
}
}

func TestRemoveSignal(t *testing.T) {
bus, err := NewConn(nil)
if err != nil {
Expand Down
17 changes: 14 additions & 3 deletions object.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ func (o *Object) AddMatchSignal(iface, member string) *Call {
// will be allocated. Otherwise, ch has to be buffered or Go will panic.
//
// If the flags include FlagNoReplyExpected, ch is ignored and a Call structure
// is returned of which only the Err member is valid.
// is returned with any error in Err and a closed channel in Done containing
// the returned Call as it's one entry.
//
// If the method parameter contains a dot ('.'), the part before the last dot
// specifies the interface on which the method is called.
Expand Down Expand Up @@ -97,11 +98,21 @@ func (o *Object) Go(method string, flags Flags, ch chan *Call, args ...interface
}
o.conn.outLck.RLock()
defer o.conn.outLck.RUnlock()
done := make(chan *Call, 1)
call := &Call{
Err: nil,
Done: done,
}
defer func() {
call.Done <- call
close(done)
}()
if o.conn.closed {
return &Call{Err: ErrClosed}
call.Err = ErrClosed
return call
}
o.conn.out <- msg
return &Call{Err: nil}
return call
}

// GetProperty calls org.freedesktop.DBus.Properties.GetProperty on the given
Expand Down

0 comments on commit 204f700

Please sign in to comment.