Update to Zig 0.16.0

This commit represents the majority of the work necessary to upgrade
Ghostty to use Zig 0.16.0.

Key parts:

* In addition to its previous responsibilities, the global state now
  houses state for global I/O implementations and the process
  environment. It is now also utilized in the main application along
  with the C library. Where necessary, global state is isolated from key
  parts of the implementation (e.g., in libghostty subsystems), and it's
  expected that this list will grow.

* We currently manage our own C translation layer where necessary. In
  these cases, cImport has been removed in favor of the new external
  translate-c package. Due to fixes that have needed be made to properly
  translate the dependencies that were swapped out, as mentioned, we
  have had to backport fixes from the current translate-c package (and
  the upstream Arocc dependency). We will host this ourselves until Zig
  0.17.0 is released with these fixes.

* Where necessary (only a small number of cases), some stdlib code from
  0.15.2 (and even from 0.17.0) has been taken, adopted, and vendored in
  lib/compat.

Co-authored-by: Leah Amelia Chen <hi@pluie.me>
This commit is contained in:
Chris Marchesi
2026-05-07 09:11:14 -07:00
parent 74d0c72fd9
commit e8525c0fd9
357 changed files with 8958 additions and 6098 deletions

View File

@@ -14,7 +14,7 @@ const renderer = @import("../renderer.zig");
/// members of this state. Note that the state itself is NOT protected
/// by the mutex and is NOT thread-safe, only the members values of the
/// state (i.e. the terminal, devmode, etc. values).
mutex: *std.Thread.Mutex,
mutex: *std.Io.Mutex,
/// The terminal data.
terminal: *terminalpkg.Terminal,
@@ -64,19 +64,19 @@ const handoff_timeout_ns = 1 * std.time.ns_per_ms;
/// scheduled. Under sustained pty output the IO parse thread is
/// exactly such a loop, so without this signal the renderer can
/// starve for as long as the output lasts.
pub fn lockDemand(self: *State) void {
pub fn lockDemand(self: *State, io: std.Io) void {
_ = self.demand.fetchAdd(1, .monotonic);
self.mutex.lock();
self.mutex.lockUncancelable(io);
const prev = self.demand.fetchSub(1, .monotonic);
assert(prev > 0);
}
/// Release `mutex` acquired via `lockDemand` and notify hot loops
/// parked in `yieldToDemand` that the demanding waiter had its turn.
pub fn unlockDemand(self: *State) void {
self.mutex.unlock();
pub fn unlockDemand(self: *State, io: std.Io) void {
self.mutex.unlock(io);
_ = self.handoff_gen.fetchAdd(1, .monotonic);
std.Thread.Futex.wake(&self.handoff_gen, 1);
io.futexWake(@TypeOf(self.handoff_gen), &self.handoff_gen, 1);
}
/// Called by hot lock/unlock loops between critical sections, with
@@ -88,7 +88,7 @@ pub fn unlockDemand(self: *State) void {
/// scheduling heuristic, not a synchronization boundary: the mutex
/// itself orders the protected data, and the timeout bounds any
/// staleness.
pub fn yieldToDemand(self: *State) void {
pub fn yieldToDemand(self: *State, io: std.Io) void {
if (self.demand.load(.monotonic) == 0) return;
// Snapshot the generation before rechecking demand: if the waiter
@@ -96,10 +96,11 @@ pub fn yieldToDemand(self: *State) void {
// generation no longer matches and timedWait returns immediately.
const gen = self.handoff_gen.load(.monotonic);
if (self.demand.load(.monotonic) == 0) return;
std.Thread.Futex.timedWait(
io.futexWaitTimeout(
@TypeOf(self.handoff_gen),
&self.handoff_gen,
gen,
handoff_timeout_ns,
.init(gen),
.{ .duration = .{ .raw = .fromNanoseconds(handoff_timeout_ns), .clock = .awake } },
) catch {};
}