Skip to content

Commit

Permalink
posix: device_io: implement pread() and pwrite()
Browse files Browse the repository at this point in the history
Add pread() and pwrite() implementations, which are nearly
identical to read() and write() but differ in that they do not
update the file-descriptor offset and instead read from a
specific file offset.

Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
  • Loading branch information
cfriedt authored and nashif committed Jun 27, 2024
1 parent 86b9293 commit 2d72966
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 17 deletions.
54 changes: 41 additions & 13 deletions lib/os/fdtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,34 +308,62 @@ int zvfs_alloc_fd(void *obj, const struct fd_op_vtable *vtable)
return fd;
}

static ssize_t zvfs_rw(int fd, void *buf, size_t sz, bool is_write)
static bool supports_pread_pwrite(uint32_t mode)
{
switch (mode & ZVFS_MODE_IFMT) {
case ZVFS_MODE_IFSHM:
return true;
default:
return false;
}
}

static ssize_t zvfs_rw(int fd, void *buf, size_t sz, bool is_write, const size_t *from_offset)
{
bool prw;
ssize_t res;
const size_t *off;

if (_check_fd(fd) < 0) {
return -1;
}

(void)k_mutex_lock(&fdtable[fd].lock, K_FOREVER);

prw = supports_pread_pwrite(fdtable[fd].mode);
if (from_offset != NULL && !prw) {
/*
* Seekable file types should support pread() / pwrite() and per-fd offset passing.
* Otherwise, it's a bug.
*/
errno = ENOTSUP;
res = -1;
goto unlock;
}

/* If there is no specified from_offset, then use the current offset of the fd */
off = (from_offset == NULL) ? &fdtable[fd].offset : from_offset;

if (is_write) {
if (fdtable[fd].vtable->write_offset == NULL) {
if (fdtable[fd].vtable->write_offs == NULL) {
res = -1;
errno = EIO;
} else {
res = fdtable[fd].vtable->write_offset(fdtable[fd].obj, buf, sz,
fdtable[fd].offset);
res = fdtable[fd].vtable->write_offs(fdtable[fd].obj, buf, sz, *off);
}
} else {
if (fdtable[fd].vtable->read == NULL) {
if (fdtable[fd].vtable->read_offs == NULL) {
res = -1;
errno = EIO;
} else {
res = fdtable[fd].vtable->read_offset(fdtable[fd].obj, buf, sz,
fdtable[fd].offset);
res = fdtable[fd].vtable->read_offs(fdtable[fd].obj, buf, sz, *off);
}
}
if (res > 0) {
if (res > 0 && prw && from_offset == NULL) {
/*
* only update the fd offset when from_offset is not specified
* See pread() / pwrite()
*/
fdtable[fd].offset += res;
}

Expand All @@ -345,14 +373,14 @@ static ssize_t zvfs_rw(int fd, void *buf, size_t sz, bool is_write)
return res;
}

ssize_t zvfs_read(int fd, void *buf, size_t sz)
ssize_t zvfs_read(int fd, void *buf, size_t sz, const size_t *from_offset)
{
return zvfs_rw(fd, buf, sz, false);
return zvfs_rw(fd, buf, sz, false, from_offset);
}

ssize_t zvfs_write(int fd, const void *buf, size_t sz)
ssize_t zvfs_write(int fd, const void *buf, size_t sz, const size_t *from_offset)
{
return zvfs_rw(fd, (void *)buf, sz, true);
return zvfs_rw(fd, (void *)buf, sz, true, from_offset);
}

int zvfs_close(int fd)
Expand Down Expand Up @@ -494,7 +522,7 @@ static ssize_t stdinout_read_vmeth(void *obj, void *buffer, size_t count)
static ssize_t stdinout_write_vmeth(void *obj, const void *buffer, size_t count)
{
#if defined(CONFIG_BOARD_NATIVE_POSIX)
return zvfs_write(1, buffer, count);
return zvfs_write(1, buffer, count, NULL);
#elif defined(CONFIG_NEWLIB_LIBC) || defined(CONFIG_ARCMWDT_LIBC)
return z_impl_zephyr_write_stdout(buffer, count);
#else
Expand Down
32 changes: 28 additions & 4 deletions lib/posix/options/device_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
/* prototypes for external, not-yet-public, functions in fdtable.c or fs.c */
int zvfs_close(int fd);
int zvfs_open(const char *name, int flags);
ssize_t zvfs_read(int fd, void *buf, size_t sz);
ssize_t zvfs_write(int fd, const void *buf, size_t sz);
ssize_t zvfs_read(int fd, void *buf, size_t sz, size_t *from_offset);
ssize_t zvfs_write(int fd, const void *buf, size_t sz, size_t *from_offset);

int close(int fd)
{
Expand All @@ -41,9 +41,33 @@ int poll(struct pollfd *fds, int nfds, int timeout)
return zsock_poll(fds, nfds, timeout);
}

ssize_t pread(int fd, void *buf, size_t count, off_t offset)
{
size_t off = (size_t)offset;

if (offset < 0) {
errno = EINVAL;
return -1;
}

return zvfs_read(fd, buf, count, (size_t *)&off);
}

ssize_t pwrite(int fd, void *buf, size_t count, off_t offset)
{
size_t off = (size_t)offset;

if (offset < 0) {
errno = EINVAL;
return -1;
}

return zvfs_write(fd, buf, count, (size_t *)&off);
}

ssize_t read(int fd, void *buf, size_t sz)
{
return zvfs_read(fd, buf, sz);
return zvfs_read(fd, buf, sz, NULL);
}
#ifdef CONFIG_POSIX_DEVICE_IO_ALIAS_READ
FUNC_ALIAS(read, _read, ssize_t);
Expand All @@ -57,7 +81,7 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struc

ssize_t write(int fd, const void *buf, size_t sz)
{
return zvfs_write(fd, buf, sz);
return zvfs_write(fd, buf, sz, NULL);
}
#ifdef CONFIG_POSIX_DEVICE_IO_ALIAS_WRITE
FUNC_ALIAS(write, _write, ssize_t);
Expand Down

0 comments on commit 2d72966

Please sign in to comment.