├── .gitignore ├── README ├── build.zig ├── build.zig.zon └── src └── main.zig /.gitignore: -------------------------------------------------------------------------------- 1 | zig-cache/ 2 | zig-out/ 3 | /release/ 4 | /debug/ 5 | /build/ 6 | /build-*/ 7 | /docgen_tmp/ 8 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Zig Shared Memory Example 2 | -------------------------- 3 | 4 | A simple example of how to use shared memory in Zig. 5 | 6 | You can find the related Youtube video here: https://youtu.be/QEGihu2Z9pE 7 | 8 | Built for Version-0.12.0-dev.3158+1e67f5021 9 | -------------------------------------------------------------------------------- /build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | // Although this function looks imperative, note that its job is to 4 | // declaratively construct a build graph that will be executed by an external 5 | // runner. 6 | pub fn build(b: *std.Build) void { 7 | // Standard target options allows the person running `zig build` to choose 8 | // what target to build for. Here we do not override the defaults, which 9 | // means any target is allowed, and the default is native. Other options 10 | // for restricting supported target set are available. 11 | const target = b.standardTargetOptions(.{}); 12 | 13 | // Standard optimization options allow the person running `zig build` to select 14 | // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not 15 | // set a preferred release mode, allowing the user to decide how to optimize. 16 | const optimize = b.standardOptimizeOption(.{}); 17 | 18 | const exe = b.addExecutable(.{ 19 | .name = "zig-shm", 20 | .root_source_file = .{ .path = "src/main.zig" }, 21 | .target = target, 22 | .optimize = optimize, 23 | }); 24 | 25 | // This declares intent for the executable to be installed into the 26 | // standard location when the user invokes the "install" step (the default 27 | // step when running `zig build`). 28 | b.installArtifact(exe); 29 | 30 | // This *creates* a Run step in the build graph, to be executed when another 31 | // step is evaluated that depends on it. The next line below will establish 32 | // such a dependency. 33 | const run_cmd = b.addRunArtifact(exe); 34 | 35 | // By making the run step depend on the install step, it will be run from the 36 | // installation directory rather than directly from within the cache directory. 37 | // This is not necessary, however, if the application depends on other installed 38 | // files, this ensures they will be present and in the expected location. 39 | run_cmd.step.dependOn(b.getInstallStep()); 40 | 41 | // This allows the user to pass arguments to the application in the build 42 | // command itself, like this: `zig build run -- arg1 arg2 etc` 43 | if (b.args) |args| { 44 | run_cmd.addArgs(args); 45 | } 46 | 47 | // This creates a build step. It will be visible in the `zig build --help` menu, 48 | // and can be selected like this: `zig build run` 49 | // This will evaluate the `run` step rather than the default, which is "install". 50 | const run_step = b.step("run", "Run the app"); 51 | run_step.dependOn(&run_cmd.step); 52 | 53 | const exe_unit_tests = b.addTest(.{ 54 | .root_source_file = .{ .path = "src/main.zig" }, 55 | .target = target, 56 | .optimize = optimize, 57 | }); 58 | 59 | const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); 60 | 61 | // Similar to creating the run step earlier, this exposes a `test` step to 62 | // the `zig build --help` menu, providing a way for the user to request 63 | // running the unit tests. 64 | const test_step = b.step("test", "Run unit tests"); 65 | test_step.dependOn(&run_exe_unit_tests.step); 66 | } 67 | -------------------------------------------------------------------------------- /build.zig.zon: -------------------------------------------------------------------------------- 1 | .{ 2 | .name = "zig-shm", 3 | .version = "0.0.0", 4 | .minimum_zig_version = "0.12.0-dev.3158+1e67f5021", 5 | 6 | .dependencies = .{}, 7 | 8 | .paths = .{ 9 | "", 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /src/main.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const os = std.os; 3 | const fs = std.fs; 4 | const mem = std.mem; 5 | const c = std.c; 6 | 7 | // Without Libc - Musl c port 8 | // fn shmOpen(name: [:0]const u8, comptime flag: comptime_int, mode: c.mode_t) !usize { 9 | // const builtin = @import("builtin"); 10 | // 11 | // if (builtin.os.tag != .linux) { 12 | // return error.Unimplemented; 13 | // } 14 | // 15 | // if (mem.containsAtLeast(u8, name, 1, "/") and (name.len <= 2 and name[0] == '.' and name[name.len - 1] == '.')) { 16 | // return error.OperationNotSupported; 17 | // } 18 | // if (name.len > fs.MAX_NAME_BYTES) { 19 | // return error.NameTooLong; 20 | // } 21 | // 22 | // var buf: [fs.MAX_NAME_BYTES + 10:0]u8 = undefined; 23 | // @memcpy(buf[0..9], "/dev/shm/"); 24 | // @memcpy(buf[9..][0..name.len], name); 25 | // 26 | // const rc = os.linux.open(&buf, flag | os.O.NOFOLLOW | os.O.CLOEXEC | os.O.NONBLOCK, mode); 27 | // if (rc < 0) { 28 | // return switch (c.getErrno(rc)) { 29 | // .ACCES => error.PermissionDenied, 30 | // .EXIST => error.ObjectAlreadyExists, 31 | // // ... 32 | // else => unreachable, 33 | // }; 34 | // } 35 | // 36 | // return rc; 37 | // } 38 | 39 | // Using Libc 40 | // fn shmOpen(name: [*:0]const u8, flag: c_int, mode: c.mode_t) !c_int { 41 | // const rc = c.shm_open(name, flag, mode); 42 | // if (rc < 0) { 43 | // return switch (c.getErrno(rc)) { 44 | // .ACCES => error.PermissionDenied, 45 | // .EXIST => error.ObjectAlreadyExists, 46 | // // .. 47 | // else => unreachable, 48 | // }; 49 | // } 50 | // 51 | // return rc; 52 | // } 53 | 54 | pub fn main() !void { 55 | const stdout = std.io.getStdOut().writer(); 56 | 57 | const numbers = [_]u32{ 43, 23, 53, 82, 24, 92, 204, 18, 230, 200 }; 58 | 59 | const raw_data = try os.mmap(null, @sizeOf(u32) * numbers.len, os.PROT.READ | os.PROT.WRITE, .{ .TYPE = .SHARED, .ANONYMOUS = true }, -1, 0); 60 | defer os.munmap(raw_data); 61 | 62 | // Or - if we need persistence 63 | // --- 64 | // const fd = c.shm_open("/numbers", os.O.CREAT | os.O.RDWR, 0o666); 65 | // if (fd == -1) { 66 | // return error.shm_open_error; 67 | // } 68 | // --- Or - we can build our own wrappers 69 | // const fd = try shmOpen("/numbers", os.O.CREAT | os.O.RDWR, 0o666); 70 | // --- 71 | // defer _ = c.shm_unlink("/numbers"); 72 | // if (c.ftruncate(@intCast(fd), @sizeOf(u32) * numbers.len) == -1) { 73 | // return error.ftruncate_error; 74 | // } 75 | // const raw_data = try os.mmap(null, @sizeOf(u32) * numbers.len, os.PROT.READ | os.PROT.WRITE, os.MAP.SHARED, @intCast(fd), 0); 76 | // defer os.munmap(data); 77 | 78 | const data: *[numbers.len]u32 = @ptrCast(raw_data); 79 | data.* = numbers; 80 | 81 | try stdout.print("[INFO] Unsorted numbers array:\n", .{}); 82 | for (data) |num| { 83 | try stdout.print("- {d}\n", .{num}); 84 | } 85 | 86 | const pid = try os.fork(); 87 | 88 | if (pid == 0) { 89 | // Child 90 | mem.sort(u32, data, {}, std.sort.asc(u32)); 91 | os.exit(0); 92 | } else { 93 | // Parent 94 | // Wait for child to finish executing 95 | const result = os.waitpid(pid, 0); 96 | if (result.status != 0) { 97 | return error.ChildError; 98 | } 99 | 100 | try stdout.print("[INFO] Sorted numbers array:\n", .{}); 101 | for (data) |num| { 102 | try stdout.print("- {d}\n", .{num}); 103 | } 104 | } 105 | } 106 | --------------------------------------------------------------------------------