Skip to content
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

zvfs: improve libc FILE to integer fd abstraction #83386

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 14 additions & 18 deletions include/zephyr/posix/fcntl.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,24 @@
#ifndef ZEPHYR_POSIX_FCNTL_H_
#define ZEPHYR_POSIX_FCNTL_H_

#ifdef CONFIG_PICOLIBC
#define O_CREAT 0x0040
#define O_TRUNC 0x0200
#define O_APPEND 0x0400
#else
#define O_CREAT 0x0200
#define O_TRUNC 0x0400
#define O_APPEND 0x0008
#endif
#include <zephyr/sys/fdtable.h>

#define O_CREAT ZVFS_O_CREAT
#define O_TRUNC ZVFS_O_TRUNC
#define O_APPEND ZVFS_O_APPEND

#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
#define O_ACCMODE (ZVFS_O_RDONLY | ZVFS_O_WRONLY | ZVFS_O_RDWR)

#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
#define O_RDONLY ZVFS_O_RDONLY
#define O_WRONLY ZVFS_O_WRONLY
#define O_RDWR ZVFS_O_RDWR

#define O_EXCL 0x0800
#define O_NONBLOCK 0x4000
#define O_EXCL ZVFS_O_EXCL
#define O_NONBLOCK ZVFS_O_NONBLOCK

#define F_DUPFD 0
#define F_GETFL 3
#define F_SETFL 4
#define F_DUPFD ZVFS_F_DUPFD
#define F_GETFL ZVFS_F_GETFL
#define F_SETFL ZVFS_F_SETFL

#ifdef __cplusplus
extern "C" {
Expand Down
21 changes: 21 additions & 0 deletions include/zephyr/sys/fdtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,27 @@
#include <zephyr/kernel.h>
#include <zephyr/sys/util.h>

#ifdef CONFIG_PICOLIBC
#define ZVFS_O_CREAT 0x0040
#define ZVFS_O_TRUNC 0x0200
#define ZVFS_O_APPEND 0x0400
#else
#define ZVFS_O_CREAT 0x0200
#define ZVFS_O_TRUNC 0x0400
#define ZVFS_O_APPEND 0x0008
#endif

#define ZVFS_O_RDONLY 00
#define ZVFS_O_WRONLY 01
#define ZVFS_O_RDWR 02

#define ZVFS_O_EXCL 0x0800
#define ZVFS_O_NONBLOCK 0x4000

#define ZVFS_F_DUPFD 0
#define ZVFS_F_GETFL 3
#define ZVFS_F_SETFL 4

/* File mode bits */
#define ZVFS_MODE_IFMT 0170000
#define ZVFS_MODE_UNSPEC 0000000
Expand Down
5 changes: 4 additions & 1 deletion lib/libc/newlib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# SPDX-License-Identifier: Apache-2.0

zephyr_library()
zephyr_library_sources(libc-hooks.c)
zephyr_library_sources(
libc-hooks.c
z_libc.c
)

# Do not allow LTO when compiling libc-hooks.c file
set_source_files_properties(libc-hooks.c PROPERTIES COMPILE_OPTIONS $<TARGET_PROPERTY:compiler,prohibit_lto>)
Expand Down
6 changes: 3 additions & 3 deletions lib/libc/newlib/libc-hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
int _fstat(int fd, struct stat *st);
int _read(int fd, void *buf, int nbytes);
int _write(int fd, const void *buf, int nbytes);
int _open(const char *name, int mode);
int _open(const char *name, int mode, ...);
int _close(int file);
int _lseek(int file, int ptr, int dir);
int _kill(int pid, int sig);
Expand Down Expand Up @@ -239,11 +239,11 @@ int _write(int fd, const void *buf, int nbytes)
}
__weak FUNC_ALIAS(_write, write, int);

int _open(const char *name, int mode)
int _open(const char *name, int mode, ...)
{
return -1;
}
__weak FUNC_ALIAS(_open, open, int);
__weak int open(const char *name, int mode, ...) ALIAS_OF(_open);

int _close(int file)
{
Expand Down
81 changes: 81 additions & 0 deletions lib/libc/newlib/z_libc.c
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;
}
1 change: 1 addition & 0 deletions lib/libc/picolibc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ zephyr_library_sources(
exit.c
locks.c
stdio.c
z_libc.c
)

zephyr_library_compile_options(-fno-lto)
Expand Down
60 changes: 60 additions & 0 deletions lib/libc/picolibc/z_libc.c
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);
}
34 changes: 30 additions & 4 deletions lib/os/fdtable.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,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 {
Expand Down Expand Up @@ -76,6 +81,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;
Expand Down Expand Up @@ -407,23 +426,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)
Expand Down
Loading