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"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/wavetermdev/waveterm/pkg/filestore"
@ -77,6 +78,7 @@ type BlockController struct {
ShellInputCh chan *BlockInputUnion
ShellProcStatus string
ShellProcExitCode int
RunLock *atomic.Bool
}
type BlockControllerRuntimeStatus struct {
@ -492,7 +494,9 @@ func (bc *BlockController) DoRunShellCommand(rc *RunShellOpts, blockMeta waveobj
defer func() {
wshutil.DefaultRouter.UnregisterRoute(wshutil.MakeControllerRouteId(bc.BlockId))
bc.UpdateControllerAndSendUpdate(func() bool {
bc.ShellProcStatus = Status_Done
if bc.ShellProcStatus == Status_Running {
bc.ShellProcStatus = Status_Done
}
bc.ShellProcExitCode = exitCode
return true
})
@ -568,7 +572,31 @@ func setTermSize(ctx context.Context, blockId string, termSize waveobj.TermSize)
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) {
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()
controllerName := bdata.Meta.GetString(waveobj.MetaKey_Controller, "")
if controllerName != BlockController_Shell && controllerName != BlockController_Cmd {
@ -597,8 +625,10 @@ func (bc *BlockController) run(bdata *waveobj.Block, blockMeta map[string]any, r
return
}
}
runningShellCommand = true
go func() {
defer panichandler.PanicHandler("blockcontroller:run-shell-command")
defer bc.UnlockRunLock()
var termSize waveobj.TermSize
if rtOpts != nil {
termSize = rtOpts.TermSize
@ -658,7 +688,7 @@ func CheckConnStatus(blockId string) error {
func (bc *BlockController) StopShellProc(shouldWait bool) {
bc.Lock.Lock()
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
}
bc.ShellProc.Close()
@ -689,6 +719,7 @@ func getOrCreateBlockController(tabId string, blockId string, controllerName str
TabId: tabId,
BlockId: blockId,
ShellProcStatus: Status_Init,
RunLock: &atomic.Bool{},
}
blockControllerMap[blockId] = bc
createdController = true
@ -716,11 +747,13 @@ func ResyncController(ctx context.Context, tabId string, blockId string, rtOpts
}
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 {
bcStatus := curBc.GetRuntimeStatus()
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
@ -754,20 +787,20 @@ func startBlockController(ctx context.Context, tabId string, blockId string, rtO
return fmt.Errorf("unknown controller %q", controllerName)
}
connName := blockData.Meta.GetString(waveobj.MetaKey_Connection, "")
log.Printf("start blockcontroller %s %q (%q)\n", blockId, controllerName, connName)
err = CheckConnStatus(blockId)
if err != nil {
return fmt.Errorf("cannot start shellproc: %w", err)
}
bc := getOrCreateBlockController(tabId, blockId, controllerName)
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 {
go bc.run(blockData, blockData.Meta, rtOpts, force)
}
return nil
}
func StopBlockController(blockId string) {
func StopBlockControllerAndSetStatus(blockId string, newStatus string) {
bc := GetBlockController(blockId)
if bc == nil {
return
@ -776,13 +809,17 @@ func StopBlockController(blockId string) {
bc.ShellProc.Close()
<-bc.ShellProc.DoneCh
bc.UpdateControllerAndSendUpdate(func() bool {
bc.ShellProcStatus = Status_Done
bc.ShellProcStatus = newStatus
return true
})
}
}
func StopBlockController(blockId string) {
StopBlockControllerAndSetStatus(blockId, Status_Done)
}
func getControllerList() []*BlockController {
globalLock.Lock()
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
func (cs *ClientService) FocusWindow(ctx context.Context, windowId string) error {
log.Printf("FocusWindow %s\n", windowId)
return wcore.FocusWindow(ctx, windowId)
}