Statistics
| Branch: | Revision:

root / compatfd.c @ dcc38d1c

History | View | Annotate | Download (2.3 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
    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
}