Home | History | Annotate | Download | only in qemu
      1 /*
      2  * signalfd/eventfd compatibility
      3  *
      4  * Copyright IBM, Corp. 2008
      5  *
      6  * Authors:
      7  *  Anthony Liguori   <aliguori (at) 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     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 
    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 
    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