Files
bun.sh/src/Global.zig
2025-08-25 02:03:43 +00:00

275 lines
9.2 KiB
Zig

const Global = @This();
extern "c" fn setenv(name: [*:0]const u8, value: [*:0]const u8, overwrite: i32) i32;
/// Does not have the canary tag, because it is exposed in `Bun.version`
/// "1.0.0" or "1.0.0-debug"
pub const package_json_version = if (Environment.isDebug)
version_string ++ "-debug"
else
version_string;
/// This is used for `bun` without any arguments, it `package_json_version` but with canary if it is a canary build.
/// like "1.0.0-canary.12"
pub const package_json_version_with_canary = if (Environment.isDebug)
version_string ++ "-debug"
else if (Environment.is_canary)
std.fmt.comptimePrint("{s}-canary.{d}", .{ version_string, Environment.canary_revision })
else
version_string;
/// The version and a short hash in parenthesis.
pub const package_json_version_with_sha = if (Environment.git_sha.len == 0)
package_json_version
else if (Environment.isDebug)
std.fmt.comptimePrint("{s} ({s})", .{ version_string, Environment.git_sha[0..@min(Environment.git_sha.len, 8)] })
else if (Environment.is_canary)
std.fmt.comptimePrint("{s}-canary.{d} ({s})", .{ version_string, Environment.canary_revision, Environment.git_sha[0..@min(Environment.git_sha.len, 8)] })
else
std.fmt.comptimePrint("{s} ({s})", .{ version_string, Environment.git_sha[0..@min(Environment.git_sha.len, 8)] });
/// What is printed by `bun --revision`
/// "1.0.0+abcdefghi" or "1.0.0-canary.12+abcdefghi"
pub const package_json_version_with_revision = if (Environment.git_sha.len == 0)
package_json_version
else if (Environment.isDebug)
std.fmt.comptimePrint(version_string ++ "-debug+{s}", .{Environment.git_sha_short})
else if (Environment.is_canary)
std.fmt.comptimePrint(version_string ++ "-canary.{d}+{s}", .{ Environment.canary_revision, Environment.git_sha_short })
else
std.fmt.comptimePrint(version_string ++ "+{s}", .{Environment.git_sha_short});
pub const os_name = Environment.os.nameString();
// Bun v1.0.0 (Linux x64 baseline)
// Bun v1.0.0-debug (Linux x64)
// Bun v1.0.0-canary.0+44e09bb7f (Linux x64)
pub const unhandled_error_bun_version_string = "Bun v" ++
(if (Environment.is_canary) package_json_version_with_revision else package_json_version) ++
" (" ++ Environment.os.displayString() ++ " " ++ arch_name ++
(if (Environment.baseline) " baseline)" else ")");
pub const arch_name = if (Environment.isX64)
"x64"
else if (Environment.isX86)
"x86"
else if (Environment.isAarch64)
"arm64"
else
"unknown";
pub inline fn getStartTime() i128 {
return bun.start_time;
}
extern "kernel32" fn SetThreadDescription(thread: std.os.windows.HANDLE, name: [*:0]const u16) callconv(std.os.windows.WINAPI) std.os.windows.HRESULT;
pub fn setThreadName(name: [:0]const u8) void {
if (Environment.isLinux) {
_ = std.posix.prctl(.SET_NAME, .{@intFromPtr(name.ptr)}) catch 0;
} else if (Environment.isMac) {
_ = std.c.pthread_setname_np(name);
} else if (Environment.isWindows) {
// TODO: use SetThreadDescription or NtSetInformationThread with 0x26 (ThreadNameInformation)
// without causing exit code 0xC0000409 (stack buffer overrun) in child process
}
}
const ExitFn = *const fn () callconv(.C) void;
var on_exit_callbacks = std.ArrayListUnmanaged(ExitFn){};
export fn Bun__atexit(function: ExitFn) void {
if (std.mem.indexOfScalar(ExitFn, on_exit_callbacks.items, function) == null) {
on_exit_callbacks.append(bun.default_allocator, function) catch {};
}
}
pub fn addExitCallback(function: ExitFn) void {
Bun__atexit(function);
}
pub fn runExitCallbacks() void {
for (on_exit_callbacks.items) |callback| {
callback();
}
on_exit_callbacks.items.len = 0;
}
var is_exiting = std.atomic.Value(bool).init(false);
export fn bun_is_exiting() c_int {
return @intFromBool(isExiting());
}
pub fn isExiting() bool {
return is_exiting.load(.monotonic);
}
/// Flushes stdout and stderr (in exit/quick_exit callback) and exits with the given code.
pub fn exit(code: u32) noreturn {
is_exiting.store(true, .monotonic);
_ = @atomicRmw(usize, &bun.analytics.Features.exited, .Add, 1, .monotonic);
// If we are crashing, allow the crash handler to finish it's work.
bun.crash_handler.sleepForeverIfAnotherThreadIsCrashing();
// Check restart policy for JavaScript files
const cli_ctx = bun.cli.Command.get();
const restart_policy = cli_ctx.runtime_options.restart_policy;
// Determine if we should restart based on the policy and exit code
const should_restart = switch (restart_policy) {
.no => false,
.on_failure => code != 0,
.always => true,
.unless_stopped => code != 0,
};
if (should_restart) {
// Track restart count for logging purposes
const restart_count_env = bun.getenvZ("BUN_RESTART_COUNT") orelse "0";
const restart_count = std.fmt.parseInt(u32, restart_count_env, 10) catch 0;
// Set environment variable for next restart
var restart_count_buf: [16]u8 = undefined;
const new_count_str = std.fmt.bufPrint(&restart_count_buf, "{d}", .{restart_count + 1}) catch "0";
// Create null-terminated string for setenv
var value_buf: [32]u8 = undefined;
if (std.fmt.bufPrintZ(&value_buf, "{s}", .{new_count_str})) |value_z| {
if (setenv("BUN_RESTART_COUNT", value_z.ptr, 1) == 0) {
// Show restart message (similar to Docker)
if (restart_count == 0) {
bun.Output.prettyln("<d>Process restarting due to restart policy: {s}<r>", .{@tagName(restart_policy)});
} else if (restart_count <= 5 or restart_count % 10 == 0) {
bun.Output.prettyln("<d>Process restarting (attempt {d})...<r>", .{restart_count + 1});
}
bun.Output.flush();
// Use bun.reloadProcess to restart the process
bun.reloadProcess(bun.default_allocator, false, false);
// If reloadProcess returned (failure case), continue with normal exit
}
// If setenv failed, continue with normal exit
} else |_| {
// Failed to format value, continue with normal exit
}
}
if (Environment.isDebug) {
bun.assert(bun.debug_allocator_data.backing.?.deinit() == .ok);
bun.debug_allocator_data.backing = null;
}
switch (Environment.os) {
.mac => std.c.exit(@bitCast(code)),
.windows => {
Bun__onExit();
std.os.windows.kernel32.ExitProcess(code);
},
else => {
bun.c.quick_exit(@bitCast(code));
std.c.abort(); // quick_exit should be noreturn
},
}
}
pub fn raiseIgnoringPanicHandler(sig: bun.SignalCode) noreturn {
Output.flush();
Output.Source.Stdio.restore();
// clear segfault handler
bun.crash_handler.resetSegfaultHandler();
// clear signal handler
if (bun.Environment.os != .windows) {
var sa: std.c.Sigaction = .{
.handler = .{ .handler = std.posix.SIG.DFL },
.mask = std.posix.empty_sigset,
.flags = std.posix.SA.RESETHAND,
};
_ = std.c.sigaction(@intFromEnum(sig), &sa, null);
}
// kill self
_ = std.c.raise(@intFromEnum(sig));
std.c.abort();
}
pub const AllocatorConfiguration = struct {
verbose: bool = false,
long_running: bool = false,
};
pub inline fn mimalloc_cleanup(force: bool) void {
if (comptime use_mimalloc) {
Mimalloc.mi_collect(force);
}
}
pub const versions = @import("./generated_versions_list.zig");
// Enabling huge pages slows down bun by 8x or so
// Keeping this code for:
// 1. documentation that an attempt was made
// 2. if I want to configure allocator later
pub inline fn configureAllocator(_: AllocatorConfiguration) void {}
pub fn notimpl() noreturn {
@branchHint(.cold);
Output.panic("Not implemented yet!!!!!", .{});
}
// Make sure we always print any leftover
pub fn crash() noreturn {
@branchHint(.cold);
Global.exit(1);
}
pub const BunInfo = struct {
bun_version: string,
platform: analytics.GenerateHeader.GeneratePlatform.Platform,
const analytics = bun.analytics;
const JSON = bun.json;
const JSAst = bun.ast;
pub fn generate(comptime Bundler: type, _: Bundler, allocator: std.mem.Allocator) !JSAst.Expr {
const info = BunInfo{
.bun_version = Global.package_json_version,
.platform = analytics.GenerateHeader.GeneratePlatform.forOS(),
};
return try JSON.toAST(allocator, BunInfo, info);
}
};
pub const user_agent = "Bun/" ++ Global.package_json_version;
pub export const Bun__userAgent: [*:0]const u8 = Global.user_agent;
comptime {
_ = Bun__userAgent;
}
pub export fn Bun__onExit() void {
bun.jsc.Node.FSEvents.closeAndWait();
runExitCallbacks();
Output.flush();
std.mem.doNotOptimizeAway(&Bun__atexit);
Output.Source.Stdio.restore();
}
comptime {
_ = Bun__onExit;
}
const string = []const u8;
const Output = @import("./output.zig");
const std = @import("std");
const Environment = @import("./env.zig");
const version_string = Environment.version_string;
const bun = @import("bun");
const Mimalloc = bun.mimalloc;
const use_mimalloc = bun.use_mimalloc;