authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2022-12-16 20:08:28-08:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2022-12-16 21:42:39-08:00
logb362cbbc9fb4ab09c6a52948476d3d7dff27d795
treeaa08044016c10e62ce20531eb775f023ab68e053
parent6a1021fb7d14604b4f66b2c992f47eadcc812989

ChildProcess.spawnWindows: Drastically reduce the amount of allocation during FileNotFound recovery

Avoid a lot of unnecessary utf8 -> utf16 conversion and use a single ArrayList buffer for all the joined paths instead of a separate allocation for each join

1 files changed, 23 insertions(+), 34 deletions(-)

lib/std/child_process.zig+23-34
......@@ -968,52 +968,41 @@ pub const ChildProcess = struct {
968968 windowsCreateProcess(app_path_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo) catch |no_path_err| {
969969 if (no_path_err != error.FileNotFound) return no_path_err;
970970
971 var free_path = true;
972 const PATH = process.getEnvVarOwned(self.allocator, "PATH") catch |err| switch (err) {
973 error.EnvironmentVariableNotFound => blk: {
974 free_path = false;
975 break :blk "";
976 },
977 else => |e| return e,
978 };
979 defer if (free_path) self.allocator.free(PATH);
971 const PATH: [:0]const u16 = std.os.getenvW(unicode.utf8ToUtf16LeStringLiteral("PATH")) orelse &[_:0]u16{};
972 const PATHEXT: [:0]const u16 = std.os.getenvW(unicode.utf8ToUtf16LeStringLiteral("PATHEXT")) orelse &[_:0]u16{};
980973
981 var free_path_ext = true;
982 const PATHEXT = process.getEnvVarOwned(self.allocator, "PATHEXT") catch |err| switch (err) {
983 error.EnvironmentVariableNotFound => blk: {
984 free_path_ext = false;
985 break :blk "";
986 },
987 else => |e| return e,
988 };
989 defer if (free_path_ext) self.allocator.free(PATHEXT);
974 var path_buf = std.ArrayListUnmanaged(u16){};
975 defer path_buf.deinit(self.allocator);
990976
991977 const app_name = self.argv[0];
978 const app_name_trimmed_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, mem.trimLeft(u8, app_name, "\\/"));
979 defer self.allocator.free(app_name_trimmed_w);
992980
993 var it = mem.tokenize(u8, PATH, ";");
981 var it = mem.tokenize(u16, PATH, &[_]u16{';'});
994982 retry: while (it.next()) |search_path| {
995 const path_no_ext = try fs.path.join(self.allocator, &[_][]const u8{ search_path, app_name });
996 defer self.allocator.free(path_no_ext);
997
998 const path_no_ext_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, path_no_ext);
999 defer self.allocator.free(path_no_ext_w);
1000
1001 if (windowsCreateProcess(path_no_ext_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| {
983 path_buf.clearRetainingCapacity();
984 const search_path_trimmed = mem.trimRight(u16, search_path, &[_]u16{ '\\', '/' });
985 try path_buf.appendSlice(self.allocator, search_path_trimmed);
986 try path_buf.append(self.allocator, fs.path.sep);
987 try path_buf.appendSlice(self.allocator, app_name_trimmed_w);
988 try path_buf.append(self.allocator, 0);
989 const path_no_ext = path_buf.items[0 .. path_buf.items.len - 1 :0];
990
991 if (windowsCreateProcess(path_no_ext.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| {
1002992 break :retry;
1003993 } else |err| switch (err) {
1004994 error.FileNotFound, error.AccessDenied => {},
1005995 else => return err,
1006996 }
1007997
1008 var ext_it = mem.tokenize(u8, PATHEXT, ";");
1009 while (ext_it.next()) |app_ext| {
1010 const ext_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, app_ext);
1011 defer self.allocator.free(ext_w);
1012
1013 const joined_path_w = try std.mem.concatWithSentinel(self.allocator, u16, &.{ path_no_ext_w, ext_w }, 0);
1014 defer self.allocator.free(joined_path_w);
998 var ext_it = mem.tokenize(u16, PATHEXT, &[_]u16{';'});
999 while (ext_it.next()) |ext| {
1000 path_buf.shrinkRetainingCapacity(path_no_ext.len);
1001 try path_buf.appendSlice(self.allocator, ext);
1002 try path_buf.append(self.allocator, 0);
1003 const joined_path = path_buf.items[0 .. path_buf.items.len - 1 :0];
10151004
1016 if (windowsCreateProcess(joined_path_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| {
1005 if (windowsCreateProcess(joined_path.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| {
10171006 break :retry;
10181007 } else |err| switch (err) {
10191008 error.FileNotFound => continue,