Statistics
| Branch: | Revision:

root / compatfd.c @ 1b902f7d

History | View | Annotate | Download (2.8 kB)

1
/*
2
 * signalfd/eventfd compatibility
3
 *
4
 * Copyright IBM, Corp. 2008
5
 *
6
 * Authors:
7
 *  Anthony Liguori   <aliguori@us.ibm.com>
8
 *
9
 * This work is licensed under the terms of the GNU GPL, version 2.  See
10
 * the COPYING file in the top-level directory.
11
 *
12
 * Contributions after 2012-01-13 are licensed under the terms of the
13
 * GNU GPL, version 2 or (at your option) any later version.
14
 */
15

    
16
#include "qemu-common.h"
17
#include "compatfd.h"
18

    
19
#include <sys/syscall.h>
20
#include <pthread.h>
21

    
22
struct sigfd_compat_info
23
{
24
    sigset_t mask;
25
    int fd;
26
};
27

    
28
static void *sigwait_compat(void *opaque)
29
{
30
    struct sigfd_compat_info *info = opaque;
31
    sigset_t all;
32

    
33
    sigfillset(&all);
34
    pthread_sigmask(SIG_BLOCK, &all, NULL);
35

    
36
    while (1) {
37
        int sig;
38
        int err;
39

    
40
        err = sigwait(&info->mask, &sig);
41
        if (err != 0) {
42
            if (errno == EINTR) {
43
                continue;
44
            } else {
45
                return NULL;
46
            }
47
        } else {
48
            struct qemu_signalfd_siginfo buffer;
49
            size_t offset = 0;
50

    
51
            memset(&buffer, 0, sizeof(buffer));
52
            buffer.ssi_signo = sig;
53

    
54
            while (offset < sizeof(buffer)) {
55
                ssize_t len;
56

    
57
                len = write(info->fd, (char *)&buffer + offset,
58
                            sizeof(buffer) - offset);
59
                if (len == -1 && errno == EINTR)
60
                    continue;
61

    
62
                if (len <= 0) {
63
                    return NULL;
64
                }
65

    
66
                offset += len;
67
            }
68
        }
69
    }
70
}
71

    
72
static int qemu_signalfd_compat(const sigset_t *mask)
73
{
74
    pthread_attr_t attr;
75
    pthread_t tid;
76
    struct sigfd_compat_info *info;
77
    int fds[2];
78

    
79
    info = malloc(sizeof(*info));
80
    if (info == NULL) {
81
        errno = ENOMEM;
82
        return -1;
83
    }
84

    
85
    if (pipe(fds) == -1) {
86
        free(info);
87
        return -1;
88
    }
89

    
90
    qemu_set_cloexec(fds[0]);
91
    qemu_set_cloexec(fds[1]);
92

    
93
    memcpy(&info->mask, mask, sizeof(*mask));
94
    info->fd = fds[1];
95

    
96
    pthread_attr_init(&attr);
97
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
98

    
99
    pthread_create(&tid, &attr, sigwait_compat, info);
100

    
101
    pthread_attr_destroy(&attr);
102

    
103
    return fds[0];
104
}
105

    
106
int qemu_signalfd(const sigset_t *mask)
107
{
108
#if defined(CONFIG_SIGNALFD)
109
    int ret;
110

    
111
    ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);
112
    if (ret != -1) {
113
        qemu_set_cloexec(ret);
114
        return ret;
115
    }
116
#endif
117

    
118
    return qemu_signalfd_compat(mask);
119
}
120

    
121
bool qemu_signalfd_available(void)
122
{
123
#ifdef CONFIG_SIGNALFD
124
    sigset_t mask;
125
    int fd;
126
    bool ok;
127
    sigemptyset(&mask);
128
    errno = 0;
129
    fd = syscall(SYS_signalfd, -1, &mask, _NSIG / 8);
130
    ok = (errno != ENOSYS);
131
    if (fd >= 0) {
132
        close(fd);
133
    }
134
    return ok;
135
#else
136
    return false;
137
#endif
138
}