//go:build !windows package windows import ( "context" "errors" "os" "time" "github.com/rvbox/rvbox/internal/client/supervisor" ) func stdinLineEnding() []byte { return []byte{'\n'} } // NewSupervisor returns the deterministic local adapter used by tests and by // non-Windows development builds. The v1 client does not advertise this // adapter as a supported Unix client; it exists so protocol/runtime tests can // exercise real child processes without a Windows host. func NewSupervisor(options NativeOptions) (supervisor.Supervisor, error) { return newExecSupervisor(options), nil } func (manager *execSupervisor) Start(ctx context.Context, spec supervisor.StartSpec) (supervisor.Process, error) { return manager.startPortable(ctx, spec) } func (manager *execSupervisor) Signal(ctx context.Context, process supervisor.Process, signal supervisor.SignalKind) (supervisor.SignalOutcome, error) { if process == nil { return supervisor.SignalOutcome{}, ErrProcessNotFound } executable, ok := process.(*execProcess) if !ok { return supervisor.SignalOutcome{}, ErrProcessNotFound } if signal != supervisor.SignalTerm && signal != supervisor.SignalKill { return supervisor.SignalOutcome{}, errors.New("unsupported signal") } if signal == supervisor.SignalTerm { if executable.cmd.Process != nil { _ = executable.cmd.Process.Signal(os.Interrupt) } select { case <-ctx.Done(): return supervisor.SignalOutcome{}, ctx.Err() case <-time.After(manager.options.WindowsTermGrace): } } if err := executable.terminate(1); err != nil { return supervisor.SignalOutcome{}, err } return supervisor.SignalOutcome{Delivered: true, Escalated: signal == supervisor.SignalTerm, Detail: "process terminated", ObservedAt: manager.options.Now()}, nil } func (manager *execSupervisor) Snapshot(ctx context.Context, process supervisor.Process) (supervisor.ResourceSnapshot, error) { if process == nil { return supervisor.ResourceSnapshot{}, ErrProcessNotFound } select { case <-ctx.Done(): return supervisor.ResourceSnapshot{}, ctx.Err() default: } return supervisor.ResourceSnapshot{ProcessCount: 1, ObservedAt: manager.options.Now(), Complete: false, Detail: "portable adapter does not expose aggregate process accounting"}, nil } func (manager *execSupervisor) StopAll(_ context.Context) error { manager.mu.Lock() processes := make([]*execProcess, 0, len(manager.active)) for _, process := range manager.active { processes = append(processes, process) } manager.mu.Unlock() for _, process := range processes { if err := process.terminate(1); err != nil && !errors.Is(err, os.ErrProcessDone) { return err } } return nil }