Skip to content

Commit dd7bb9c

Browse files
Merge pull request digitalocean#158 from digitalocean/wait-for-signal-block
qemu/block: fixes deadlock in waitForSignal
2 parents d5e8dbf + 2a5482d commit dd7bb9c

File tree

5 files changed

+13
-17
lines changed

5 files changed

+13
-17
lines changed

hypervisor/example_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@ import (
2323
"github.com/digitalocean/go-qemu/qmp/qmptest"
2424
)
2525

26-
// ExampleStub exists to prevent godoc from treating this as a "whole-file"
27-
// example, and showing the code for the unexported types.
28-
func ExampleStub() {}
29-
3026
func ExampleNew() {
3127
// Create a hypervisor.Hypervisor using an in-memory hypervisor.Driver,
3228
// that returns a fixed list of three domains.

internal/qmp-gen/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
"io/ioutil"
2323
)
2424

25-
const specURL = `https://raw.githubusercontent.com/qemu/qemu/master/qapi-schema.json`
25+
const specURL = `https://raw.githubusercontent.com/qemu/qemu/stable-2.11/qapi-schema.json`
2626

2727
var (
2828
inputSpec = flag.String("input", specURL, "Input spec")

qemu/block.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -225,21 +225,25 @@ func (bd BlockDevice) Snapshot(d *Domain, overlay string) error {
225225
// waitForSignal opens a domain's QMP event stream and invokes an input
226226
// closure to send commands which would create results on that event stream.
227227
func waitForSignal(d *Domain, signal string, timeout time.Duration, fn func() error) error {
228-
// "done" signal must be sent in both the error and non-error case, to
229-
// avoid leaking goroutines.
228+
// "done" signal must always be sent to avoid leaking goroutines.
230229
events, done, err := d.Events()
231230
if err != nil {
232231
return err
233232
}
233+
defer func() { done <- struct{}{} }()
234234

235-
if err = fn(); err != nil {
236-
done <- struct{}{}
235+
// start listening for events prior to command execution. QMP events
236+
// may emit before the command returns.
237+
jobErr := make(chan error)
238+
go func() {
239+
jobErr <- waitForJob(events, signal, timeout)
240+
}()
241+
242+
if err := fn(); err != nil {
237243
return err
238244
}
239245

240-
err = waitForJob(events, signal, timeout)
241-
done <- struct{}{}
242-
return err
246+
return <-jobErr
243247
}
244248

245249
// waitForJob monitors the domain's QMP event stream, waiting

qemu/example_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@ import (
2323
"github.com/digitalocean/go-qemu/qmp/qmptest"
2424
)
2525

26-
// ExampleStub exists to prevent godoc from treating this as a "whole-file"
27-
// example, and showing the code for the unexported exampleMonitor type.
28-
func ExampleStub() {}
29-
3026
// This example demonstrates how to use qemu.NewDomain with a qmp.Monitor to
3127
// perform actions on a Domain.
3228
//

qmp/raw/spec.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
##QEMU SPECIFICATION VERSION: 2.11.50
2+
##QEMU SPECIFICATION VERSION: 2.11.2
33

44

55
# Whitelists to permit QAPI rule violations; think twice before you

0 commit comments

Comments
 (0)