Provide generic services for binary events. Blocking wait would be feasible but is not included yet as there are no users.
Signed-off-by: Jan Kiszka <jan.kis...@siemens.com> --- Makefile | 2 +- Makefile.objs | 5 ++- qemu-event-posix.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++ qemu-event-win32.c | 65 ++++++++++++++++++++++++++++++ qemu-thread-posix.h | 5 ++ qemu-thread-win32.h | 4 ++ qemu-thread.h | 12 ++++++ 7 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 qemu-event-posix.c create mode 100644 qemu-event-win32.c diff --git a/Makefile b/Makefile index 35c7a2a..ea127f9 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ endif qemu-img.o: qemu-img-cmds.h qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o qemu-ga.o: $(GENERATED_HEADERS) -tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \ +tools-obj-y = $(oslib-obj-y) $(event-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \ qemu-timer-common.o main-loop.o notify.o iohandler.o cutils.o async.o tools-obj-$(CONFIG_POSIX) += compatfd.o diff --git a/Makefile.objs b/Makefile.objs index f308b57..377bfe2 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -24,6 +24,9 @@ oslib-obj-y = osdep.o oslib-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o +event-obj-$(CONFIG_POSIX) = qemu-event-posix.o +event-obj-$(CONFIG_WIN32) = qemu-event-win32.o + ####################################################################### # coroutines coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o @@ -97,7 +100,7 @@ common-obj-y += $(net-obj-y) common-obj-y += $(qom-obj-twice-y) common-obj-$(CONFIG_LINUX) += $(fsdev-obj-$(CONFIG_LINUX)) common-obj-y += readline.o console.o cursor.o -common-obj-y += $(oslib-obj-y) +common-obj-y += $(oslib-obj-y) $(event-obj-y) common-obj-$(CONFIG_WIN32) += os-win32.o common-obj-$(CONFIG_POSIX) += os-posix.o diff --git a/qemu-event-posix.c b/qemu-event-posix.c new file mode 100644 index 0000000..6138168 --- /dev/null +++ b/qemu-event-posix.c @@ -0,0 +1,110 @@ +/* + * Posix implementations of event signaling service + * + * Copyright Red Hat, Inc. 2012 + * Copyright Siemens AG 2012 + * + * Author: + * Paolo Bonzini <pbonz...@redhat.com> + * Jan Kiszka <jan.kis...@siemens.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ +#include "qemu-thread.h" +#include "qemu-common.h" +#include "main-loop.h" + +#ifdef CONFIG_EVENTFD +#include <sys/eventfd.h> +#endif + +void qemu_event_init(QemuEvent *event, bool signaled) +{ + int fds[2]; + int ret; + +#ifdef CONFIG_EVENTFD + ret = eventfd(signaled, EFD_NONBLOCK | EFD_CLOEXEC); + if (ret >= 0) { + event->rfd = ret; + event->wfd = dup(ret); + if (event->wfd < 0) { + qemu_error_exit(errno, __func__); + } + qemu_set_cloexec(event->wfd); + return; + } + if (errno != ENOSYS) { + qemu_error_exit(errno, __func__); + } + /* fall back to pipe-based support */ +#endif + + ret = qemu_pipe(fds); + if (ret < 0) { + qemu_error_exit(errno, __func__); + } + event->rfd = fds[0]; + event->wfd = fds[1]; + if (signaled) { + qemu_event_signal(event); + } +} + +void qemu_event_destroy(QemuEvent *event) +{ + close(event->rfd); + close(event->wfd); +} + +int qemu_event_get_signal_fd(QemuEvent *event) +{ + return event->wfd; +} + +int qemu_event_get_poll_fd(QemuEvent *event) +{ + return event->rfd; +} + +void qemu_event_set_handler(QemuEvent *event, QemuEventHandler *handler, + void *opaque) +{ + qemu_set_fd_handler2(event->rfd, NULL, (IOHandler *)handler, NULL, opaque); +} + +void qemu_event_signal(QemuEvent *event) +{ + /* Write 8 bytes to be compatible with eventfd. */ + static const uint64_t val = 1; + ssize_t ret; + + do { + ret = write(event->wfd, &val, sizeof(val)); + } while (ret < 0 && errno == EINTR); + + if (ret < 0 && errno != EAGAIN) { + qemu_error_exit(errno, __func__); + } +} + +bool qemu_event_consume(QemuEvent *event) +{ + bool was_set = false; + uint64_t val; + int ret; + + while (1) { + ret = read(event->rfd, &val, sizeof(val)); + if (ret == sizeof(val)) { + was_set = true; + continue; + } + if (ret < 0 && errno == EAGAIN) { + return was_set; + } + qemu_error_exit(errno, __func__); + } +} diff --git a/qemu-event-win32.c b/qemu-event-win32.c new file mode 100644 index 0000000..38fe9ae --- /dev/null +++ b/qemu-event-win32.c @@ -0,0 +1,65 @@ +/* + * Win32 implementations of event signaling service + * + * Copyright Red Hat, Inc. 2012 + * Copyright Siemens AG 2012 + * + * Author: + * Paolo Bonzini <pbonz...@redhat.com> + * Jan Kiszka <jan.kis...@siemens.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ +#include <stdbool.h> +#include "qemu-thread.h" +#include "qemu-common.h" +#include "main-loop.h" + +void qemu_event_init(QemuEvent *event, bool signaled) +{ + event->event = CreateEvent(NULL, FALSE, signaled, NULL); + if (!event->event) { + qemu_error_exit(GetLastError(), __func__); + } +} + +void qemu_event_destroy(QemuEvent *event) +{ + CloseHandle(event->event); +} + +int qemu_event_get_signal_fd(QemuEvent *event) +{ + /* unsupported on Win32 */ + abort(); +} + +void qemu_event_set_handler(QemuEvent *event, QemuEventHandler *handler, + void *opaque) +{ + if (handler) { + qemu_add_wait_object(event->event, (IOHandler *)handler, opaque); + } else { + qemu_del_wait_object(event->event, (IOHandler *)handler, opaque); + } +} + +void qemu_event_signal(QemuEvent *event) +{ + if (!SetEvent(event->event)) { + qemu_error_exit(GetLastError(), __func__); + } +} + +bool qemu_event_consume(QemuEvent *event) +{ + DWORD ret; + + ret = WaitForSingleObject(event->event, 0); + if (ret == WAIT_FAILED) { + qemu_error_exit(GetLastError(), __func__); + } + return ret == WAIT_OBJECT_0; +} diff --git a/qemu-thread-posix.h b/qemu-thread-posix.h index 9f00524..95fbb45 100644 --- a/qemu-thread-posix.h +++ b/qemu-thread-posix.h @@ -11,6 +11,11 @@ struct QemuCond { pthread_cond_t cond; }; +struct QemuEvent { + int rfd; + int wfd; +}; + struct QemuThread { pthread_t thread; }; diff --git a/qemu-thread-win32.h b/qemu-thread-win32.h index b9d1be8..d1b7631 100644 --- a/qemu-thread-win32.h +++ b/qemu-thread-win32.h @@ -13,6 +13,10 @@ struct QemuCond { HANDLE continue_event; }; +struct QemuEvent { + HANDLE event; +}; + typedef struct QemuThreadData QemuThreadData; struct QemuThread { QemuThreadData *data; diff --git a/qemu-thread.h b/qemu-thread.h index 10f2c51..a53384f 100644 --- a/qemu-thread.h +++ b/qemu-thread.h @@ -5,8 +5,11 @@ typedef struct QemuMutex QemuMutex; typedef struct QemuCond QemuCond; +typedef struct QemuEvent QemuEvent; typedef struct QemuThread QemuThread; +typedef void QemuEventHandler(void *opaque); + #ifdef _WIN32 #include "qemu-thread-win32.h" #else @@ -28,6 +31,15 @@ void qemu_mutex_unlock(QemuMutex *mutex); void qemu_cond_init(QemuCond *cond); void qemu_cond_destroy(QemuCond *cond); +void qemu_event_init(QemuEvent *event, bool signaled); +void qemu_event_destroy(QemuEvent *event); +int qemu_event_get_signal_fd(QemuEvent *event); +int qemu_event_get_poll_fd(QemuEvent *event); +void qemu_event_set_handler(QemuEvent *event, QemuEventHandler *handler, + void *opaque); +void qemu_event_signal(QemuEvent *event); +bool qemu_event_consume(QemuEvent *event); + /* * IMPORTANT: The implementation does not guarantee that pthread_cond_signal * and pthread_cond_broadcast can be called except while the same mutex is -- 1.7.3.4