18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * signalfd/eventfd compatibility
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright IBM, Corp. 2008
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Authors:
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *  Anthony Liguori   <aliguori@us.ibm.com>
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * This work is licensed under the terms of the GNU GPL, version 2.  See
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * the COPYING file in the top-level directory.
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu-common.h"
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "compatfd.h"
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <sys/syscall.h>
188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <pthread.h>
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstruct sigfd_compat_info
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    sigset_t mask;
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int fd;
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void *sigwait_compat(void *opaque)
278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct sigfd_compat_info *info = opaque;
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    sigset_t all;
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    sigfillset(&all);
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    sigprocmask(SIG_BLOCK, &all, NULL);
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
34e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner    while (1) {
35e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner        int sig;
36e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner        int err;
37e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner
38e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner        err = sigwait(&info->mask, &sig);
39e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner        if (err != 0) {
40e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner            if (errno == EINTR) {
41e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner                continue;
42e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner            } else {
43e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner                return NULL;
44e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner            }
45e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner        } else {
46e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner            struct qemu_signalfd_siginfo buffer;
47e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner            size_t offset = 0;
48e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner
49e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner            memset(&buffer, 0, sizeof(buffer));
50e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner            buffer.ssi_signo = sig;
51e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner
52e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner            while (offset < sizeof(buffer)) {
53e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner                ssize_t len;
54e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner
55e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner                len = write(info->fd, (char *)&buffer + offset,
56e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner                            sizeof(buffer) - offset);
57e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner                if (len == -1 && errno == EINTR)
58e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner                    continue;
59e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner
60e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner                if (len <= 0) {
61e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner                    return NULL;
62e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner                }
63e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner
64e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner                offset += len;
65e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner            }
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
67e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner    }
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int qemu_signalfd_compat(const sigset_t *mask)
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pthread_attr_t attr;
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pthread_t tid;
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    struct sigfd_compat_info *info;
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int fds[2];
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    info = malloc(sizeof(*info));
788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (info == NULL) {
79e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner        errno = ENOMEM;
80e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner        return -1;
818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (pipe(fds) == -1) {
84e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner        free(info);
85e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner        return -1;
868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
88e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner    qemu_set_cloexec(fds[0]);
89e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner    qemu_set_cloexec(fds[1]);
90e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner
918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memcpy(&info->mask, mask, sizeof(*mask));
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    info->fd = fds[1];
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pthread_attr_init(&attr);
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pthread_create(&tid, &attr, sigwait_compat, info);
988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    pthread_attr_destroy(&attr);
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return fds[0];
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint qemu_signalfd(const sigset_t *mask)
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
106e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner#if defined(CONFIG_SIGNALFD)
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int ret;
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);
110e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner    if (ret != -1) {
111e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner        qemu_set_cloexec(ret);
112e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner        return ret;
113e49c3f3e66b4337859af7c1be013b076eb4de136David 'Digit' Turner    }
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return qemu_signalfd_compat(mask);
1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
118