commit 2014cf19d8a8510e45cbf7f46a6c529003203ae7
parent 79d0f6184ef00ba6daa7bc6e30b046e36af4ae4c
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 14 Apr 2024 11:05:52 +0200
os: add shared memory support
Adds os::shm_open and os::shm_link for all platforms, as well as memfd
support for Linux and FreeBSD.
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
18 files changed, 353 insertions(+), 9 deletions(-)
diff --git a/makefiles/freebsd.aarch64.mk b/makefiles/freebsd.aarch64.mk
@@ -129,7 +129,7 @@ $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACH
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha)
-os_ha = os/+freebsd/dirfdfs.ha os/+freebsd/exit.ha os/+freebsd/fs.ha os/+freebsd/platform_environ.ha os/+freebsd/status.ha os/+freebsd/stdfd.ha os/environ.ha os/os.ha
+os_ha = os/+freebsd/dirfdfs.ha os/+freebsd/exit.ha os/+freebsd/fs.ha os/+freebsd/memfd.ha os/+freebsd/platform_environ.ha os/+freebsd/shm.ha os/+freebsd/status.ha os/+freebsd/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/freebsd.riscv64.mk b/makefiles/freebsd.riscv64.mk
@@ -129,7 +129,7 @@ $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACH
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha)
-os_ha = os/+freebsd/dirfdfs.ha os/+freebsd/exit.ha os/+freebsd/fs.ha os/+freebsd/platform_environ.ha os/+freebsd/status.ha os/+freebsd/stdfd.ha os/environ.ha os/os.ha
+os_ha = os/+freebsd/dirfdfs.ha os/+freebsd/exit.ha os/+freebsd/fs.ha os/+freebsd/memfd.ha os/+freebsd/platform_environ.ha os/+freebsd/shm.ha os/+freebsd/status.ha os/+freebsd/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/freebsd.x86_64.mk b/makefiles/freebsd.x86_64.mk
@@ -129,7 +129,7 @@ $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACH
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha)
-os_ha = os/+freebsd/dirfdfs.ha os/+freebsd/exit.ha os/+freebsd/fs.ha os/+freebsd/platform_environ.ha os/+freebsd/status.ha os/+freebsd/stdfd.ha os/environ.ha os/os.ha
+os_ha = os/+freebsd/dirfdfs.ha os/+freebsd/exit.ha os/+freebsd/fs.ha os/+freebsd/memfd.ha os/+freebsd/platform_environ.ha os/+freebsd/shm.ha os/+freebsd/status.ha os/+freebsd/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/linux.aarch64.mk b/makefiles/linux.aarch64.mk
@@ -147,7 +147,7 @@ $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha)
-os_ha = os/+linux/dirfdfs.ha os/+linux/exit.ha os/+linux/fs.ha os/+linux/memory.ha os/+linux/platform_environ.ha os/+linux/status.ha os/+linux/stdfd.ha os/environ.ha os/os.ha
+os_ha = os/+linux/dirfdfs.ha os/+linux/exit.ha os/+linux/fs.ha os/+linux/memfd.ha os/+linux/memory.ha os/+linux/platform_environ.ha os/+linux/shm.ha os/+linux/status.ha os/+linux/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/linux.riscv64.mk b/makefiles/linux.riscv64.mk
@@ -147,7 +147,7 @@ $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha)
-os_ha = os/+linux/dirfdfs.ha os/+linux/exit.ha os/+linux/fs.ha os/+linux/memory.ha os/+linux/platform_environ.ha os/+linux/status.ha os/+linux/stdfd.ha os/environ.ha os/os.ha
+os_ha = os/+linux/dirfdfs.ha os/+linux/exit.ha os/+linux/fs.ha os/+linux/memfd.ha os/+linux/memory.ha os/+linux/platform_environ.ha os/+linux/shm.ha os/+linux/status.ha os/+linux/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/linux.x86_64.mk b/makefiles/linux.x86_64.mk
@@ -147,7 +147,7 @@ $(HARECACHE)/fs.ssa: $(fs_ha) $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/fs.td.tmp -N fs $(fs_ha)
-os_ha = os/+linux/dirfdfs.ha os/+linux/exit.ha os/+linux/fs.ha os/+linux/memory.ha os/+linux/platform_environ.ha os/+linux/status.ha os/+linux/stdfd.ha os/environ.ha os/os.ha
+os_ha = os/+linux/dirfdfs.ha os/+linux/exit.ha os/+linux/fs.ha os/+linux/memfd.ha os/+linux/memory.ha os/+linux/platform_environ.ha os/+linux/shm.ha os/+linux/status.ha os/+linux/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/openbsd.aarch64.mk b/makefiles/openbsd.aarch64.mk
@@ -129,7 +129,7 @@ $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACH
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha)
-os_ha = os/+openbsd/dirfdfs.ha os/+openbsd/exit.ha os/+openbsd/fs.ha os/+openbsd/platform_environ.ha os/+openbsd/status.ha os/+openbsd/stdfd.ha os/environ.ha os/os.ha
+os_ha = os/+openbsd/dirfdfs.ha os/+openbsd/exit.ha os/+openbsd/fs.ha os/+openbsd/platform_environ.ha os/+openbsd/shm.ha os/+openbsd/status.ha os/+openbsd/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/openbsd.riscv64.mk b/makefiles/openbsd.riscv64.mk
@@ -129,7 +129,7 @@ $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACH
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha)
-os_ha = os/+openbsd/dirfdfs.ha os/+openbsd/exit.ha os/+openbsd/fs.ha os/+openbsd/platform_environ.ha os/+openbsd/status.ha os/+openbsd/stdfd.ha os/environ.ha os/os.ha
+os_ha = os/+openbsd/dirfdfs.ha os/+openbsd/exit.ha os/+openbsd/fs.ha os/+openbsd/platform_environ.ha os/+openbsd/shm.ha os/+openbsd/status.ha os/+openbsd/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/makefiles/openbsd.x86_64.mk b/makefiles/openbsd.x86_64.mk
@@ -129,7 +129,7 @@ $(HARECACHE)/types_c.ssa: $(types_c_ha) $(HARECACHE)/encoding_utf8.td $(HARECACH
@printf 'HAREC\t%s\n' "$@"
@$(TDENV) $(HAREC) $(HARECFLAGS) -o $@ -t $(HARECACHE)/types_c.td.tmp -N types::c $(types_c_ha)
-os_ha = os/+openbsd/dirfdfs.ha os/+openbsd/exit.ha os/+openbsd/fs.ha os/+openbsd/platform_environ.ha os/+openbsd/status.ha os/+openbsd/stdfd.ha os/environ.ha os/os.ha
+os_ha = os/+openbsd/dirfdfs.ha os/+openbsd/exit.ha os/+openbsd/fs.ha os/+openbsd/platform_environ.ha os/+openbsd/shm.ha os/+openbsd/status.ha os/+openbsd/stdfd.ha os/environ.ha os/os.ha
$(HARECACHE)/os.ssa: $(os_ha) $(HARECACHE)/bufio.td $(HARECACHE)/encoding_utf8.td $(HARECACHE)/errors.td $(HARECACHE)/fs.td $(HARECACHE)/io.td $(HARECACHE)/math.td $(HARECACHE)/path.td $(HARECACHE)/rt.td $(HARECACHE)/strings.td $(HARECACHE)/time.td $(HARECACHE)/types_c.td
@mkdir -p -- "$(HARECACHE)"
@printf 'HAREC\t%s\n' "$@"
diff --git a/os/+freebsd/memfd.ha b/os/+freebsd/memfd.ha
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: MPL-2.0
+// (c) Hare authors <https://harelang.org>
+
+use errors;
+use io;
+use rt;
+
+// Flags for [[memfd]].
+export type memfd_flag = enum uint {
+ NONE = 0,
+ // Unsets the close-on-exec flag when creating a memfd.
+ NOCLOEXEC = 1,
+ // ALlows sealing operations on this file.
+ ALLOW_SEALING = 2,
+};
+
+// Creates a new anonyomous [[io::file]] backed by memory.
+//
+// The initial file size is zero. It can be written to normally, or the size can
+// be set manually with [[trunc]].
+//
+// This function is available on Linux and FreeBSD.
+export fn memfd(
+ name: str,
+ flags: memfd_flag = memfd_flag::NONE,
+) (io::file | errors::error) = {
+ let oflag = rt::O_RDWR | rt::O_CLOEXEC;
+ let shm_flag = rt::SHM_GROW_ON_WRITE;
+ if (flags & memfd_flag::NOCLOEXEC != 0) {
+ oflag &= ~rt::O_CLOEXEC;
+ };
+ if (flags & memfd_flag::ALLOW_SEALING != 0) {
+ shm_flag |= rt::SHM_ALLOW_SEALING;
+ };
+
+ match (rt::shm_open(rt::SHM_ANON, oflag, 0, shm_flag, name)) {
+ case let fd: int =>
+ return fd: io::file;
+ case let err: rt::errno =>
+ return errors::errno(err);
+ };
+};
diff --git a/os/+freebsd/shm.ha b/os/+freebsd/shm.ha
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: MPL-2.0
+// (c) Hare authors <https://harelang.org>
+
+use errors;
+use fs;
+use io;
+use path;
+use rt;
+use strings;
+
+fn shm_path(name: str) (str | fs::error) = {
+ const name = strings::ltrim(name, '/');
+ if (len(name) > rt::NAME_MAX) {
+ return errors::invalid;
+ };
+ if (name == "." || name == "..") {
+ return errors::invalid;
+ };
+ static let buf = path::buffer { ... };
+ path::set(&buf, "/", name)!;
+ return path::string(&buf);
+};
+
+// Opens (or creates, given [[fs::flag::CREATE]]) a global shared memory file
+// with the given name, suitable for use with [[io::mmap]] to establish shared
+// memory areas with other processes using the same name.
+//
+// The name must not contain any forward slashes (one is permissible at the
+// start, e.g. "/example") and cannot be "." or "..".
+//
+// The "oflag" parameter, if provided, must include either [[fs::flag::RDONLY]]
+// or [[fs::flag::RDWR]], and may optionally add [[fs::flag::CREATE]],
+// [[fs::flag::EXCL]], and/or [[fs::flag::TRUNC]], which are supported on all
+// POSIX-compatible platforms. Other platforms may support additional
+// non-standard flags; consult the shm_open(3) manual for your target system for
+// details.
+//
+// The new file descriptor always has CLOEXEC set regardless of the provided
+// flags. If creating a new shared memory object, set its initial size with
+// [[io::trunc]] before mapping it with [[io::mmap]].
+//
+// Call [[shm_unlink]] to remove the global shared memory object.
+export fn shm_open(
+ name: str,
+ oflag: fs::flag = fs::flag::CREATE | fs::flag::RDWR,
+ mode: fs::mode = 0o600,
+) (io::file | fs::error) = {
+ const path = shm_path(name)?;
+ def VALID_FLAGS: int = rt::O_RDWR | rt::O_CREAT | rt::O_EXCL | rt::O_TRUNC;
+ const oflag = (fsflags_to_bsd(oflag)? & VALID_FLAGS) | rt::O_CLOEXEC;
+
+ match (rt::shm_open(path, oflag, mode: rt::mode_t, 0, null: *const u8)) {
+ case let fd: int =>
+ return fd: io::file;
+ case let err: rt::errno =>
+ return errors::errno(err): fs::error;
+ };
+};
+
+// Removes the shared memory object with the given name. Processes which already
+// hold a reference to the file may continue to use the memory associated with
+// it. Once all processes have unmapped the associated shared memory object, or
+// exited, the memory is released.
+export fn shm_unlink(name: str) (void | fs::error) = {
+ const path = shm_path(name)?;
+ match (rt::shm_unlink(path)) {
+ case let err: rt::errno =>
+ return errors::errno(err): fs::error;
+ case void =>
+ return;
+ };
+};
diff --git a/os/+linux/memfd.ha b/os/+linux/memfd.ha
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: MPL-2.0
+// (c) Hare authors <https://harelang.org>
+
+use errors;
+use io;
+use rt;
+
+// Flags for [[memfd]].
+export type memfd_flag = enum uint {
+ NONE = 0,
+ // Unsets the close-on-exec flag when creating a memfd.
+ NOCLOEXEC = rt::MFD_CLOEXEC,
+ // ALlows sealing operations on this file.
+ ALLOW_SEALING = rt::MFD_ALLOW_SEALING,
+ // Create the memfd with huge pages using hugetlbfs. Linux-only.
+ HUGETLB = rt::MFD_HUGETLB,
+};
+
+// Creates a new anonyomous [[io::file]] backed by memory.
+//
+// The initial file size is zero. It can be written to normally, or the size can
+// be set manually with [[trunc]].
+//
+// This function is available on Linux and FreeBSD.
+export fn memfd(
+ name: str,
+ flags: memfd_flag = memfd_flag::NONE,
+) (io::file | errors::error) = {
+ flags ^= memfd_flag::NOCLOEXEC;
+ match (rt::memfd_create(name, flags: uint)) {
+ case let i: int =>
+ return i: io::file;
+ case let err: rt::errno =>
+ return errors::errno(err);
+ };
+};
diff --git a/os/+linux/shm.ha b/os/+linux/shm.ha
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: MPL-2.0
+// (c) Hare authors <https://harelang.org>
+
+use errors;
+use fs;
+use io;
+use path;
+use rt;
+use strings;
+
+def SHM_PATH: str = "/dev/shm/";
+
+fn shm_path(name: str) (str | fs::error) = {
+ const name = strings::ltrim(name, '/');
+ if (len(name) > rt::NAME_MAX) {
+ return errors::invalid;
+ };
+ if (name == "." || name == "..") {
+ return errors::invalid;
+ };
+ static let buf = path::buffer { ... };
+ path::set(&buf, SHM_PATH, name)!;
+ return path::string(&buf);
+};
+
+// Opens (or creates, given [[fs::flag::CREATE]]) a global shared memory file
+// with the given name, suitable for use with [[io::mmap]] to establish shared
+// memory areas with other processes using the same name.
+//
+// The name must not contain any forward slashes (one is permissible at the
+// start, e.g. "/example") and cannot be "." or "..".
+//
+// The "oflag" parameter, if provided, must include either [[fs::flag::RDONLY]]
+// or [[fs::flag::RDWR]], and may optionally add [[fs::flag::CREATE]],
+// [[fs::flag::EXCL]], and/or [[fs::flag::TRUNC]], other flags are silently
+// ignored if set.
+//
+// The new file descriptor always has CLOEXEC set regardless of the provided
+// flags. If creating a new shared memory object, set its initial size with
+// [[io::trunc]] before mapping it with [[io::mmap]].
+//
+// Call [[shm_unlink]] to remove the global shared memory object.
+export fn shm_open(
+ name: str,
+ oflag: fs::flag = fs::flag::CREATE | fs::flag::RDWR,
+ mode: fs::mode = 0o600,
+) (io::file | fs::error) = {
+ const path = shm_path(name)?;
+ oflag |= fs::flag::NOFOLLOW | fs::flag::NONBLOCK;
+ oflag &= ~fs::flag::NOCLOEXEC; // Unconditionally set CLOEXEC
+ return create(path, mode, oflag);
+};
+
+// Removes the shared memory object with the given name. Processes which already
+// hold a reference to the file may continue to use the memory associated with
+// it. Once all processes have unmapped the associated shared memory object, or
+// exited, the memory is released.
+export fn shm_unlink(name: str) (void | fs::error) = {
+ return remove(shm_path(name)?);
+};
diff --git a/os/+openbsd/shm.ha b/os/+openbsd/shm.ha
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: MPL-2.0
+// (c) Hare authors <https://harelang.org>
+
+use errors;
+use fs;
+use io;
+use path;
+use rt;
+use strings;
+
+fn shm_path(name: str) (str | fs::error) = {
+ const name = strings::ltrim(name, '/');
+ if (len(name) > rt::NAME_MAX) {
+ return errors::invalid;
+ };
+ if (name == "." || name == "..") {
+ return errors::invalid;
+ };
+ static let buf = path::buffer { ... };
+ path::set(&buf, "/", name)!;
+ return path::string(&buf);
+};
+
+// Opens (or creates, given [[fs::flag::CREATE]]) a global shared memory file
+// with the given name, suitable for use with [[io::mmap]] to establish shared
+// memory areas with other processes using the same name.
+//
+// The name must not contain any forward slashes (one is permissible at the
+// start, e.g. "/example") and cannot be "." or "..".
+//
+// The "oflag" parameter, if provided, must include either [[fs::flag::RDONLY]]
+// or [[fs::flag::RDWR]], and may optionally add [[fs::flag::CREATE]],
+// [[fs::flag::EXCL]], and/or [[fs::flag::TRUNC]], other flags are silently
+// ignored if set.
+//
+// The new file descriptor always has CLOEXEC set regardless of the provided
+// flags. If creating a new shared memory object, set its initial size with
+// [[io::trunc]] before mapping it with [[io::mmap]].
+//
+// Call [[shm_unlink]] to remove the global shared memory object.
+export fn shm_open(
+ name: str,
+ oflag: fs::flag = fs::flag::CREATE | fs::flag::RDWR,
+ mode: fs::mode = 0o600,
+) (io::file | fs::error) = {
+ const path = shm_path(name)?;
+ def VALID_FLAGS: int = rt::O_RDWR | rt::O_CREAT | rt::O_EXCL | rt::O_TRUNC;
+ const oflag = (fsflags_to_bsd(oflag)? & VALID_FLAGS) | rt::O_CLOEXEC;
+
+ match (rt::shm_open(path, oflag, mode: rt::mode_t)) {
+ case let fd: int =>
+ return fd: io::file;
+ case let err: rt::errno =>
+ return errors::errno(err): fs::error;
+ };
+};
+
+// Removes the shared memory object with the given name. Processes which already
+// hold a reference to the file may continue to use the memory associated with
+// it. Once all processes have unmapped the associated shared memory object, or
+// exited, the memory is released.
+export fn shm_unlink(name: str) (void | fs::error) = {
+ const path = shm_path(name)?;
+ match (rt::shm_unlink(path)) {
+ case let err: rt::errno =>
+ return errors::errno(err): fs::error;
+ case void =>
+ return;
+ };
+};
diff --git a/rt/+freebsd/syscalls.ha b/rt/+freebsd/syscalls.ha
@@ -22,6 +22,7 @@ fn syscall4(u64, u64, u64, u64, u64) u64;
fn syscall5(u64, u64, u64, u64, u64, u64) u64;
fn syscall6(u64, u64, u64, u64, u64, u64, u64) u64;
+export def NAME_MAX: size = 255z;
export def PATH_MAX: size = 1024z;
export type path = (str | []u8 | *const u8);
let pathbuf: [PATH_MAX]u8 = [0...];
@@ -579,6 +580,34 @@ export fn flock(fd: int, op: int) (void | errno) = {
fd: u64, op: u64))?;
};
+export fn shm_open(
+ shm_path: path,
+ oflags: int,
+ mode: mode_t,
+ shmflags: int,
+ anon_path: path,
+) (int | errno) = {
+ const shm_path = match (shm_path) {
+ case let string: *const u8 =>
+ if (string == SHM_ANON) yield SHM_ANON;
+ yield kpath(shm_path)?;
+ case =>
+ yield kpath(shm_path)?;
+ };
+ const anon_path = kpath(anon_path)?;
+ return wrap_return(syscall5(SYS_shm_open2,
+ shm_path: uintptr: u64,
+ oflags: u64,
+ mode: u64,
+ shmflags: u64,
+ anon_path: uintptr: u64))?: int;
+};
+
+export fn shm_unlink(shm_path: path) (void | errno) = {
+ const path = kpath(shm_path)?;
+ wrap_return(syscall1(SYS_shm_unlink, path: uintptr: u64))?;
+};
+
export fn shmat(id: int, addr: *const opaque, flag: int) *opaque = {
return syscall3(SYS_shmat, id: u64, addr: uintptr: u64,
flag: u64): uintptr: *opaque;
diff --git a/rt/+freebsd/types.ha b/rt/+freebsd/types.ha
@@ -488,3 +488,13 @@ export def RLIMIT_UMTXP: int = 14;
export def SHUT_RD: int = 0;
export def SHUT_WR: int = 1;
export def SHUT_RDWR: int = 2;
+
+export let SHM_ANON: *const u8 = 1: uintptr: *const u8;
+
+export def SHM_ALLOW_SEALING: int = 0x00000001;
+export def SHM_GROW_ON_WRITE: int = 0x00000002;
+export def SHM_LARGEPAGE: int = 0x00000004;
+
+export def SHM_LARGEPAGE_ALLOC_DEFAULT: int = 0;
+export def SHM_LARGEPAGE_ALLOC_NOWAIT: int = 1;
+export def SHM_LARGEPAGE_ALLOC_HARD: int = 2;
diff --git a/rt/+openbsd/syscalls.ha b/rt/+openbsd/syscalls.ha
@@ -1240,6 +1240,29 @@ export fn getpgid(pid: pid_t) (pid_t | errno) = {
// issetugid
// lchown
+// shm_open
+
+@symbol("shm_open") fn libc_shm_open(path: *const u8, flags: int, mode: mode_t) int;
+
+export fn shm_open(path: path, flags: int, mode: mode_t) (int | errno) = {
+ let res = libc_shm_open(cpath(path)?, flags, mode);
+ if (res == -1) {
+ return *__errno(): errno;
+ };
+ return res;
+};
+
+// shm_unlink
+
+@symbol("shm_unlink") fn libc_shm_unlink(path: *const u8) int;
+
+export fn shm_unlink(path: path) (void | errno) = {
+ let res = libc_shm_unlink(cpath(path)?);
+ if (res == -1) {
+ return *__errno(): errno;
+ };
+};
+
// getsid
@symbol("getsid") fn libc_getsid(pid: pid_t) pid_t;
diff --git a/rt/+openbsd/types.ha b/rt/+openbsd/types.ha
@@ -25,6 +25,8 @@ export type nullpromise = void;
// Maximum length of a file path including the NUL terminator.
export def PATH_MAX: size = 1024;
+export def NAME_MAX: size = 255;
+
export def PATH_PTMDEV: str = "/dev/ptm";
export def PTMGET: u64 = 0x40287401;