Reserve toolsrv process slots atomically

This commit is contained in:
Ollie Agent 2026-08-18 06:50:02 +02:00
parent 562e1ef780
commit b6009f0f7a
1 changed files with 19 additions and 6 deletions

View File

@ -38,10 +38,11 @@ type State struct {
pathLocks pathLockTable
// Process management
procMu sync.Mutex
procs map[int]*Proc
nextID int
procLimit int
procMu sync.Mutex
procs map[int]*Proc
nextID int
procLimit int
procReserved int
// Callbacks
OnToolsChanged func()
@ -223,13 +224,23 @@ func (st *State) NewProc(ctx context.Context, payload string, background bool) (
return "", 0, fmt.Errorf("missing 'tool' in payload")
}
// Check proc limit
// Reserve a process slot before setup so concurrent callers cannot all pass
// the limit check while their processes are still being initialized.
st.procMu.Lock()
if len(st.procs) >= st.procLimit {
if len(st.procs)+st.procReserved >= st.procLimit {
st.procMu.Unlock()
return "", 0, fmt.Errorf("process limit reached (%d)", st.procLimit)
}
st.procReserved++
st.procMu.Unlock()
reserved := true
defer func() {
if reserved {
st.procMu.Lock()
st.procReserved--
st.procMu.Unlock()
}
}()
// Look up tool
st.mu.RLock()
@ -289,7 +300,9 @@ func (st *State) NewProc(ctx context.Context, payload string, background bool) (
st.procMu.Lock()
st.procs[proc.ID] = proc
st.procReserved--
st.procMu.Unlock()
reserved = false
// For background procs, stream output directly into the proc buffer.
// For foreground, use nil (local buffer in exec path).