From afd497e194e8374b848a3ab2f91f8b820010035f Mon Sep 17 00:00:00 2001 From: Konstantin Koroviev Date: Mon, 9 Mar 2015 15:43:10 +0200 Subject: [PATCH 1/3] Dirty hack to fix race conditions in the daemon --- cmd/ipfs/daemon.go | 4 ++++ cmd/ipfs/main.go | 11 +++++++++++ commands/request.go | 7 ++++--- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index b1d9d696e..7ccaf8776 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -267,6 +267,10 @@ func daemonFunc(req cmds.Request, res cmds.Response) { gateway.ServeOption(), corehttp.VersionOption(), } + + // our global interrupt handler can now try to stop the daemon + close(req.Context().ContextIsReadyToBeClosed) + if rootRedirect != nil { opts = append(opts, rootRedirect) } diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index 8dc1f9d0b..69050804c 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -132,6 +132,14 @@ func main() { os.Exit(1) } + // our global interrupt handler may try to stop the daemon + // before the daemon is ready to be stopped; this dirty + // workaround is for the daemon only; other commands are always + // ready to be stopped + if invoc.cmd != daemonCmd { + close(invoc.req.Context().ContextIsReadyToBeClosed) + } + // ok, finally, run the command invocation. output, err := invoc.Run(ctx) if err != nil { @@ -473,6 +481,9 @@ func (i *cmdInvocation) setupInterruptHandler() { sig := allInterruptSignals() go func() { + // wait till the context is ready to be closed + <-ctx.ContextIsReadyToBeClosed + // first time, try to shut down. // loop because we may be diff --git a/commands/request.go b/commands/request.go index c9748198b..6a5e05775 100644 --- a/commands/request.go +++ b/commands/request.go @@ -28,8 +28,9 @@ type Context struct { config *config.Config LoadConfig func(path string) (*config.Config, error) - node *core.IpfsNode - ConstructNode func() (*core.IpfsNode, error) + node *core.IpfsNode + ConstructNode func() (*core.IpfsNode, error) + ContextIsReadyToBeClosed chan bool } // GetConfig returns the config of the current Command exection @@ -287,7 +288,7 @@ func NewRequest(path []string, opts OptMap, args []string, file files.File, cmd optDefs = make(map[string]Option) } - ctx := Context{Context: context.TODO()} + ctx := Context{Context: context.TODO(), ContextIsReadyToBeClosed: make(chan bool)} values := make(map[string]interface{}) req := &request{path, opts, args, file, cmd, ctx, optDefs, values, os.Stdin} err := req.ConvertOptions() From d23bed5baa2bd2cb86580021d0a2f09d16792a06 Mon Sep 17 00:00:00 2001 From: Konstantin Koroviev Date: Thu, 12 Mar 2015 11:42:07 +0200 Subject: [PATCH 2/3] Rename `ContextIsReadyToBeClosed` to `InitDone` --- cmd/ipfs/daemon.go | 2 +- cmd/ipfs/main.go | 4 ++-- commands/request.go | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd/ipfs/daemon.go b/cmd/ipfs/daemon.go index 7ccaf8776..e8794f68a 100644 --- a/cmd/ipfs/daemon.go +++ b/cmd/ipfs/daemon.go @@ -269,7 +269,7 @@ func daemonFunc(req cmds.Request, res cmds.Response) { } // our global interrupt handler can now try to stop the daemon - close(req.Context().ContextIsReadyToBeClosed) + close(req.Context().InitDone) if rootRedirect != nil { opts = append(opts, rootRedirect) diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index 69050804c..7696fad99 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -137,7 +137,7 @@ func main() { // workaround is for the daemon only; other commands are always // ready to be stopped if invoc.cmd != daemonCmd { - close(invoc.req.Context().ContextIsReadyToBeClosed) + close(invoc.req.Context().InitDone) } // ok, finally, run the command invocation. @@ -482,7 +482,7 @@ func (i *cmdInvocation) setupInterruptHandler() { go func() { // wait till the context is ready to be closed - <-ctx.ContextIsReadyToBeClosed + <-ctx.InitDone // first time, try to shut down. diff --git a/commands/request.go b/commands/request.go index 6a5e05775..e7f9d4e33 100644 --- a/commands/request.go +++ b/commands/request.go @@ -28,9 +28,9 @@ type Context struct { config *config.Config LoadConfig func(path string) (*config.Config, error) - node *core.IpfsNode - ConstructNode func() (*core.IpfsNode, error) - ContextIsReadyToBeClosed chan bool + node *core.IpfsNode + ConstructNode func() (*core.IpfsNode, error) + InitDone chan bool } // GetConfig returns the config of the current Command exection @@ -288,7 +288,7 @@ func NewRequest(path []string, opts OptMap, args []string, file files.File, cmd optDefs = make(map[string]Option) } - ctx := Context{Context: context.TODO(), ContextIsReadyToBeClosed: make(chan bool)} + ctx := Context{Context: context.TODO(), InitDone: make(chan bool)} values := make(map[string]interface{}) req := &request{path, opts, args, file, cmd, ctx, optDefs, values, os.Stdin} err := req.ConvertOptions() From 01db359c0f960a2cf10662ecb65e67c908a22ec4 Mon Sep 17 00:00:00 2001 From: Konstantin Koroviev Date: Thu, 12 Mar 2015 12:05:10 +0200 Subject: [PATCH 3/3] Kill the daemon during its startup --- cmd/ipfs/main.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cmd/ipfs/main.go b/cmd/ipfs/main.go index 7696fad99..2bca9dd45 100644 --- a/cmd/ipfs/main.go +++ b/cmd/ipfs/main.go @@ -481,15 +481,20 @@ func (i *cmdInvocation) setupInterruptHandler() { sig := allInterruptSignals() go func() { - // wait till the context is ready to be closed - <-ctx.InitDone - // first time, try to shut down. // loop because we may be for count := 0; ; count++ { <-sig + // if we're still initializing, cannot use `ctx.GetNode()` + select { + default: // initialization not done + fmt.Println("Received interrupt signal, shutting down...") + os.Exit(-1) + case <-ctx.InitDone: + } + // TODO cancel the command context instead n, err := ctx.GetNode()