Tizen 2.0 Release
[sdk/emulator/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     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     sigset_t mask;
123     int fd;
124     bool ok;
125     sigemptyset(&mask);
126     errno = 0;
127     fd = syscall(SYS_signalfd, -1, &mask, _NSIG / 8);
128     ok = (errno != ENOSYS);
129     if (fd >= 0) {
130         close(fd);
131     }
132     return ok;
133 #else
134     return false;
135 #endif
136 }