[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v3] linux-user: add signalfd/signalfd4 syscalls
From: |
Riku Voipio |
Subject: |
Re: [Qemu-devel] [PATCH v3] linux-user: add signalfd/signalfd4 syscalls |
Date: |
Fri, 2 Oct 2015 14:42:35 +0300 |
User-agent: |
Mutt/1.5.24 (2015-08-30) |
Hi,
On Mon, Sep 28, 2015 at 11:42:28PM +0200, Laurent Vivier wrote:
> This patch introduces a system very similar to the one used in the kernel
> to attach specific functions to a given file descriptor.
>
> In this case, we attach a specific "host_to_target()" translator to the fd
> returned by signalfd() to be able to byte-swap the signalfd_siginfo
> structure provided by read().
>
> This patch allows to execute the example program given by
> man signalfd(2):
Looks good, but unfortunately collides with your
name_to_handle_at/open_by_handle_at
patch. Can you update in on top of that patch, or better, agains the que
at:
https://git.linaro.org/people/riku.voipio/qemu.git/shortlog/refs/heads/linux-user-for-upstream
I take this means adding fd_trans_unregister to the open_by_handle_at
function.
> #include <sys/signalfd.h>
> #include <signal.h>
> #include <unistd.h>
> #include <stdlib.h>
> #include <stdio.h>
>
> #define handle_error(msg) \
> do { perror(msg); exit(EXIT_FAILURE); } while (0)
>
> int
> main(int argc, char *argv[])
> {
> sigset_t mask;
> int sfd;
> struct signalfd_siginfo fdsi;
> ssize_t s;
>
> sigemptyset(&mask);
> sigaddset(&mask, SIGINT);
> sigaddset(&mask, SIGQUIT);
>
> /* Block signals so that they aren't handled
> according to their default dispositions */
>
> if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
> handle_error("sigprocmask");
>
> sfd = signalfd(-1, &mask, 0);
> if (sfd == -1)
> handle_error("signalfd");
>
> for (;;) {
> s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
> if (s != sizeof(struct signalfd_siginfo))
> handle_error("read");
>
> if (fdsi.ssi_signo == SIGINT) {
> printf("Got SIGINT\n");
> } else if (fdsi.ssi_signo == SIGQUIT) {
> printf("Got SIGQUIT\n");
> exit(EXIT_SUCCESS);
> } else {
> printf("Read unexpected signal\n");
> }
> }
> }
>
> $ ./signalfd_demo
> ^CGot SIGINT
> ^CGot SIGINT
> ^\Got SIGQUIT
>
> Signed-off-by: Laurent Vivier <address@hidden>
> ---
> v3: Combine struct definition and typedef
> replace a = x ? y : z by if () { }
> clear extra memory from g_realloc()
> remove useless management of O_CLOEXEC
> swap ssi_addr_lsb
> fix host_flags checking
> v2: Update commit message with example from man page
> Use CamelCase for struct
> Allocate entries in the fd array on demand
> Clear fd entries on open(), close(),...
> Swap ssi_errno
> Try to manage dup() and O_CLOEXEC cases
> Fix signalfd() parameters
> merge signalfd() and signalfd4()
> Change the API to only provide functions to process
> data stream.
>
> TargetFdTrans has an unused field, target_to_host, for symmetry
> and which could used later with netlink() functions.
>
> linux-user/syscall.c | 165
> +++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 165 insertions(+)
>
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index f62c698..b22b9f4 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -60,6 +60,7 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
> #include <sys/statfs.h>
> #include <utime.h>
> #include <sys/sysinfo.h>
> +#include <sys/signalfd.h>
> //#include <sys/user.h>
> #include <netinet/ip.h>
> #include <netinet/tcp.h>
> @@ -294,6 +295,54 @@ static bitmask_transtbl fcntl_flags_tbl[] = {
> { 0, 0, 0, 0 }
> };
>
> +typedef abi_long (*TargetFdFunc)(void *, size_t);
> +typedef struct TargetFdTrans {
> + TargetFdFunc host_to_target;
> + TargetFdFunc target_to_host;
> +} TargetFdTrans;
> +
> +static TargetFdTrans **target_fd_trans;
> +
> +static unsigned int target_fd_max;
> +
> +static TargetFdFunc fd_trans_host_to_target(int fd)
> +{
> + if (fd < target_fd_max && target_fd_trans[fd]) {
> + return target_fd_trans[fd]->host_to_target;
> + }
> + return NULL;
> +}
> +
> +static void fd_trans_register(int fd, TargetFdTrans *trans)
> +{
> + unsigned int oldmax;
> +
> + if (fd >= target_fd_max) {
> + oldmax = target_fd_max;
> + target_fd_max = ((fd >> 6) + 1) << 6; /* by slice of 64 entries */
> + target_fd_trans = g_realloc(target_fd_trans,
> + target_fd_max * sizeof(TargetFdTrans));
> + memset((void *)(target_fd_trans + oldmax), 0,
> + (target_fd_max - oldmax) * sizeof(TargetFdTrans *));
> + }
> + target_fd_trans[fd] = trans;
> +}
> +
> +static void fd_trans_unregister(int fd)
> +{
> + if (fd >= 0 && fd < target_fd_max) {
> + target_fd_trans[fd] = NULL;
> + }
> +}
> +
> +static void fd_trans_dup(int oldfd, int newfd)
> +{
> + fd_trans_unregister(newfd);
> + if (oldfd < target_fd_max && target_fd_trans[oldfd]) {
> + fd_trans_register(newfd, target_fd_trans[oldfd]);
> + }
> +}
> +
> static int sys_getcwd1(char *buf, size_t size)
> {
> if (getcwd(buf, size) == NULL) {
> @@ -5246,6 +5295,91 @@ static int do_futex(target_ulong uaddr, int op, int
> val, target_ulong timeout,
> return -TARGET_ENOSYS;
> }
> }
> +#if defined(TARGET_NR_signalfd) || defined(TARGET_NR_signalfd4)
> +
> +/* signalfd siginfo conversion */
> +
> +static void
> +host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo,
> + const struct signalfd_siginfo *info)
> +{
> + int sig = host_to_target_signal(info->ssi_signo);
> +
> + /* linux/signalfd.h defines a ssi_addr_lsb
> + * not defined in sys/signalfd.h but used by some kernels
> + */
> +
> +#ifdef BUS_MCEERR_AO
> + if (tinfo->ssi_signo == SIGBUS &&
> + (tinfo->ssi_code == BUS_MCEERR_AR ||
> + tinfo->ssi_code == BUS_MCEERR_AO)) {
> + uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1);
> + uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1);
> + *tssi_addr_lsb = tswap16(*ssi_addr_lsb);
> + }
> +#endif
> +
> + tinfo->ssi_signo = tswap32(sig);
> + tinfo->ssi_errno = tswap32(tinfo->ssi_errno);
> + tinfo->ssi_code = tswap32(info->ssi_code);
> + tinfo->ssi_pid = tswap32(info->ssi_pid);
> + tinfo->ssi_uid = tswap32(info->ssi_uid);
> + tinfo->ssi_fd = tswap32(info->ssi_fd);
> + tinfo->ssi_tid = tswap32(info->ssi_tid);
> + tinfo->ssi_band = tswap32(info->ssi_band);
> + tinfo->ssi_overrun = tswap32(info->ssi_overrun);
> + tinfo->ssi_trapno = tswap32(info->ssi_trapno);
> + tinfo->ssi_status = tswap32(info->ssi_status);
> + tinfo->ssi_int = tswap32(info->ssi_int);
> + tinfo->ssi_ptr = tswap64(info->ssi_ptr);
> + tinfo->ssi_utime = tswap64(info->ssi_utime);
> + tinfo->ssi_stime = tswap64(info->ssi_stime);
> + tinfo->ssi_addr = tswap64(info->ssi_addr);
> +}
> +
> +static abi_long host_to_target_signalfd(void *buf, size_t len)
> +{
> + int i;
> +
> + for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) {
> + host_to_target_signalfd_siginfo(buf + i, buf + i);
> + }
> +
> + return len;
> +}
> +
> +static TargetFdTrans target_signalfd_trans = {
> + .host_to_target = host_to_target_signalfd,
> +};
> +
> +static abi_long do_signalfd4(int fd, abi_long mask, int flags)
> +{
> + int host_flags;
> + target_sigset_t *target_mask;
> + sigset_t host_mask;
> + abi_long ret;
> +
> + if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
> + return -TARGET_EINVAL;
> + }
> + if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
> + return -TARGET_EFAULT;
> + }
> +
> + target_to_host_sigset(&host_mask, target_mask);
> +
> + host_flags = target_to_host_bitmask(flags, fcntl_flags_tbl);
> +
> + ret = get_errno(signalfd(fd, &host_mask, host_flags));
> + if (ret >= 0) {
> + fd_trans_register(ret, &target_signalfd_trans);
> + }
> +
> + unlock_user_struct(target_mask, mask, 0);
> +
> + return ret;
> +}
> +#endif
>
> /* Map host to target signal numbers for the wait family of syscalls.
> Assume all other status bits are the same. */
> @@ -5630,6 +5764,10 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
> arg1,
> if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0)))
> goto efault;
> ret = get_errno(read(arg1, p, arg3));
> + if (ret >= 0 &&
> + fd_trans_host_to_target(arg1)) {
> + ret = fd_trans_host_to_target(arg1)(p, ret);
> + }
> unlock_user(p, arg2, ret);
> }
> break;
> @@ -5645,6 +5783,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
> arg1,
> ret = get_errno(do_openat(cpu_env, AT_FDCWD, p,
> target_to_host_bitmask(arg2,
> fcntl_flags_tbl),
> arg3));
> + fd_trans_unregister(ret);
> unlock_user(p, arg1, 0);
> break;
> case TARGET_NR_openat:
> @@ -5653,9 +5792,11 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
> arg1,
> ret = get_errno(do_openat(cpu_env, arg1, p,
> target_to_host_bitmask(arg3,
> fcntl_flags_tbl),
> arg4));
> + fd_trans_unregister(ret);
> unlock_user(p, arg2, 0);
> break;
> case TARGET_NR_close:
> + fd_trans_unregister(arg1);
> ret = get_errno(close(arg1));
> break;
> case TARGET_NR_brk:
> @@ -5695,6 +5836,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
> arg1,
> if (!(p = lock_user_string(arg1)))
> goto efault;
> ret = get_errno(creat(p, arg2));
> + fd_trans_unregister(ret);
> unlock_user(p, arg1, 0);
> break;
> #endif
> @@ -6130,6 +6272,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
> arg1,
> break;
> case TARGET_NR_dup:
> ret = get_errno(dup(arg1));
> + if (ret >= 0) {
> + fd_trans_dup(arg1, ret);
> + }
> break;
> case TARGET_NR_pipe:
> ret = do_pipe(cpu_env, arg1, 0, 0);
> @@ -6222,10 +6367,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
> arg1,
> goto unimplemented;
> case TARGET_NR_dup2:
> ret = get_errno(dup2(arg1, arg2));
> + if (ret >= 0) {
> + fd_trans_dup(arg1, arg2);
> + }
> break;
> #if defined(CONFIG_DUP3) && defined(TARGET_NR_dup3)
> case TARGET_NR_dup3:
> ret = get_errno(dup3(arg1, arg2, arg3));
> + if (ret >= 0) {
> + fd_trans_dup(arg1, arg2);
> + }
> break;
> #endif
> #ifdef TARGET_NR_getppid /* not on alpha */
> @@ -7215,6 +7366,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
> arg1,
> #ifdef TARGET_NR_socket
> case TARGET_NR_socket:
> ret = do_socket(arg1, arg2, arg3);
> + fd_trans_unregister(ret);
> break;
> #endif
> #ifdef TARGET_NR_socketpair
> @@ -9454,6 +9606,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
> arg1,
> #if defined(TARGET_NR_eventfd)
> case TARGET_NR_eventfd:
> ret = get_errno(eventfd(arg1, 0));
> + fd_trans_unregister(ret);
> break;
> #endif
> #if defined(TARGET_NR_eventfd2)
> @@ -9467,6 +9620,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
> arg1,
> host_flags |= O_CLOEXEC;
> }
> ret = get_errno(eventfd(arg1, host_flags));
> + fd_trans_unregister(ret);
> break;
> }
> #endif
> @@ -9509,6 +9663,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
> arg1,
> break;
> #endif
> #endif
> +#if defined(TARGET_NR_signalfd4)
> + case TARGET_NR_signalfd4:
> + ret = do_signalfd4(arg1, arg2, arg4);
> + break;
> +#endif
> +#if defined(TARGET_NR_signalfd)
> + case TARGET_NR_signalfd:
> + ret = do_signalfd4(arg1, arg2, 0);
> + break;
> +#endif
> #if defined(CONFIG_EPOLL)
> #if defined(TARGET_NR_epoll_create)
> case TARGET_NR_epoll_create:
> @@ -9780,6 +9944,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
> arg1,
> timer_t htimer = g_posix_timers[timerid];
> ret = get_errno(timer_getoverrun(htimer));
> }
> + fd_trans_unregister(ret);
> break;
> }
> #endif
> --
> 2.4.3
>
>
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: [Qemu-devel] [PATCH v3] linux-user: add signalfd/signalfd4 syscalls,
Riku Voipio <=