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 20struct sigfd_compat_info 21{ 22 sigset_t mask; 23 int fd; 24}; 25 26static 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 70static 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 101int 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 114int 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