Statistics
| Branch: | Revision:

root / compatfd.c @ d25f89c9

History | View | Annotate | Download (2.5 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
 */
13

    
14
#include "qemu-common.h"
15
#include "compatfd.h"
16

    
17
#include <sys/syscall.h>
18
#include <pthread.h>
19

    
20
struct sigfd_compat_info
21
{
22
    sigset_t mask;
23
    int fd;
24
};
25

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

    
31
    sigfillset(&all);
32
    pthread_sigmask(SIG_BLOCK, &all, NULL);
33

    
34
    while (1) {
35
        int sig;
36
        int err;
37

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

    
49
            memset(&buffer, 0, sizeof(buffer));
50
            buffer.ssi_signo = sig;
51

    
52
            while (offset < sizeof(buffer)) {
53
                ssize_t len;
54

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

    
60
                if (len <= 0) {
61
                    return NULL;
62
                }
63

    
64
                offset += len;
65
            }
66
        }
67
    }
68
}
69

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

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

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

    
88
    qemu_set_cloexec(fds[0]);
89
    qemu_set_cloexec(fds[1]);
90

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

    
94
    pthread_attr_init(&attr);
95
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
96

    
97
    pthread_create(&tid, &attr, sigwait_compat, info);
98

    
99
    pthread_attr_destroy(&attr);
100

    
101
    return fds[0];
102
}
103

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

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

    
116
    return qemu_signalfd_compat(mask);
117
}
118

    
119
bool qemu_signalfd_available(void)
120
{
121
#ifdef CONFIG_SIGNALFD
122
    errno = 0;
123
    syscall(SYS_signalfd, -1, NULL, _NSIG / 8);
124
    return errno != ENOSYS;
125
#else
126
    return false;
127
#endif
128
}