-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix race/deadlock in v1 plugin handlers
When a plugin is activated, and then `plugins.Handle` is called to register a new handler for a given plugin type, a deadlock occurs when for anything which calls `waitActive`, including `Get`, and `GetAll`. This happens because `Handle()` is setting `activated` to `false` to ensure that plugin handlers are run on next activation. Maybe these handlers should be called immediately for any plugins which are already registered... but to preserve the existing behavior while fixing the deadlock, track if handlers have been run on plugins and reset when a new handler is registered. The simplest way to reproduce the deadlock with Docker is to add a `-v /foo` to the test container created for the external graphdriver tests. Signed-off-by: Brian Goff <[email protected]>
- Loading branch information
Showing
3 changed files
with
92 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package plugins | ||
|
||
import ( | ||
"path/filepath" | ||
"runtime" | ||
"sync" | ||
"testing" | ||
"time" | ||
) | ||
|
||
// regression test for deadlock in handlers | ||
func TestPluginAddHandler(t *testing.T) { | ||
// make a plugin which is pre-activated | ||
p := &Plugin{activateWait: sync.NewCond(&sync.Mutex{})} | ||
p.Manifest = &Manifest{Implements: []string{"bananas"}} | ||
storage.plugins["qwerty"] = p | ||
|
||
testActive(t, p) | ||
Handle("bananas", func(_ string, _ *Client) {}) | ||
testActive(t, p) | ||
} | ||
|
||
func testActive(t *testing.T, p *Plugin) { | ||
done := make(chan struct{}) | ||
go func() { | ||
p.waitActive() | ||
close(done) | ||
}() | ||
|
||
select { | ||
case <-time.After(100 * time.Millisecond): | ||
_, f, l, _ := runtime.Caller(1) | ||
t.Fatalf("%s:%d: deadlock in waitActive", filepath.Base(f), l) | ||
case <-done: | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters