Statistics
| Branch: | Revision:

root / compatfd.c @ bcdf9b4d

History | View | Annotate | Download (2.2 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
    int err;
30
    sigset_t all;
31

    
32
    sigfillset(&all);
33
    sigprocmask(SIG_BLOCK, &all, NULL);
34

    
35
    do {
36
        siginfo_t siginfo;
37

    
38
        err = sigwaitinfo(&info->mask, &siginfo);
39
        if (err == -1 && errno == EINTR) {
40
            err = 0;
41
            continue;
42
        }
43

    
44
        if (err > 0) {
45
            char buffer[128];
46
            size_t offset = 0;
47

    
48
            memcpy(buffer, &err, sizeof(err));
49
            while (offset < sizeof(buffer)) {
50
                ssize_t len;
51

    
52
                len = write(info->fd, buffer + offset,
53
                            sizeof(buffer) - offset);
54
                if (len == -1 && errno == EINTR)
55
                    continue;
56

    
57
                if (len <= 0) {
58
                    err = -1;
59
                    break;
60
                }
61

    
62
                offset += len;
63
            }
64
        }
65
    } while (err >= 0);
66

    
67
    return NULL;
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
    memcpy(&info->mask, mask, sizeof(*mask));
89
    info->fd = fds[1];
90

    
91
    pthread_attr_init(&attr);
92
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
93

    
94
    pthread_create(&tid, &attr, sigwait_compat, info);
95

    
96
    pthread_attr_destroy(&attr);
97

    
98
    return fds[0];
99
}
100

    
101
int qemu_signalfd(const sigset_t *mask)
102
{
103
#if defined(SYS_signalfd)
104
    int ret;
105

    
106
    ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);
107
    if (!(ret == -1 && errno == ENOSYS))
108
        return ret;
109
#endif
110

    
111
    return qemu_signalfd_compat(mask);
112
}
113

    
114
int qemu_eventfd(int *fds)
115
{
116
#if defined(SYS_eventfd)
117
    int ret;
118

    
119
    ret = syscall(SYS_eventfd, 0);
120
    if (ret >= 0) {
121
        fds[0] = fds[1] = ret;
122
        return 0;
123
    } else if (!(ret == -1 && errno == ENOSYS))
124
        return ret;
125
#endif
126

    
127
    return pipe(fds);
128
}