support xattr syscall in qemu-arm
[external/qemu.git] / compatfd.c
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 }