Files
ghostty/src/termio/backend.zig
Mitchell Hashimoto 591ef0f40f Move child exit handling logic to apprt thread
Fixes #7500
Supersedes #7582

This commit moves the child exit handling logic from the IO thead to the
apprt thread. The IO thread now only sends a `child_exited` message to
the apprt thread with metadata about the exit conditions (exit code,
runtime).

From there, the apprt thread can handle the exit situation however is
necessary. This commit doesn't change the behavior but it does fix the
issue #7500. The behavior is: exit immediately, show abnormal exit
message, wait for user input, etc.

This also gets us closer to #7649.
2025-06-27 10:36:23 -07:00

129 lines
3.5 KiB
Zig

const std = @import("std");
const builtin = @import("builtin");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const posix = std.posix;
const xev = @import("../global.zig").xev;
const build_config = @import("../build_config.zig");
const configpkg = @import("../config.zig");
const internal_os = @import("../os/main.zig");
const renderer = @import("../renderer.zig");
const shell_integration = @import("shell_integration.zig");
const terminal = @import("../terminal/main.zig");
const termio = @import("../termio.zig");
const Command = @import("../Command.zig");
const Pty = @import("../pty.zig").Pty;
// The preallocation size for the write request pool. This should be big
// enough to satisfy most write requests. It must be a power of 2.
const WRITE_REQ_PREALLOC = std.math.pow(usize, 2, 5);
/// The kinds of backends.
pub const Kind = enum { exec };
/// Configuration for the various backend types.
pub const Config = union(Kind) {
/// Exec uses posix exec to run a command with a pty.
exec: termio.Exec.Config,
};
/// Backend implementations. A backend is responsible for owning the pty
/// behavior and providing read/write capabilities.
pub const Backend = union(Kind) {
exec: termio.Exec,
pub fn deinit(self: *Backend) void {
switch (self.*) {
.exec => |*exec| exec.deinit(),
}
}
pub fn initTerminal(self: *Backend, t: *terminal.Terminal) void {
switch (self.*) {
.exec => |*exec| exec.initTerminal(t),
}
}
pub fn threadEnter(
self: *Backend,
alloc: Allocator,
io: *termio.Termio,
td: *termio.Termio.ThreadData,
) !void {
switch (self.*) {
.exec => |*exec| try exec.threadEnter(alloc, io, td),
}
}
pub fn threadExit(self: *Backend, td: *termio.Termio.ThreadData) void {
switch (self.*) {
.exec => |*exec| exec.threadExit(td),
}
}
pub fn focusGained(
self: *Backend,
td: *termio.Termio.ThreadData,
focused: bool,
) !void {
switch (self.*) {
.exec => |*exec| try exec.focusGained(td, focused),
}
}
pub fn resize(
self: *Backend,
grid_size: renderer.GridSize,
screen_size: renderer.ScreenSize,
) !void {
switch (self.*) {
.exec => |*exec| try exec.resize(grid_size, screen_size),
}
}
pub fn queueWrite(
self: *Backend,
alloc: Allocator,
td: *termio.Termio.ThreadData,
data: []const u8,
linefeed: bool,
) !void {
switch (self.*) {
.exec => |*exec| try exec.queueWrite(alloc, td, data, linefeed),
}
}
pub fn childExitedAbnormally(
self: *Backend,
gpa: Allocator,
t: *terminal.Terminal,
exit_code: u32,
runtime_ms: u64,
) !void {
switch (self.*) {
.exec => |*exec| try exec.childExitedAbnormally(
gpa,
t,
exit_code,
runtime_ms,
),
}
}
};
/// Termio thread data. See termio.ThreadData for docs.
pub const ThreadData = union(Kind) {
exec: termio.Exec.ThreadData,
pub fn deinit(self: *ThreadData, alloc: Allocator) void {
switch (self.*) {
.exec => |*exec| exec.deinit(alloc),
}
}
pub fn changeConfig(self: *ThreadData, config: *termio.DerivedConfig) void {
_ = self;
_ = config;
}
};