-
Notifications
You must be signed in to change notification settings - Fork 8k
zvfs: improve libc FILE to integer fd abstraction #83386
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* Copyright (c) 2024 Tenstorrent AI ULC | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <stddef.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
|
||
#include <zephyr/sys/fdtable.h> | ||
|
||
static int z_libc_sflags(const char *mode) | ||
{ | ||
int ret = 0; | ||
|
||
switch (mode[0]) { | ||
case 'r': | ||
ret = ZVFS_O_RDONLY; | ||
break; | ||
|
||
case 'w': | ||
ret = ZVFS_O_WRONLY | ZVFS_O_CREAT | ZVFS_O_TRUNC; | ||
break; | ||
|
||
case 'a': | ||
ret = ZVFS_O_WRONLY | ZVFS_O_CREAT | ZVFS_O_APPEND; | ||
break; | ||
default: | ||
return 0; | ||
} | ||
|
||
while (*++mode) { | ||
switch (*mode) { | ||
case '+': | ||
ret |= ZVFS_O_RDWR; | ||
break; | ||
case 'x': | ||
ret |= ZVFS_O_EXCL; | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
FILE *z_libc_file_alloc(int fd, const char *mode) | ||
{ | ||
FILE *fp; | ||
/* | ||
* These symbols have conflicting declarations in upstream headers. | ||
* Use uintptr_t and a cast to assign cleanly. | ||
*/ | ||
extern uintptr_t _close_r; | ||
extern uintptr_t _lseek_r; | ||
extern uintptr_t _read_r; | ||
extern uintptr_t _write_r; | ||
|
||
fp = calloc(1, sizeof(*fp)); | ||
if (fp == NULL) { | ||
return NULL; | ||
} | ||
|
||
fp->_flags = z_libc_sflags(mode); | ||
fp->_file = fd; | ||
fp->_cookie = (void *)fp; | ||
|
||
*(uintptr_t *)fp->_read = _read_r; | ||
*(uintptr_t *)fp->_write = _write_r; | ||
*(uintptr_t *)fp->_seek = _lseek_r; | ||
*(uintptr_t *)fp->_close = _close_r; | ||
|
||
return fp; | ||
} | ||
|
||
int z_libc_file_get_fd(FILE *fp) | ||
{ | ||
return fp->_file; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/* | ||
* Copyright (c) 2024 Tenstorrent AI ULC | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include "stdio-bufio.h" | ||
|
||
#include <stddef.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
|
||
#include <zephyr/sys/fdtable.h> | ||
|
||
#define FDEV_SETUP_ZVFS(fd, buf, size, rwflags, bflags) \ | ||
FDEV_SETUP_BUFIO(fd, buf, size, zvfs_read_wrap, zvfs_write_wrap, zvfs_lseek, zvfs_close, \ | ||
rwflags, bflags) | ||
|
||
int __posix_sflags(const char *mode, int *optr); | ||
|
||
/* FIXME: do not use ssize_t or off_t */ | ||
ssize_t zvfs_read(int fd, void *buf, size_t sz, const size_t *from_offset); | ||
ssize_t zvfs_write(int fd, const void *buf, size_t sz, const size_t *from_offset); | ||
off_t zvfs_lseek(int fd, off_t offset, int whence); | ||
int zvfs_close(int fd); | ||
|
||
static ssize_t zvfs_read_wrap(int fd, void *buf, size_t sz) | ||
{ | ||
return zvfs_read(fd, buf, sz, NULL); | ||
} | ||
|
||
static ssize_t zvfs_write_wrap(int fd, const void *buf, size_t sz) | ||
{ | ||
return zvfs_write(fd, buf, sz, NULL); | ||
} | ||
|
||
FILE *z_libc_file_alloc(int fd, const char *mode) | ||
{ | ||
struct __file_bufio *bf; | ||
int __maybe_unused unused; | ||
|
||
bf = calloc(1, sizeof(struct __file_bufio) + BUFSIZ); | ||
if (bf == NULL) { | ||
return NULL; | ||
} | ||
|
||
*bf = (struct __file_bufio)FDEV_SETUP_ZVFS(fd, (char *)(bf + 1), BUFSIZ, | ||
__posix_sflags(mode, &unused), __BFALL); | ||
|
||
__bufio_lock_init(&(bf->xfile.cfile.file)); | ||
|
||
return &(bf->xfile.cfile.file); | ||
} | ||
|
||
int z_libc_file_get_fd(const FILE *fp) | ||
{ | ||
const struct __file_bufio *const bf = (const struct __file_bufio *)fp; | ||
|
||
return POINTER_TO_INT(bf->ptr); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,11 @@ | |
#include <zephyr/internal/syscall_handler.h> | ||
#include <zephyr/sys/atomic.h> | ||
|
||
#ifndef CONFIG_MINIMAL_LIBC | ||
extern FILE *z_libc_file_alloc(int fd, const char *mode); | ||
|
||
extern int z_libc_file_get_fd(const FILE *fp); | ||
#endif | ||
|
||
struct stat; | ||
|
||
struct fd_entry { | ||
|
@@ -75,6 +80,20 @@ static struct fd_entry fdtable[CONFIG_ZVFS_OPEN_MAX] = { | |
|
||
static K_MUTEX_DEFINE(fdtable_lock); | ||
|
||
#ifdef CONFIG_MINIMAL_LIBC | ||
static ALWAYS_INLINE inline FILE *z_libc_file_alloc(int fd, const char *mode) | ||
{ | ||
ARG_UNUSED(mode); | ||
|
||
return (FILE *)&fdtable[fd]; | ||
} | ||
|
||
static ALWAYS_INLINE inline int z_libc_file_get_fd(const FILE *fp) | ||
{ | ||
return (const struct fd_entry *)fp - fdtable; | ||
} | ||
#endif | ||
|
||
static int z_fd_ref(int fd) | ||
{ | ||
return atomic_inc(&fdtable[fd].refcount) + 1; | ||
|
@@ -413,23 +432,30 @@ int zvfs_close(int fd) | |
|
||
FILE *zvfs_fdopen(int fd, const char *mode) | ||
{ | ||
ARG_UNUSED(mode); | ||
FILE *ret; | ||
|
||
if (_check_fd(fd) < 0) { | ||
return NULL; | ||
} | ||
|
||
return (FILE *)&fdtable[fd]; | ||
ret = z_libc_file_alloc(fd, mode); | ||
if (ret == NULL) { | ||
errno = ENOMEM; | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
int zvfs_fileno(FILE *file) | ||
{ | ||
if (!IS_ARRAY_ELEMENT(fdtable, file)) { | ||
int fd = z_libc_file_get_fd(file); | ||
|
||
if (fd < 0 || fd >= ARRAY_SIZE(fdtable)) { | ||
errno = EBADF; | ||
return -1; | ||
} | ||
|
||
return (struct fd_entry *)file - fdtable; | ||
return fd; | ||
} | ||
|
||
int zvfs_fstat(int fd, struct stat *buf) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was some comments about not using dynamic memory alloc. I just wonder if it could be possible to allow static allocation here, for example have Kconfig option to allow user either use dynamic alloc or to have an static array of these structs. This would allow the user to decide what suits his/hers usage better. Using malloc allows always a possibility to memory leaks.