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_
|
||||
#define ZEPHYR_INCLUDE_POSIX_POSIX__FDTABLE_H_
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
/* FIXME: For native_posix ssize_t, off_t. */
|
||||
#include <fs.h>
|
||||
|
@ -21,7 +22,7 @@ extern "C" {
|
|||
struct fd_op_vtable {
|
||||
ssize_t (*read)(void *obj, 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);
|
||||
|
||||
/**
|
||||
* @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().
|
||||
*
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <kernel.h>
|
||||
#include <misc/fdtable.h>
|
||||
|
||||
|
@ -173,7 +174,7 @@ int close(int fd)
|
|||
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);
|
||||
|
||||
return res;
|
||||
|
@ -181,16 +182,11 @@ int close(int fd)
|
|||
|
||||
int fsync(int fd)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (_check_fd(fd) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = fdtable[fd].vtable->ioctl(fdtable[fd].obj, ZFD_IOCTL_FSYNC);
|
||||
z_free_fd(fd);
|
||||
|
||||
return res;
|
||||
return z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, ZFD_IOCTL_FSYNC);
|
||||
}
|
||||
|
||||
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 fdtable[fd].vtable->ioctl(fdtable[fd].obj, ZFD_IOCTL_LSEEK,
|
||||
offset, whence);
|
||||
return z_fdtable_call_ioctl(fdtable[fd].vtable, fdtable[fd].obj, ZFD_IOCTL_LSEEK,
|
||||
offset, whence);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -225,7 +221,7 @@ static ssize_t stdinout_write_vmeth(void *obj, const void *buffer, size_t count)
|
|||
#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;
|
||||
return -1;
|
||||
|
|
|
@ -94,7 +94,7 @@ int open(const char *name, int flags)
|
|||
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;
|
||||
struct posix_fs_desc *ptr = obj;
|
||||
|
@ -105,14 +105,11 @@ static int fs_ioctl_vmeth(void *obj, unsigned int request, ...)
|
|||
break;
|
||||
|
||||
case ZFD_IOCTL_LSEEK: {
|
||||
va_list args;
|
||||
off_t offset;
|
||||
int whence;
|
||||
|
||||
va_start(args, request);
|
||||
offset = va_arg(args, off_t);
|
||||
whence = va_arg(args, int);
|
||||
va_end(args);
|
||||
|
||||
rc = fs_seek(&ptr->file, offset, whence);
|
||||
break;
|
||||
|
|
|
@ -157,8 +157,8 @@ int zsock_close_ctx(struct net_context *ctx)
|
|||
|
||||
int _impl_zsock_close(int sock)
|
||||
{
|
||||
const struct socket_op_vtable *vtable;
|
||||
void *ctx = get_sock_vtable(sock, &vtable);
|
||||
const struct fd_op_vtable *vtable;
|
||||
void *ctx = z_get_fd_obj_and_vtable(sock, &vtable);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
|
@ -166,7 +166,7 @@ int _impl_zsock_close(int 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
|
||||
|
@ -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)
|
||||
{
|
||||
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
|
||||
|
@ -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 *pev;
|
||||
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();
|
||||
|
||||
if (timeout < 0) {
|
||||
|
@ -771,14 +779,14 @@ int _impl_zsock_poll(struct zsock_pollfd *fds, int nfds, int timeout)
|
|||
continue;
|
||||
}
|
||||
|
||||
ctx = get_sock_vtable(pfd->fd, &vtable);
|
||||
ctx = z_get_fd_obj_and_vtable(pfd->fd, &vtable);
|
||||
if (ctx == NULL) {
|
||||
/* Will set POLLNVAL in return loop */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vtable->fd_vtable.ioctl(ctx, ZFD_IOCTL_POLL_PREPARE,
|
||||
pfd, &pev, pev_end) < 0) {
|
||||
if (z_fdtable_call_ioctl(vtable, ctx, ZFD_IOCTL_POLL_PREPARE,
|
||||
pfd, &pev, pev_end) < 0) {
|
||||
if (errno == EALREADY) {
|
||||
timeout = K_NO_WAIT;
|
||||
continue;
|
||||
|
@ -811,15 +819,15 @@ int _impl_zsock_poll(struct zsock_pollfd *fds, int nfds, int timeout)
|
|||
continue;
|
||||
}
|
||||
|
||||
ctx = get_sock_vtable(pfd->fd, &vtable);
|
||||
ctx = z_get_fd_obj_and_vtable(pfd->fd, &vtable);
|
||||
if (ctx == NULL) {
|
||||
pfd->revents = ZSOCK_POLLNVAL;
|
||||
ret++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vtable->fd_vtable.ioctl(ctx, ZFD_IOCTL_POLL_UPDATE,
|
||||
pfd, &pev) < 0) {
|
||||
if (z_fdtable_call_ioctl(vtable, ctx, ZFD_IOCTL_POLL_UPDATE,
|
||||
pfd, &pev) < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
retry = true;
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
|
@ -971,10 +979,8 @@ static int sock_ioctl_vmeth(void *obj, unsigned int request, ...)
|
|||
return 0;
|
||||
|
||||
case F_SETFL: {
|
||||
va_list args;
|
||||
int flags;
|
||||
|
||||
va_start(args, request);
|
||||
flags = va_arg(args, int);
|
||||
|
||||
if (flags & O_NONBLOCK) {
|
||||
|
@ -990,29 +996,23 @@ static int sock_ioctl_vmeth(void *obj, unsigned int request, ...)
|
|||
return zsock_close_ctx(obj);
|
||||
|
||||
case ZFD_IOCTL_POLL_PREPARE: {
|
||||
va_list args;
|
||||
struct zsock_pollfd *pfd;
|
||||
struct k_poll_event **pev;
|
||||
struct k_poll_event *pev_end;
|
||||
|
||||
va_start(args, request);
|
||||
pfd = va_arg(args, struct zsock_pollfd *);
|
||||
pev = 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);
|
||||
}
|
||||
|
||||
case ZFD_IOCTL_POLL_UPDATE: {
|
||||
va_list args;
|
||||
struct zsock_pollfd *pfd;
|
||||
struct k_poll_event **pev;
|
||||
|
||||
va_start(args, request);
|
||||
pfd = va_arg(args, struct zsock_pollfd *);
|
||||
pev = va_arg(args, struct k_poll_event **);
|
||||
va_end(args);
|
||||
|
||||
return zsock_poll_update_ctx(obj, pfd, pev);
|
||||
}
|
||||
|
|
|
@ -1180,7 +1180,7 @@ int ztls_close_ctx(struct net_context *ctx)
|
|||
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 succeeds, but tls_release fails, set errno
|
||||
|
@ -1315,7 +1315,7 @@ error:
|
|||
__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");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
/* fcntl() commands */
|
||||
case F_GETFL:
|
||||
case F_SETFL: {
|
||||
va_list args;
|
||||
int err;
|
||||
|
||||
case F_SETFL:
|
||||
/* Pass the call to the core socket implementation. */
|
||||
va_start(args, request);
|
||||
err = sock_fd_op_vtable.fd_vtable.ioctl(obj, request, args);
|
||||
va_end(args);
|
||||
|
||||
return err;
|
||||
}
|
||||
return sock_fd_op_vtable.fd_vtable.ioctl(obj, request, args);
|
||||
|
||||
case ZFD_IOCTL_CLOSE:
|
||||
return ztls_close_ctx(obj);
|
||||
|
||||
case ZFD_IOCTL_POLL_PREPARE: {
|
||||
va_list args;
|
||||
struct zsock_pollfd *pfd;
|
||||
struct k_poll_event **pev;
|
||||
struct k_poll_event *pev_end;
|
||||
|
||||
va_start(args, request);
|
||||
pfd = va_arg(args, struct zsock_pollfd *);
|
||||
pev = 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);
|
||||
}
|
||||
|
||||
case ZFD_IOCTL_POLL_UPDATE: {
|
||||
va_list args;
|
||||
struct zsock_pollfd *pfd;
|
||||
struct k_poll_event **pev;
|
||||
|
||||
va_start(args, request);
|
||||
pfd = va_arg(args, struct zsock_pollfd *);
|
||||
pev = va_arg(args, struct k_poll_event **);
|
||||
va_end(args);
|
||||
|
||||
return ztls_poll_update_ctx(obj, pfd, pev);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue