Documentation
¶
Overview ¶
Package platform contains the small amount of process behaviour that is inherently operating-system specific. Keeping it outside the session package makes the PTY lifecycle compile cleanly on unsupported platforms.
Index ¶
- Variables
- func IsPTYCloseError(err error) bool
- func KillProcessGroup(command *exec.Cmd)
- func NewShellCommand(ctx context.Context, script string) (*exec.Cmd, error)
- func ProcessGroupExists(command *exec.Cmd) bool
- func ProcessGroupHasLiveMember(command *exec.Cmd) bool
- func ProcessGroupIDHasLiveMember(pgid int) bool
- func ProcessGroupLivenessIsExact() bool
- func PublishByRename(source, target string) error
- func ReapProcessGroupZombies(command *exec.Cmd) int
- func RemoveFile(path string) error
- func RetryWhileTransient(operation func() error) error
- func SetGracefulCancel(command *exec.Cmd, grace time.Duration, stop func())
- func TerminateProcessGroup(command *exec.Cmd)
- func TransientFileError(error) bool
Constants ¶
This section is empty.
Variables ¶
var ErrShellUnsupported = errors.New("shell execution not supported on this platform")
ErrShellUnsupported reports that the current platform has no supported system shell launcher for PTY-backed sessions.
var ReplaceTimeout = 2 * time.Second
ReplaceTimeout bounds how long a replacement waits for a refusal to clear. It is a var so a test can shorten it; nothing else should write it.
Functions ¶
func IsPTYCloseError ¶
IsPTYCloseError recognizes the EIO returned by many Unix PTY masters after the slave side has closed.
func KillProcessGroup ¶
KillProcessGroup forcefully stops the process group and then kills the leader as a fallback in case group signalling failed.
func NewShellCommand ¶
NewShellCommand constructs the explicitly requested Unix shell invocation. The script is passed as one argument; it is never interpolated by Relayer.
func ProcessGroupExists ¶
ProcessGroupExists reports whether the command's process group still exists.
func ProcessGroupHasLiveMember ¶ added in v0.8.14
ProcessGroupHasLiveMember reports whether the command's process group still has a member that can run. Unlike ProcessGroupExists it does not count a member left as a zombie: it runs no code and has closed every descriptor, the PTY slave included. It only keeps the group's number reserved until whoever adopted it reaps it, which an init that reaps on a timer takes a second or two to do, and Relayer itself running as PID 1 never does.
It is only meaningful once the group was sent SIGKILL: the kernel then lets no member start a new one, so a group seen with nothing but zombies stays that way. Only Linux can tell a zombie apart here; elsewhere, and wherever /proc may not show every member, it is ProcessGroupExists.
func ProcessGroupIDHasLiveMember ¶ added in v0.8.14
ProcessGroupIDHasLiveMember is ProcessGroupHasLiveMember for a group known only by its number.
func ProcessGroupLivenessIsExact ¶ added in v0.8.14
func ProcessGroupLivenessIsExact() bool
ProcessGroupLivenessIsExact reports whether ProcessGroupHasLiveMember can tell a group left only with zombies from a live one here, rather than count every group that exists as live.
func PublishByRename ¶ added in v0.8.1
PublishByRename moves a fully written temporary file over the file it replaces, waiting out a transient platform refusal.
A failure that will not clear -- a missing source, a missing directory -- is returned at once: waiting does not create a file, and the caller needs the report now.
func ReapProcessGroupZombies ¶ added in v0.8.15
ReapProcessGroupZombies waits for every member of the command's process group that has exited and is Relayer's child, and returns how many it reaped. Only the leader starts as Relayer's child, and it is reaped by os/exec; the other members become Relayer's children only when they are orphaned and Relayer adopts them, which it does as PID 1 in a container started without an init. Nothing else would ever reap those, so each Stop would leave its agent's orphans in the process table for good.
It never blocks and never waits for a process outside the group, so it cannot take the exit status of a child os/exec is waiting for elsewhere. Call it only once the leader has been reaped, as its own Wait would otherwise lose the leader's status.
func RemoveFile ¶ added in v0.8.1
RemoveFile deletes a file, waiting out a transient platform refusal.
A file that is already absent is not an error: callers use this to clear a path before writing it, and a path that is already clear is the state they wanted.
func RetryWhileTransient ¶ added in v0.8.1
RetryWhileTransient runs an operation until it succeeds, fails permanently, or the budget is spent. The last error is returned unwrapped so a caller can still inspect it.
func SetGracefulCancel ¶ added in v0.8.6
SetGracefulCancel makes cancelling the command's context call stop — the caller's graceful stop request — instead of os/exec's default of killing the leader outright. A leader still running after grace is then killed by os/exec itself.
Without it, every path that cancels a parent context before stopping the sessions — a supervisor shutting down, a signal to relayer serve — sent SIGKILL to each agent before any SIGTERM, so no agent could shut down cleanly. The caller passes its own stop request rather than a signal, so the cancellation and a later explicit stop are one request and one SIGTERM: an agent whose handler runs only once was killed by a second.
os/exec may call Cancel after the leader was reaped but before Wait returned, and the session only learns of the reap when Wait returns. In that moment the stop request signals the group by number, as the session's own cleanup does right after the reap. That is safe on Unix: the kernel keeps a group's number reserved while any member lives, and a group with no member left answers ESRCH unless the whole PID space wrapped around in between. Windows has no such rule, which is why it holds the process handle instead.
func TerminateProcessGroup ¶
TerminateProcessGroup asks the whole process group led by command to stop. creack/pty starts commands in a new session on Unix, so the command PID is also the process-group ID.
func TransientFileError ¶ added in v0.8.1
TransientFileError reports nothing as transient away from Windows.
rename(2) and unlink(2) do not fail because another process holds the file open, so every error they return is a real one: a missing path, a cross-device move, a permission problem. Retrying would delay the report without changing it.
Types ¶
This section is empty.