hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mmakefiles/freebsd.aarch64.mk | 2+-
Mmakefiles/freebsd.riscv64.mk | 2+-
Mmakefiles/freebsd.x86_64.mk | 2+-
Mmakefiles/linux.aarch64.mk | 2+-
Mmakefiles/linux.riscv64.mk | 2+-
Mmakefiles/linux.x86_64.mk | 2+-
Mmakefiles/openbsd.aarch64.mk | 2+-
Mmakefiles/openbsd.riscv64.mk | 2+-
Mmakefiles/openbsd.x86_64.mk | 2+-
Aos/+freebsd/memfd.ha | 42++++++++++++++++++++++++++++++++++++++++++
Aos/+freebsd/shm.ha | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aos/+linux/memfd.ha | 36++++++++++++++++++++++++++++++++++++
Aos/+linux/shm.ha | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aos/+openbsd/shm.ha | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mrt/+freebsd/syscalls.ha | 29+++++++++++++++++++++++++++++
Mrt/+freebsd/types.ha | 10++++++++++
Mrt/+openbsd/syscalls.ha | 23+++++++++++++++++++++++
Mrt/+openbsd/types.ha | 2++
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;