Skip to content

Commit

Permalink
add timeout (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
jiacai2050 authored Jan 23, 2025
1 parent 04296e3 commit 09c75b3
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 12 deletions.
8 changes: 7 additions & 1 deletion build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ fn buildBinaries(
"dark-mode",
"repeat",
"tcp-proxy",
"timeout",
}) |name| {
try buildBinary(
b,
Expand Down Expand Up @@ -207,7 +208,7 @@ fn makeCompileStep(
// We can't use `target.result.isDarwin()` here
// Since when cross compile to darwin, there is no framework in the host!
const is_darwin = @import("builtin").os.tag == .macos;

const is_win = target.result.os.tag == .windows;
if (!is_darwin) {
if (std.mem.eql(u8, name, "night-shift") or std.mem.eql(u8, name, "dark-mode")) {
return null;
Expand All @@ -229,6 +230,11 @@ fn makeCompileStep(
exe.linkFramework("SkyLight");
} else if (std.mem.eql(u8, name, "tcp-proxy")) {
exe.linkLibC();
} else if (std.mem.eql(u8, name, "timeout")) {
if (is_win) { // error: TODO windows Sigaction definition
return null;
}
exe.linkLibC();
} else if (std.mem.eql(u8, name, "zigfetch")) {
if (skip_zigfetch) {
return null;
Expand Down
18 changes: 18 additions & 0 deletions docs/content/programs/timeout.org
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#+TITLE: timeout
#+DATE: 2025-01-23T22:28:53+0800
#+LASTMOD: 2025-01-23T22:35:32+0800
#+TYPE: docs
#+DESCRIPTION: Run a command with bounded time

#+begin_example
timeout SECONDS COMMAND [ARG]...
#+end_example

Start a command, and kill it if the specified timeout expires.

The =timeout= command is crucial for:

- Process Control
- Limits execution time of commands
- Prevents resource-consuming tasks from running indefinitely
- Provides automatic process termination
6 changes: 3 additions & 3 deletions docs/content/programs/zigfetch.org
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#+TITLE: zigfetch
#+DATE: 2025-01-01T18:01:47+0800
#+LASTMOD: 2025-01-04T09:46:39+0800
#+LASTMOD: 2025-01-04T17:16:15+0800
#+TYPE: docs
#+DESCRIPTION: Fetch zig packages, utilizing libcurl.

=zigfetch= behaves similarly to =zig fetch=, utilizing the capabilities of libcurl for its functionality.
=zigfetch= behaves similarly to =zig fetch=, but utilizing the capabilities of libcurl for its functionality.

Since the HTTP support within Zig's standard library isn't currently stable, [[https://github.com/ziglang/zig/issues/21792][this proxy issue]] make it even harder, resulting in multiple errors occurring during dependency downloads when building Zig projects.
HTTP support within Zig's standard library isn't currently stable, [[https://github.com/ziglang/zig/issues/21792][this proxy issue]] make it even harder, resulting in multiple errors occurring during dependency downloads when building Zig projects.

{{< figure src="https://fs.liujiacai.net/cdn-img/zigcli/zig-fetch-errors.webp" >}}

Expand Down
66 changes: 66 additions & 0 deletions src/bin/timeout.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//! Run a command with bounded time
//! https://github.com/coreutils/coreutils/blob/v9.6/src/timeout.c

const std = @import("std");
const posix = std.posix;
const Child = std.process.Child;

pub var child: Child = undefined;
pub var spawn_success = false;

pub fn main() !void {
try posix.sigaction(posix.SIG.ALRM, &posix.Sigaction{
.handler = .{
.handler = struct {
pub fn handler(got: c_int) callconv(.C) void {
std.debug.assert(got == posix.SIG.ALRM);
_ = child.kill() catch |e| {
std.log.err("Kill child failed, err:{any}", .{e});
return;
};
posix.exit(124); // timeout
}
}.handler,
},
.mask = posix.empty_sigset,
.flags = 0,
}, null);

var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer if (gpa.deinit() != .ok) @panic("leak");
const allocator = gpa.allocator();

const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);

if (args.len < 3) {
std.debug.print(
\\Usage:
\\ {s} SECONDS COMMAND [ARG]...
\\
, .{args[0]});
posix.exit(1);
}

const ttl_seconds = try std.fmt.parseInt(c_uint, args[1], 10);
const cmds = args[2..];
const ret = std.c.alarm(ttl_seconds);
if (ret != 0) {
std.log.err("Set alarm signal failed, retcode:{d}", .{ret});
posix.exit(1);
}

child = Child.init(cmds, allocator);
try child.spawn();
spawn_success = true;
const term = try child.wait();
switch (term) {
.Exited => |status| {
posix.exit(status);
},
else => {
std.log.err("Child internal error, term:{any}", .{term});
posix.exit(125);
},
}
}
26 changes: 18 additions & 8 deletions src/bin/zigfetch.zig
Original file line number Diff line number Diff line change
Expand Up @@ -365,15 +365,15 @@ fn moveToCache(allocator: Allocator, src_dir: []const u8, hex: Manifest.MultiHas
const dst = try std.fmt.allocPrint(allocator, "{s}/p/{s}", .{ cache_dirname, hex });
defer allocator.free(dst);

_ = fs.openDirAbsolute(dst, .{}) catch |err| switch (err) {
error.FileNotFound => {
return fs.renameAbsolute(src_dir, dst);
},
else => return err,
};
if (args.verbose) {
log.info("Dir({s}) already exists, skip copy...", .{dst});
const found = try checkFileExists(dst);
if (found) {
if (args.verbose) {
log.info("Dir({s}) already exists, skip copy...", .{dst});
}
return;
}

try fs.renameAbsolute(src_dir, dst);
}

fn fetchPackage(allocator: Allocator, url: [:0]const u8, out_dir: fs.Dir) ![]const u8 {
Expand Down Expand Up @@ -921,3 +921,13 @@ fn recursiveDirectoryCopy(allocator: Allocator, dir: fs.Dir, tmp_dir: fs.Dir) an
}
}
}

// Returns true if path exists
fn checkFileExists(path: []const u8) !bool {
fs.cwd().access(path, .{}) catch |e| switch (e) {
error.FileNotFound => return false,
else => return e,
};

return true;
}

0 comments on commit 09c75b3

Please sign in to comment.