lib: fdtable: Change ioctl vmethod signature to take va_list
As extend fdtable usage to more cases, there regularly arises a need to forward ioctl/fcntl arguments to another ioctl vmethod, which is complicated because it defined as taking variadic arguments. The only portable solution is to convert variadic arguments to va_list at the first point of entry from client code, and then pass va_list around. To facilitate calling ioctl with variadic arguments from system code, z_fdtable_call_ioctl() helper function is added. Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
This commit is contained in:
parent
4b1eba7cac
commit
13b38ed686
5 changed files with 59 additions and 54 deletions
|
@ -6,6 +6,7 @@
|
||||||
#ifndef ZEPHYR_INCLUDE_POSIX_POSIX__FDTABLE_H_
|
#ifndef ZEPHYR_INCLUDE_POSIX_POSIX__FDTABLE_H_
|
||||||
#define ZEPHYR_INCLUDE_POSIX_POSIX__FDTABLE_H_
|
#define ZEPHYR_INCLUDE_POSIX_POSIX__FDTABLE_H_
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
/* FIXME: For native_posix ssize_t, off_t. */
|
/* FIXME: For native_posix ssize_t, off_t. */
|
||||||
#include <fs.h>
|
#include <fs.h>
|
||||||
|
@ -21,7 +22,7 @@ extern "C" {
|
||||||
struct fd_op_vtable {
|
struct fd_op_vtable {
|
||||||
ssize_t (*read)(void *obj, void *buf, size_t sz);
|
ssize_t (*read)(void *obj, void *buf, size_t sz);
|
||||||
ssize_t (*write)(void *obj, const void *buf, size_t sz);
|
ssize_t (*write)(void *obj, const void *buf, size_t sz);
|
||||||
int (*ioctl)(void *obj, unsigned int request, ...);
|
int (*ioctl)(void *obj, unsigned int request, va_list args);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,6 +100,31 @@ void *z_get_fd_obj(int fd, const struct fd_op_vtable *vtable, int err);
|
||||||
*/
|
*/
|
||||||
void *z_get_fd_obj_and_vtable(int fd, const struct fd_op_vtable **vtable);
|
void *z_get_fd_obj_and_vtable(int fd, const struct fd_op_vtable **vtable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Call ioctl vmethod on an object using varargs.
|
||||||
|
*
|
||||||
|
* We need this helper function because ioctl vmethod is declared to
|
||||||
|
* take va_list and the only portable way to construct va_list is from
|
||||||
|
* function's ... parameters.
|
||||||
|
*
|
||||||
|
* @param vtable vtable containing ioctl function pointer
|
||||||
|
* @param obj Object to call ioctl on
|
||||||
|
* @param request ioctl request number
|
||||||
|
* @param ... Variadic arguments to ioctl
|
||||||
|
*/
|
||||||
|
static inline int z_fdtable_call_ioctl(const struct fd_op_vtable *vtable, void *obj,
|
||||||
|
unsigned long request, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
va_start(args, request);
|
||||||
|
res = vtable->ioctl(obj, request, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request codes for fd_op_vtable.ioctl().
|
* Request codes for fd_op_vtable.ioctl().
|
||||||
*
|
*
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include <misc/fdtable.h>
|
#include <misc/fdtable.h>
|
||||||
|
|
||||||
|
@ -173,7 +174,7 @@ int close(int fd)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fdtable[fd].vtable->ioctl(fdtable[fd].obj, ZFD_IOCTL_CLOSE);
|
res = z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, ZFD_IOCTL_CLOSE);
|
||||||
z_free_fd(fd);
|
z_free_fd(fd);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -181,16 +182,11 @@ int close(int fd)
|
||||||
|
|
||||||
int fsync(int fd)
|
int fsync(int fd)
|
||||||
{
|
{
|
||||||
int res;
|
|
||||||
|
|
||||||
if (_check_fd(fd) < 0) {
|
if (_check_fd(fd) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = fdtable[fd].vtable->ioctl(fdtable[fd].obj, ZFD_IOCTL_FSYNC);
|
return z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, ZFD_IOCTL_FSYNC);
|
||||||
z_free_fd(fd);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
off_t lseek(int fd, off_t offset, int whence)
|
off_t lseek(int fd, off_t offset, int whence)
|
||||||
|
@ -199,8 +195,8 @@ off_t lseek(int fd, off_t offset, int whence)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fdtable[fd].vtable->ioctl(fdtable[fd].obj, ZFD_IOCTL_LSEEK,
|
return z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, ZFD_IOCTL_LSEEK,
|
||||||
offset, whence);
|
offset, whence);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -225,7 +221,7 @@ static ssize_t stdinout_write_vmeth(void *obj, const void *buffer, size_t count)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stdinout_ioctl_vmeth(void *obj, unsigned int request, ...)
|
static int stdinout_ioctl_vmeth(void *obj, unsigned int request, va_list args)
|
||||||
{
|
{
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -94,7 +94,7 @@ int open(const char *name, int flags)
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fs_ioctl_vmeth(void *obj, unsigned int request, ...)
|
static int fs_ioctl_vmeth(void *obj, unsigned int request, va_list args)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct posix_fs_desc *ptr = obj;
|
struct posix_fs_desc *ptr = obj;
|
||||||
|
@ -105,14 +105,11 @@ static int fs_ioctl_vmeth(void *obj, unsigned int request, ...)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ZFD_IOCTL_LSEEK: {
|
case ZFD_IOCTL_LSEEK: {
|
||||||
va_list args;
|
|
||||||
off_t offset;
|
off_t offset;
|
||||||
int whence;
|
int whence;
|
||||||
|
|
||||||
va_start(args, request);
|
|
||||||
offset = va_arg(args, off_t);
|
offset = va_arg(args, off_t);
|
||||||
whence = va_arg(args, int);
|
whence = va_arg(args, int);
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
rc = fs_seek(&ptr->file, offset, whence);
|
rc = fs_seek(&ptr->file, offset, whence);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -157,8 +157,8 @@ int zsock_close_ctx(struct net_context *ctx)
|
||||||
|
|
||||||
int _impl_zsock_close(int sock)
|
int _impl_zsock_close(int sock)
|
||||||
{
|
{
|
||||||
const struct socket_op_vtable *vtable;
|
const struct fd_op_vtable *vtable;
|
||||||
void *ctx = get_sock_vtable(sock, &vtable);
|
void *ctx = z_get_fd_obj_and_vtable(sock, &vtable);
|
||||||
|
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -166,7 +166,7 @@ int _impl_zsock_close(int sock)
|
||||||
|
|
||||||
z_free_fd(sock);
|
z_free_fd(sock);
|
||||||
|
|
||||||
return vtable->fd_vtable.ioctl(ctx, ZFD_IOCTL_CLOSE);
|
return z_fdtable_call_ioctl(vtable, ctx, ZFD_IOCTL_CLOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_USERSPACE
|
#ifdef CONFIG_USERSPACE
|
||||||
|
@ -687,7 +687,15 @@ Z_SYSCALL_HANDLER(zsock_recvfrom, sock, buf, max_len, flags, src_addr,
|
||||||
*/
|
*/
|
||||||
int _impl_zsock_fcntl(int sock, int cmd, int flags)
|
int _impl_zsock_fcntl(int sock, int cmd, int flags)
|
||||||
{
|
{
|
||||||
VTABLE_CALL(fd_vtable.ioctl, sock, cmd, flags);
|
const struct fd_op_vtable *vtable;
|
||||||
|
void *obj;
|
||||||
|
|
||||||
|
obj = z_get_fd_obj_and_vtable(sock, &vtable);
|
||||||
|
if (obj == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return z_fdtable_call_ioctl(vtable, obj, cmd, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_USERSPACE
|
#ifdef CONFIG_USERSPACE
|
||||||
|
@ -755,7 +763,7 @@ int _impl_zsock_poll(struct zsock_pollfd *fds, int nfds, int timeout)
|
||||||
struct k_poll_event poll_events[CONFIG_NET_SOCKETS_POLL_MAX];
|
struct k_poll_event poll_events[CONFIG_NET_SOCKETS_POLL_MAX];
|
||||||
struct k_poll_event *pev;
|
struct k_poll_event *pev;
|
||||||
struct k_poll_event *pev_end = poll_events + ARRAY_SIZE(poll_events);
|
struct k_poll_event *pev_end = poll_events + ARRAY_SIZE(poll_events);
|
||||||
const struct socket_op_vtable *vtable;
|
const struct fd_op_vtable *vtable;
|
||||||
u32_t entry_time = k_uptime_get_32();
|
u32_t entry_time = k_uptime_get_32();
|
||||||
|
|
||||||
if (timeout < 0) {
|
if (timeout < 0) {
|
||||||
|
@ -771,14 +779,14 @@ int _impl_zsock_poll(struct zsock_pollfd *fds, int nfds, int timeout)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = get_sock_vtable(pfd->fd, &vtable);
|
ctx = z_get_fd_obj_and_vtable(pfd->fd, &vtable);
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
/* Will set POLLNVAL in return loop */
|
/* Will set POLLNVAL in return loop */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vtable->fd_vtable.ioctl(ctx, ZFD_IOCTL_POLL_PREPARE,
|
if (z_fdtable_call_ioctl(vtable, ctx, ZFD_IOCTL_POLL_PREPARE,
|
||||||
pfd, &pev, pev_end) < 0) {
|
pfd, &pev, pev_end) < 0) {
|
||||||
if (errno == EALREADY) {
|
if (errno == EALREADY) {
|
||||||
timeout = K_NO_WAIT;
|
timeout = K_NO_WAIT;
|
||||||
continue;
|
continue;
|
||||||
|
@ -811,15 +819,15 @@ int _impl_zsock_poll(struct zsock_pollfd *fds, int nfds, int timeout)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = get_sock_vtable(pfd->fd, &vtable);
|
ctx = z_get_fd_obj_and_vtable(pfd->fd, &vtable);
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
pfd->revents = ZSOCK_POLLNVAL;
|
pfd->revents = ZSOCK_POLLNVAL;
|
||||||
ret++;
|
ret++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vtable->fd_vtable.ioctl(ctx, ZFD_IOCTL_POLL_UPDATE,
|
if (z_fdtable_call_ioctl(vtable, ctx, ZFD_IOCTL_POLL_UPDATE,
|
||||||
pfd, &pev) < 0) {
|
pfd, &pev) < 0) {
|
||||||
if (errno == EAGAIN) {
|
if (errno == EAGAIN) {
|
||||||
retry = true;
|
retry = true;
|
||||||
continue;
|
continue;
|
||||||
|
@ -958,7 +966,7 @@ static ssize_t sock_write_vmeth(void *obj, const void *buffer, size_t count)
|
||||||
return zsock_sendto_ctx(obj, buffer, count, 0, NULL, 0);
|
return zsock_sendto_ctx(obj, buffer, count, 0, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sock_ioctl_vmeth(void *obj, unsigned int request, ...)
|
static int sock_ioctl_vmeth(void *obj, unsigned int request, va_list args)
|
||||||
{
|
{
|
||||||
switch (request) {
|
switch (request) {
|
||||||
|
|
||||||
|
@ -971,10 +979,8 @@ static int sock_ioctl_vmeth(void *obj, unsigned int request, ...)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case F_SETFL: {
|
case F_SETFL: {
|
||||||
va_list args;
|
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
va_start(args, request);
|
|
||||||
flags = va_arg(args, int);
|
flags = va_arg(args, int);
|
||||||
|
|
||||||
if (flags & O_NONBLOCK) {
|
if (flags & O_NONBLOCK) {
|
||||||
|
@ -990,29 +996,23 @@ static int sock_ioctl_vmeth(void *obj, unsigned int request, ...)
|
||||||
return zsock_close_ctx(obj);
|
return zsock_close_ctx(obj);
|
||||||
|
|
||||||
case ZFD_IOCTL_POLL_PREPARE: {
|
case ZFD_IOCTL_POLL_PREPARE: {
|
||||||
va_list args;
|
|
||||||
struct zsock_pollfd *pfd;
|
struct zsock_pollfd *pfd;
|
||||||
struct k_poll_event **pev;
|
struct k_poll_event **pev;
|
||||||
struct k_poll_event *pev_end;
|
struct k_poll_event *pev_end;
|
||||||
|
|
||||||
va_start(args, request);
|
|
||||||
pfd = va_arg(args, struct zsock_pollfd *);
|
pfd = va_arg(args, struct zsock_pollfd *);
|
||||||
pev = va_arg(args, struct k_poll_event **);
|
pev = va_arg(args, struct k_poll_event **);
|
||||||
pev_end = va_arg(args, struct k_poll_event *);
|
pev_end = va_arg(args, struct k_poll_event *);
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
return zsock_poll_prepare_ctx(obj, pfd, pev, pev_end);
|
return zsock_poll_prepare_ctx(obj, pfd, pev, pev_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
case ZFD_IOCTL_POLL_UPDATE: {
|
case ZFD_IOCTL_POLL_UPDATE: {
|
||||||
va_list args;
|
|
||||||
struct zsock_pollfd *pfd;
|
struct zsock_pollfd *pfd;
|
||||||
struct k_poll_event **pev;
|
struct k_poll_event **pev;
|
||||||
|
|
||||||
va_start(args, request);
|
|
||||||
pfd = va_arg(args, struct zsock_pollfd *);
|
pfd = va_arg(args, struct zsock_pollfd *);
|
||||||
pev = va_arg(args, struct k_poll_event **);
|
pev = va_arg(args, struct k_poll_event **);
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
return zsock_poll_update_ctx(obj, pfd, pev);
|
return zsock_poll_update_ctx(obj, pfd, pev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1180,7 +1180,7 @@ int ztls_close_ctx(struct net_context *ctx)
|
||||||
err = -EBADF;
|
err = -EBADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = sock_fd_op_vtable.fd_vtable.ioctl(ctx, ZFD_IOCTL_CLOSE);
|
ret = z_fdtable_call_ioctl(&sock_fd_op_vtable.fd_vtable, ctx, ZFD_IOCTL_CLOSE);
|
||||||
|
|
||||||
/* In case close fails, we propagate errno value set by close.
|
/* In case close fails, we propagate errno value set by close.
|
||||||
* In case close succeeds, but tls_release fails, set errno
|
* In case close succeeds, but tls_release fails, set errno
|
||||||
|
@ -1315,7 +1315,7 @@ error:
|
||||||
__ASSERT(err == 0, "TLS context release failed");
|
__ASSERT(err == 0, "TLS context release failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sock_fd_op_vtable.fd_vtable.ioctl(child, ZFD_IOCTL_CLOSE);
|
err = z_fdtable_call_ioctl(&sock_fd_op_vtable.fd_vtable, child, ZFD_IOCTL_CLOSE);
|
||||||
__ASSERT(err == 0, "Child socket close failed");
|
__ASSERT(err == 0, "Child socket close failed");
|
||||||
|
|
||||||
z_free_fd(fd);
|
z_free_fd(fd);
|
||||||
|
@ -1849,51 +1849,37 @@ static ssize_t tls_sock_write_vmeth(void *obj, const void *buffer,
|
||||||
return ztls_sendto_ctx(obj, buffer, count, 0, NULL, 0);
|
return ztls_sendto_ctx(obj, buffer, count, 0, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tls_sock_ioctl_vmeth(void *obj, unsigned int request, ...)
|
static int tls_sock_ioctl_vmeth(void *obj, unsigned int request, va_list args)
|
||||||
{
|
{
|
||||||
switch (request) {
|
switch (request) {
|
||||||
|
|
||||||
/* fcntl() commands */
|
/* fcntl() commands */
|
||||||
case F_GETFL:
|
case F_GETFL:
|
||||||
case F_SETFL: {
|
case F_SETFL:
|
||||||
va_list args;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/* Pass the call to the core socket implementation. */
|
/* Pass the call to the core socket implementation. */
|
||||||
va_start(args, request);
|
return sock_fd_op_vtable.fd_vtable.ioctl(obj, request, args);
|
||||||
err = sock_fd_op_vtable.fd_vtable.ioctl(obj, request, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
case ZFD_IOCTL_CLOSE:
|
case ZFD_IOCTL_CLOSE:
|
||||||
return ztls_close_ctx(obj);
|
return ztls_close_ctx(obj);
|
||||||
|
|
||||||
case ZFD_IOCTL_POLL_PREPARE: {
|
case ZFD_IOCTL_POLL_PREPARE: {
|
||||||
va_list args;
|
|
||||||
struct zsock_pollfd *pfd;
|
struct zsock_pollfd *pfd;
|
||||||
struct k_poll_event **pev;
|
struct k_poll_event **pev;
|
||||||
struct k_poll_event *pev_end;
|
struct k_poll_event *pev_end;
|
||||||
|
|
||||||
va_start(args, request);
|
|
||||||
pfd = va_arg(args, struct zsock_pollfd *);
|
pfd = va_arg(args, struct zsock_pollfd *);
|
||||||
pev = va_arg(args, struct k_poll_event **);
|
pev = va_arg(args, struct k_poll_event **);
|
||||||
pev_end = va_arg(args, struct k_poll_event *);
|
pev_end = va_arg(args, struct k_poll_event *);
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
return ztls_poll_prepare_ctx(obj, pfd, pev, pev_end);
|
return ztls_poll_prepare_ctx(obj, pfd, pev, pev_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
case ZFD_IOCTL_POLL_UPDATE: {
|
case ZFD_IOCTL_POLL_UPDATE: {
|
||||||
va_list args;
|
|
||||||
struct zsock_pollfd *pfd;
|
struct zsock_pollfd *pfd;
|
||||||
struct k_poll_event **pev;
|
struct k_poll_event **pev;
|
||||||
|
|
||||||
va_start(args, request);
|
|
||||||
pfd = va_arg(args, struct zsock_pollfd *);
|
pfd = va_arg(args, struct zsock_pollfd *);
|
||||||
pev = va_arg(args, struct k_poll_event **);
|
pev = va_arg(args, struct k_poll_event **);
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
return ztls_poll_update_ctx(obj, pfd, pev);
|
return ztls_poll_update_ctx(obj, pfd, pev);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue