hare

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

commit 3c362bec22fb22ac81f7929365770cc612e0e29f
parent 8d5cf5206a6a57d9d2e35e1c34e5961917a4b06a
Author: Drew DeVault <sir@cmpwn.com>
Date:   Mon, 16 Aug 2021 10:03:52 +0200

os::dirfdfs: allow tuning getdents buffer size

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Merrors/common.ha | 4++++
Merrors/string.ha | 1+
Mos/+linux/dirfdfs.ha | 24++++++++++++++++++++++--
3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/errors/common.ha b/errors/common.ha @@ -28,6 +28,9 @@ export type cancelled = !void; // A connection attempt was refused. export type refused = !void; +// Unable to allocate sufficient memory for the requested operation. +export type nomem = !void; + // A tagged union of all error types. export type error = !( busy | @@ -40,5 +43,6 @@ export type error = !( timeout | cancelled | refused | + nomem | opaque ); diff --git a/errors/string.ha b/errors/string.ha @@ -19,5 +19,6 @@ export fn strerror(err: error) const str = match (err) { timeout => "The requested operation timed out", cancelled => "The requested operation was cancelled", refused => "A connection attempt was refused", + nomem => "Unable to allocate sufficient memory for the requested operation", op: opaque => op.strerror(&op.data), }; diff --git a/os/+linux/dirfdfs.ha b/os/+linux/dirfdfs.ha @@ -41,6 +41,7 @@ type os_filesystem = struct { fs: fs::fs, dirfd: int, resolve: resolve_flags, + getdents_bufsz: size, }; // Opens a file descriptor as an [[fs::fs]]. This file descriptor must be a @@ -78,6 +79,7 @@ fn static_dirfdopen(fd: int, filesystem: *os_filesystem) *fs::fs = { ... }, dirfd = fd, + getdents_bufsz = 32768, // 32 KiB }; return &filesystem.fs; }; @@ -95,6 +97,17 @@ export fn dirfs_clone(fs: *fs::fs, resolve: resolve_flags...) *fs::fs = { return &new.fs; }; +// Sets the buffer size to use with the getdents(2) system call, for use with +// [[fs::iter]]. A larger buffer requires a larger runtime allocation, but can +// scan large directories faster. The default buffer size is 32 KiB. +// +// This function is not portable. +export fn dirfdfs_set_getdents_bufsz(fs: *fs::fs, sz: size) void = { + assert(fs.open == &fs_open); + let fs = fs: *os_filesystem; + fs.getdents_bufsz = sz; +}; + fn errno_to_fs(err: rt::errno) fs::error = switch (err) { rt::ENOENT => errors::noentry, rt::EEXIST => errors::exists, @@ -349,7 +362,7 @@ type os_iterator = struct { fd: int, buf_pos: size, buf_end: size, - buf: [BUFSIZ]u8, + buf: []u8, }; fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { @@ -364,11 +377,16 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { n: int => n, }; + let buf = match (rt::malloc(fs.getdents_bufsz)) { + v: *void => v: *[*]u8, + null => return errors::nomem, + }; let iter = alloc(os_iterator { iter = fs::iterator { next = &iter_next, }, fd = fd, + buf = buf[..fs.getdents_bufsz], ... }); return &iter.iter; @@ -377,9 +395,11 @@ fn fs_iter(fs: *fs::fs, path: str) (*fs::iterator | fs::error) = { fn iter_next(iter: *fs::iterator) (fs::dirent | void) = { let iter = iter: *os_iterator; if (iter.buf_pos >= iter.buf_end) { - let n = rt::getdents64(iter.fd, &iter.buf, BUFSIZ) as size; + let n = rt::getdents64(iter.fd, + iter.buf: *[*]u8, len(iter.buf)) as size; if (n == 0) { rt::close(iter.fd)!; + free(iter.buf); free(iter); return; };