• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
sigwait_compat(void * opaque)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 
qemu_signalfd_compat(const sigset_t * mask)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 
qemu_signalfd(const sigset_t * mask)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 
qemu_eventfd(int * fds)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 }
129