Skip to content

Commit f484bba

Browse files
pfalconcarlescufi
authored andcommitted
lib: posix: Implement generic file descriptor table
The table allows to wrap read/write (i.e. POSIX-compatible) semantics of any I/O object in POSIX-compatible fd (file descriptor) handling. Intended I/O objects include files, sockets, special devices, etc. The table table itself consists of (underlying obj*, function table*) pairs, where function table provides entries for read(), write, and generalized ioctl(), where generalized ioctl handles all other operations, up to and including closing of the underlying I/O object. Fixes: #7405 Signed-off-by: Paul Sokolovsky <[email protected]>
1 parent 3215dd8 commit f484bba

File tree

4 files changed

+294
-3
lines changed

4 files changed

+294
-3
lines changed

include/misc/fdtable.h

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright (c) 2018 Linaro Limited
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#ifndef ZEPHYR_INCLUDE_POSIX_POSIX__FDTABLE_H_
7+
#define ZEPHYR_INCLUDE_POSIX_POSIX__FDTABLE_H_
8+
9+
#include <sys/types.h>
10+
/* FIXME: For native_posix ssize_t, off_t. */
11+
#include <fs.h>
12+
13+
#ifdef __cplusplus
14+
extern "C" {
15+
#endif
16+
17+
/**
18+
* File descriptor virtual method table.
19+
* All operations beyond read/write go thru ioctl method.
20+
*/
21+
struct fd_op_vtable {
22+
ssize_t (*read)(void *obj, void *buf, size_t sz);
23+
ssize_t (*write)(void *obj, const void *buf, size_t sz);
24+
int (*ioctl)(void *obj, unsigned int request, ...);
25+
};
26+
27+
/**
28+
* @brief Reserve file descriptor.
29+
*
30+
* This function allows to reserve a space for file descriptor entry in
31+
* the underlying table, and thus allows caller to fail fast if no free
32+
* descriptor is available. If this function succeeds, z_finalize_fd()
33+
* or z_free_fd() must be called mandatorily.
34+
*
35+
* @return Allocated file descriptor, or -1 in case of error (errno is set)
36+
*/
37+
int z_reserve_fd(void);
38+
39+
/**
40+
* @brief Finalize creation of file descriptor.
41+
*
42+
* This function should be called exactly once after z_reserve_fd(), and
43+
* should not be called in any other case.
44+
*
45+
* @param fd File descriptor previously returned by z_reserve_fd()
46+
* @param obj pointer to I/O object structure
47+
* @param vtable pointer to I/O operation implementations for the object
48+
*/
49+
void z_finalize_fd(int fd, void *obj, const struct fd_op_vtable *vtable);
50+
51+
/**
52+
* @brief Allocate file descriptor for underlying I/O object.
53+
*
54+
* This function combines operations of z_reserve_fd() and z_finalize_fd()
55+
* in one step, and provided for convenience.
56+
*
57+
* @param obj pointer to I/O object structure
58+
* @param vtable pointer to I/O operation implementations for the object
59+
*
60+
* @return Allocated file descriptor, or -1 in case of error (errno is set)
61+
*/
62+
int z_alloc_fd(void *obj, const struct fd_op_vtable *vtable);
63+
64+
/**
65+
* @brief Release reserved file descriptor.
66+
*
67+
* This function may be called once after z_reserve_fd(), and should
68+
* not be called in any other case.
69+
*
70+
* @param fd File descriptor previously returned by z_reserve_fd()
71+
*/
72+
void z_free_fd(int fd);
73+
74+
/**
75+
* @brief Get underlying object pointer from file descriptor.
76+
*
77+
* This function is useful for functions other than read/write/ioctl
78+
* to look up underlying I/O object by fd, optionally checking its
79+
* type (using vtable reference). If fd refers to invalid entry,
80+
* NULL will be returned with errno set to EBADF. If fd is valid,
81+
* but vtable param is not NULL and doesn't match object's vtable,
82+
* NULL is returned and errno set to err param.
83+
*
84+
* @param fd File descriptor previously returned by z_reserve_fd()
85+
* @param vtable Expected object vtable or NULL
86+
* @param err errno value to set if object vtable doesn't match
87+
*
88+
* @return Object pointer or NULL, with errno set
89+
*/
90+
void *z_get_fd_obj(int fd, const struct fd_op_vtable *vtable, int err);
91+
92+
/**
93+
* Request codes for fd_op_vtable.ioctl().
94+
*
95+
* Note that these codes are internal Zephyr numbers, for internal
96+
* Zephyr operation (and subject to change without notice, not part
97+
* of "stable ABI"). These are however expected to co-exist with
98+
* "well-known" POSIX/Linux ioctl numbers, and not clash with them.
99+
*/
100+
enum {
101+
ZFD_IOCTL_CLOSE = 1,
102+
ZFD_IOCTL_FSYNC,
103+
ZFD_IOCTL_LSEEK,
104+
};
105+
106+
#ifdef __cplusplus
107+
}
108+
#endif
109+
110+
#endif /* ZEPHYR_INCLUDE_POSIX_POSIX__FDTABLE_H_ */

lib/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
zephyr_sources(thread_entry.c)
2+
zephyr_sources(fdtable.c)
23
add_subdirectory(crc)
34
add_subdirectory_ifdef(CONFIG_JSON_LIBRARY json)
45
if(NOT CONFIG_NATIVE_APPLICATION)

lib/fdtable.c

+171
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/*
2+
* Copyright (c) 2018 Linaro Limited
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @file
9+
* @brief File descriptor table
10+
*
11+
* This file provides generic file descriptor table implementation, suitable
12+
* for any I/O object implementing POSIX I/O semantics (i.e. read/write +
13+
* aux operations).
14+
*/
15+
16+
#include <errno.h>
17+
#include <kernel.h>
18+
#include <misc/fdtable.h>
19+
20+
struct fd_entry {
21+
void *obj;
22+
const struct fd_op_vtable *vtable;
23+
};
24+
25+
static struct fd_entry fdtable[CONFIG_POSIX_MAX_FDS];
26+
27+
static K_MUTEX_DEFINE(fdtable_lock);
28+
29+
static int _find_fd_entry(void)
30+
{
31+
int fd;
32+
33+
for (fd = 0; fd < ARRAY_SIZE(fdtable); fd++) {
34+
if (fdtable[fd].obj == NULL) {
35+
return fd;
36+
}
37+
}
38+
39+
errno = ENFILE;
40+
return -1;
41+
}
42+
43+
static int _check_fd(int fd)
44+
{
45+
if (fd < 0 || fd >= ARRAY_SIZE(fdtable) || fdtable[fd].obj == NULL) {
46+
errno = EBADF;
47+
return -1;
48+
}
49+
50+
return 0;
51+
}
52+
53+
void *z_get_fd_obj(int fd, const struct fd_op_vtable *vtable, int err)
54+
{
55+
struct fd_entry *fd_entry;
56+
57+
if (_check_fd(fd) < 0) {
58+
return NULL;
59+
}
60+
61+
fd_entry = &fdtable[fd];
62+
63+
if (vtable != NULL && fd_entry->vtable != vtable) {
64+
errno = err;
65+
return NULL;
66+
}
67+
68+
return fd_entry->obj;
69+
}
70+
71+
int z_reserve_fd(void)
72+
{
73+
int fd;
74+
75+
(void)k_mutex_lock(&fdtable_lock, K_FOREVER);
76+
77+
fd = _find_fd_entry();
78+
if (fd >= 0) {
79+
/* Mark entry as used, z_finalize_fd() will fill it in. */
80+
fdtable[fd].obj = FD_OBJ_RESERVED;
81+
}
82+
83+
k_mutex_unlock(&fdtable_lock);
84+
85+
return fd;
86+
}
87+
88+
void z_finalize_fd(int fd, void *obj, const struct fd_op_vtable *vtable)
89+
{
90+
/* Assumes fd was already bounds-checked. */
91+
fdtable[fd].obj = obj;
92+
fdtable[fd].vtable = vtable;
93+
}
94+
95+
void z_free_fd(int fd)
96+
{
97+
/* Assumes fd was already bounds-checked. */
98+
fdtable[fd].obj = NULL;
99+
}
100+
101+
int z_alloc_fd(void *obj, const struct fd_op_vtable *vtable)
102+
{
103+
int fd;
104+
105+
fd = z_reserve_fd();
106+
if (fd >= 0) {
107+
z_finalize_fd(fd, obj, vtable);
108+
}
109+
110+
return fd;
111+
}
112+
113+
#ifdef CONFIG_POSIX_API
114+
115+
ssize_t read(int fd, void *buf, size_t sz)
116+
{
117+
if (_check_fd(fd) < 0) {
118+
return -1;
119+
}
120+
121+
return fdtable[fd].vtable->read(fdtable[fd].obj, buf, sz);
122+
}
123+
124+
ssize_t write(int fd, const void *buf, size_t sz)
125+
{
126+
if (_check_fd(fd) < 0) {
127+
return -1;
128+
}
129+
130+
return fdtable[fd].vtable->write(fdtable[fd].obj, buf, sz);
131+
}
132+
133+
int close(int fd)
134+
{
135+
int res;
136+
137+
if (_check_fd(fd) < 0) {
138+
return -1;
139+
}
140+
141+
res = fdtable[fd].vtable->ioctl(fdtable[fd].obj, ZFD_IOCTL_CLOSE);
142+
z_free_fd(fd);
143+
144+
return res;
145+
}
146+
147+
int fsync(int fd)
148+
{
149+
int res;
150+
151+
if (_check_fd(fd) < 0) {
152+
return -1;
153+
}
154+
155+
res = fdtable[fd].vtable->ioctl(fdtable[fd].obj, ZFD_IOCTL_FSYNC);
156+
z_free_fd(fd);
157+
158+
return res;
159+
}
160+
161+
off_t lseek(int fd, off_t offset, int whence)
162+
{
163+
if (_check_fd(fd) < 0) {
164+
return -1;
165+
}
166+
167+
return fdtable[fd].vtable->ioctl(fdtable[fd].obj, ZFD_IOCTL_LSEEK,
168+
offset, whence);
169+
}
170+
171+
#endif /* CONFIG_POSIX_API */

lib/posix/Kconfig

+12-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44
# SPDX-License-Identifier: Apache-2.0
55
#
66

7+
config POSIX_MAX_FDS
8+
int "Maximum number of open file descriptors"
9+
default 16 if POSIX_API
10+
default 4
11+
help
12+
Maximum number of open file descriptors, this includes
13+
files, sockets, special devices, etc.
14+
715
config POSIX_API
816
bool "POSIX APIs"
917
help
@@ -75,15 +83,16 @@ if FILE_SYSTEM
7583
config POSIX_FS
7684
bool "Enable POSIX file system API support"
7785
help
78-
This enabled POSIX style file system related APIs.
86+
This enables POSIX style file system related APIs.
7987

8088
if POSIX_FS
8189
config POSIX_MAX_OPEN_FILES
8290
int "Maximum number of open file descriptors"
8391
default 16
8492
help
85-
Mention maximum number of open file descriptors.
86-
endif
93+
Maximum number of open files. Note that this setting
94+
is additionally bounded by CONFIG_POSIX_MAX_FDS.
8795
endif
96+
endif # FILE_SYSTEM
8897

8998
endif # POSIX_API

0 commit comments

Comments
 (0)