fix bcstart -- don't allow two controllers to start simultaneously (#1418)

This commit is contained in:
Mike Sawka 2024-12-06 11:08:51 -08:00 committed by GitHub
parent 6dfc85b324
commit 00e3c4ec75
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 44 additions and 8 deletions

View File

@ -13,6 +13,7 @@ import (
"log" "log"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/wavetermdev/waveterm/pkg/filestore" "github.com/wavetermdev/waveterm/pkg/filestore"
@ -77,6 +78,7 @@ type BlockController struct {
ShellInputCh chan *BlockInputUnion ShellInputCh chan *BlockInputUnion
ShellProcStatus string ShellProcStatus string
ShellProcExitCode int ShellProcExitCode int
RunLock *atomic.Bool
} }
type BlockControllerRuntimeStatus struct { type BlockControllerRuntimeStatus struct {
@ -492,7 +494,9 @@ func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta waveobj
defer func() { defer func() {
wshutil.DefaultRouter.UnregisterRoute(wshutil.MakeControllerRouteId(bc.BlockId)) wshutil.DefaultRouter.UnregisterRoute(wshutil.MakeControllerRouteId(bc.BlockId))
bc.UpdateControllerAndSendUpdate(func() bool { bc.UpdateControllerAndSendUpdate(func() bool {
bc.ShellProcStatus = Status_Done if bc.ShellProcStatus == Status_Running {
bc.ShellProcStatus = Status_Done
}
bc.ShellProcExitCode = exitCode bc.ShellProcExitCode = exitCode
return true return true
}) })
@ -568,7 +572,31 @@ func setTermSize(ctx context.Context, blockId string, termSize waveobj.TermSize)
return nil return nil
} }
func (bc *BlockController) LockRunLock() bool {
rtn := bc.RunLock.CompareAndSwap(false, true)
if rtn {
log.Printf("block %q run() lock\n", bc.BlockId)
}
return rtn
}
func (bc *BlockController) UnlockRunLock() {
bc.RunLock.Store(false)
log.Printf("block %q run() unlock\n", bc.BlockId)
}
func (bc *BlockController) run(bdata *waveobj.Block, blockMeta map[string]any, rtOpts *waveobj.RuntimeOpts, force bool) { func (bc *BlockController) run(bdata *waveobj.Block, blockMeta map[string]any, rtOpts *waveobj.RuntimeOpts, force bool) {
runningShellCommand := false
ok := bc.LockRunLock()
if !ok {
log.Printf("block %q is already executing run()\n", bc.BlockId)
return
}
defer func() {
if !runningShellCommand {
bc.UnlockRunLock()
}
}()
curStatus := bc.GetRuntimeStatus() curStatus := bc.GetRuntimeStatus()
controllerName := bdata.Meta.GetString(waveobj.MetaKey_Controller, "") controllerName := bdata.Meta.GetString(waveobj.MetaKey_Controller, "")
if controllerName != BlockController_Shell && controllerName != BlockController_Cmd { if controllerName != BlockController_Shell && controllerName != BlockController_Cmd {
@ -597,8 +625,10 @@ func (bc *BlockController) run(bdata *waveobj.Block, blockMeta map[string]any, r
return return
} }
} }
runningShellCommand = true
go func() { go func() {
defer panichandler.PanicHandler("blockcontroller:run-shell-command") defer panichandler.PanicHandler("blockcontroller:run-shell-command")
defer bc.UnlockRunLock()
var termSize waveobj.TermSize var termSize waveobj.TermSize
if rtOpts != nil { if rtOpts != nil {
termSize = rtOpts.TermSize termSize = rtOpts.TermSize
@ -658,7 +688,7 @@ func CheckConnStatus(blockId string) error {
func (bc *BlockController) StopShellProc(shouldWait bool) { func (bc *BlockController) StopShellProc(shouldWait bool) {
bc.Lock.Lock() bc.Lock.Lock()
defer bc.Lock.Unlock() defer bc.Lock.Unlock()
if bc.ShellProc == nil || bc.ShellProcStatus == Status_Done { if bc.ShellProc == nil || bc.ShellProcStatus == Status_Done || bc.ShellProcStatus == Status_Init {
return return
} }
bc.ShellProc.Close() bc.ShellProc.Close()
@ -689,6 +719,7 @@ func getOrCreateBlockController(tabId string, blockId string, controllerName str
TabId: tabId, TabId: tabId,
BlockId: blockId, BlockId: blockId,
ShellProcStatus: Status_Init, ShellProcStatus: Status_Init,
RunLock: &atomic.Bool{},
} }
blockControllerMap[blockId] = bc blockControllerMap[blockId] = bc
createdController = true createdController = true
@ -716,11 +747,13 @@ func ResyncController(ctx context.Context, tabId string, blockId string, rtOpts
} }
return nil return nil
} }
// check if conn is different, if so, stop the current controller log.Printf("resync controller %s %q (%q) (force %v)\n", blockId, controllerName, connName, force)
// check if conn is different, if so, stop the current controller, and set status back to init
if curBc != nil { if curBc != nil {
bcStatus := curBc.GetRuntimeStatus() bcStatus := curBc.GetRuntimeStatus()
if bcStatus.ShellProcStatus == Status_Running && bcStatus.ShellProcConnName != connName { if bcStatus.ShellProcStatus == Status_Running && bcStatus.ShellProcConnName != connName {
StopBlockController(blockId) log.Printf("stopping blockcontroller %s due to conn change\n", blockId)
StopBlockControllerAndSetStatus(blockId, Status_Init)
} }
} }
// now if there is a conn, ensure it is connected // now if there is a conn, ensure it is connected
@ -754,20 +787,20 @@ func startBlockController(ctx context.Context, tabId string, blockId string, rtO
return fmt.Errorf("unknown controller %q", controllerName) return fmt.Errorf("unknown controller %q", controllerName)
} }
connName := blockData.Meta.GetString(waveobj.MetaKey_Connection, "") connName := blockData.Meta.GetString(waveobj.MetaKey_Connection, "")
log.Printf("start blockcontroller %s %q (%q)\n", blockId, controllerName, connName)
err = CheckConnStatus(blockId) err = CheckConnStatus(blockId)
if err != nil { if err != nil {
return fmt.Errorf("cannot start shellproc: %w", err) return fmt.Errorf("cannot start shellproc: %w", err)
} }
bc := getOrCreateBlockController(tabId, blockId, controllerName) bc := getOrCreateBlockController(tabId, blockId, controllerName)
bcStatus := bc.GetRuntimeStatus() bcStatus := bc.GetRuntimeStatus()
log.Printf("start blockcontroller %s %q (%q) (curstatus %s) (force %v)\n", blockId, controllerName, connName, bcStatus.ShellProcStatus, force)
if bcStatus.ShellProcStatus == Status_Init || bcStatus.ShellProcStatus == Status_Done { if bcStatus.ShellProcStatus == Status_Init || bcStatus.ShellProcStatus == Status_Done {
go bc.run(blockData, blockData.Meta, rtOpts, force) go bc.run(blockData, blockData.Meta, rtOpts, force)
} }
return nil return nil
} }
func StopBlockController(blockId string) { func StopBlockControllerAndSetStatus(blockId string, newStatus string) {
bc := GetBlockController(blockId) bc := GetBlockController(blockId)
if bc == nil { if bc == nil {
return return
@ -776,13 +809,17 @@ func StopBlockController(blockId string) {
bc.ShellProc.Close() bc.ShellProc.Close()
<-bc.ShellProc.DoneCh <-bc.ShellProc.DoneCh
bc.UpdateControllerAndSendUpdate(func() bool { bc.UpdateControllerAndSendUpdate(func() bool {
bc.ShellProcStatus = Status_Done bc.ShellProcStatus = newStatus
return true return true
}) })
} }
} }
func StopBlockController(blockId string) {
StopBlockControllerAndSetStatus(blockId, Status_Done)
}
func getControllerList() []*BlockController { func getControllerList() []*BlockController {
globalLock.Lock() globalLock.Lock()
defer globalLock.Unlock() defer globalLock.Unlock()

View File

@ -49,7 +49,6 @@ func (cs *ClientService) GetAllConnStatus(ctx context.Context) ([]wshrpc.ConnSta
// moves the window to the front of the windowId stack // moves the window to the front of the windowId stack
func (cs *ClientService) FocusWindow(ctx context.Context, windowId string) error { func (cs *ClientService) FocusWindow(ctx context.Context, windowId string) error {
log.Printf("FocusWindow %s\n", windowId)
return wcore.FocusWindow(ctx, windowId) return wcore.FocusWindow(ctx, windowId)
} }