Merge remote-tracking branch 'bonzini/split-main-loop-for-anthony' into staging

This commit is contained in:
Anthony Liguori
2011-10-24 10:51:12 -05:00
23 changed files with 1318 additions and 1069 deletions
+1 -1
View File
@@ -81,7 +81,7 @@ common-obj-y += $(oslib-obj-y)
common-obj-$(CONFIG_WIN32) += os-win32.o
common-obj-$(CONFIG_POSIX) += os-posix.o
common-obj-y += tcg-runtime.o host-utils.o
common-obj-y += tcg-runtime.o host-utils.o main-loop.o
common-obj-y += irq.o input.o
common-obj-$(CONFIG_PTIMER) += ptimer.o
common-obj-$(CONFIG_MAX7310) += max7310.o
+1
View File
@@ -24,6 +24,7 @@
#include "qemu-common.h"
#include "qemu-aio.h"
#include "main-loop.h"
/* Anchor of the list of Bottom Halves belonging to the context */
static struct QEMUBH *first_bh;
+280 -217
View File
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -2,8 +2,7 @@
#define QEMU_CPUS_H
/* cpus.c */
int qemu_init_main_loop(void);
void qemu_main_loop_start(void);
void qemu_init_cpu_loop(void);
void resume_all_vcpus(void);
void pause_all_vcpus(void);
void cpu_stop_current(void);
+14
View File
@@ -356,4 +356,18 @@ extern int singlestep;
/* cpu-exec.c */
extern volatile sig_atomic_t exit_request;
/* Deterministic execution requires that IO only be performed on the last
instruction of a TB so that interrupts take effect immediately. */
static inline int can_do_io(CPUState *env)
{
if (!use_icount) {
return 1;
}
/* If not executing code then assume we are ok. */
if (!env->current_tb) {
return 1;
}
return env->can_do_io != 0;
}
#endif
-3
View File
@@ -125,9 +125,6 @@ CPUState *cpu_single_env;
1 = Precise instruction counting.
2 = Adaptive rate instruction counting. */
int use_icount = 0;
/* Current instruction counter. While executing translated code this may
include some instructions that have not yet been executed. */
int64_t qemu_icount;
typedef struct PageDesc {
/* list of TBs intersecting this ram page */
-5
View File
@@ -661,11 +661,6 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
ch->io.channel = ch;
}
void DBDMA_schedule(void)
{
qemu_notify_event();
}
static void
dbdma_control_write(DBDMA_channel *ch)
{
-1
View File
@@ -41,5 +41,4 @@ struct DBDMA_io {
void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
DBDMA_rw rw, DBDMA_flush flush,
void *opaque);
void DBDMA_schedule(void);
void* DBDMA_init (MemoryRegion **dbdma_mem);
+2 -53
View File
@@ -26,6 +26,7 @@
#include "qemu-common.h"
#include "qemu-char.h"
#include "qemu-queue.h"
#include "main-loop.h"
#ifndef _WIN32
#include <sys/wait.h>
@@ -80,64 +81,12 @@ int qemu_set_fd_handler2(int fd,
return 0;
}
typedef struct IOTrampoline
{
GIOChannel *chan;
IOHandler *fd_read;
IOHandler *fd_write;
void *opaque;
guint tag;
} IOTrampoline;
static gboolean fd_trampoline(GIOChannel *chan, GIOCondition cond, gpointer opaque)
{
IOTrampoline *tramp = opaque;
if ((cond & G_IO_IN) && tramp->fd_read) {
tramp->fd_read(tramp->opaque);
}
if ((cond & G_IO_OUT) && tramp->fd_write) {
tramp->fd_write(tramp->opaque);
}
return TRUE;
}
int qemu_set_fd_handler(int fd,
IOHandler *fd_read,
IOHandler *fd_write,
void *opaque)
{
static IOTrampoline fd_trampolines[FD_SETSIZE];
IOTrampoline *tramp = &fd_trampolines[fd];
if (tramp->tag != 0) {
g_io_channel_unref(tramp->chan);
g_source_remove(tramp->tag);
tramp->tag = 0;
}
if (fd_read || fd_write || opaque) {
GIOCondition cond = 0;
tramp->fd_read = fd_read;
tramp->fd_write = fd_write;
tramp->opaque = opaque;
if (fd_read) {
cond |= G_IO_IN | G_IO_ERR;
}
if (fd_write) {
cond |= G_IO_OUT | G_IO_ERR;
}
tramp->chan = g_io_channel_unix_new(fd);
tramp->tag = g_io_add_watch(tramp->chan, cond, fd_trampoline, tramp);
}
return 0;
return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
}
void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds)
+495
View File
@@ -0,0 +1,495 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "config-host.h"
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <errno.h>
#include <sys/time.h>
#include <stdbool.h>
#ifdef _WIN32
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/stat.h>
#include "compatfd.h"
#endif
#include <glib.h>
#include "main-loop.h"
#include "qemu-timer.h"
#include "slirp/libslirp.h"
#ifndef _WIN32
static int io_thread_fd = -1;
void qemu_notify_event(void)
{
/* Write 8 bytes to be compatible with eventfd. */
static const uint64_t val = 1;
ssize_t ret;
if (io_thread_fd == -1) {
return;
}
do {
ret = write(io_thread_fd, &val, sizeof(val));
} while (ret < 0 && errno == EINTR);
/* EAGAIN is fine, a read must be pending. */
if (ret < 0 && errno != EAGAIN) {
fprintf(stderr, "qemu_notify_event: write() failed: %s\n",
strerror(errno));
exit(1);
}
}
static void qemu_event_read(void *opaque)
{
int fd = (intptr_t)opaque;
ssize_t len;
char buffer[512];
/* Drain the notify pipe. For eventfd, only 8 bytes will be read. */
do {
len = read(fd, buffer, sizeof(buffer));
} while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
}
static int qemu_event_init(void)
{
int err;
int fds[2];
err = qemu_eventfd(fds);
if (err == -1) {
return -errno;
}
err = fcntl_setfl(fds[0], O_NONBLOCK);
if (err < 0) {
goto fail;
}
err = fcntl_setfl(fds[1], O_NONBLOCK);
if (err < 0) {
goto fail;
}
qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
(void *)(intptr_t)fds[0]);
io_thread_fd = fds[1];
return 0;
fail:
close(fds[0]);
close(fds[1]);
return err;
}
/* If we have signalfd, we mask out the signals we want to handle and then
* use signalfd to listen for them. We rely on whatever the current signal
* handler is to dispatch the signals when we receive them.
*/
static void sigfd_handler(void *opaque)
{
int fd = (intptr_t)opaque;
struct qemu_signalfd_siginfo info;
struct sigaction action;
ssize_t len;
while (1) {
do {
len = read(fd, &info, sizeof(info));
} while (len == -1 && errno == EINTR);
if (len == -1 && errno == EAGAIN) {
break;
}
if (len != sizeof(info)) {
printf("read from sigfd returned %zd: %m\n", len);
return;
}
sigaction(info.ssi_signo, NULL, &action);
if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) {
action.sa_sigaction(info.ssi_signo,
(siginfo_t *)&info, NULL);
} else if (action.sa_handler) {
action.sa_handler(info.ssi_signo);
}
}
}
static int qemu_signal_init(void)
{
int sigfd;
sigset_t set;
/*
* SIG_IPI must be blocked in the main thread and must not be caught
* by sigwait() in the signal thread. Otherwise, the cpu thread will
* not catch it reliably.
*/
sigemptyset(&set);
sigaddset(&set, SIG_IPI);
pthread_sigmask(SIG_BLOCK, &set, NULL);
sigemptyset(&set);
sigaddset(&set, SIGIO);
sigaddset(&set, SIGALRM);
sigaddset(&set, SIGBUS);
pthread_sigmask(SIG_BLOCK, &set, NULL);
sigfd = qemu_signalfd(&set);
if (sigfd == -1) {
fprintf(stderr, "failed to create signalfd\n");
return -errno;
}
fcntl_setfl(sigfd, O_NONBLOCK);
qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL,
(void *)(intptr_t)sigfd);
return 0;
}
#else /* _WIN32 */
HANDLE qemu_event_handle;
static void dummy_event_handler(void *opaque)
{
}
static int qemu_event_init(void)
{
qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!qemu_event_handle) {
fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
return -1;
}
qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
return 0;
}
void qemu_notify_event(void)
{
if (!SetEvent(qemu_event_handle)) {
fprintf(stderr, "qemu_notify_event: SetEvent failed: %ld\n",
GetLastError());
exit(1);
}
}
static int qemu_signal_init(void)
{
return 0;
}
#endif
int qemu_init_main_loop(void)
{
int ret;
qemu_mutex_lock_iothread();
ret = qemu_signal_init();
if (ret) {
return ret;
}
/* Note eventfd must be drained before signalfd handlers run */
ret = qemu_event_init();
if (ret) {
return ret;
}
return 0;
}
static GPollFD poll_fds[1024 * 2]; /* this is probably overkill */
static int n_poll_fds;
static int max_priority;
static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
fd_set *xfds, struct timeval *tv)
{
GMainContext *context = g_main_context_default();
int i;
int timeout = 0, cur_timeout;
g_main_context_prepare(context, &max_priority);
n_poll_fds = g_main_context_query(context, max_priority, &timeout,
poll_fds, ARRAY_SIZE(poll_fds));
g_assert(n_poll_fds <= ARRAY_SIZE(poll_fds));
for (i = 0; i < n_poll_fds; i++) {
GPollFD *p = &poll_fds[i];
if ((p->events & G_IO_IN)) {
FD_SET(p->fd, rfds);
*max_fd = MAX(*max_fd, p->fd);
}
if ((p->events & G_IO_OUT)) {
FD_SET(p->fd, wfds);
*max_fd = MAX(*max_fd, p->fd);
}
if ((p->events & G_IO_ERR)) {
FD_SET(p->fd, xfds);
*max_fd = MAX(*max_fd, p->fd);
}
}
cur_timeout = (tv->tv_sec * 1000) + ((tv->tv_usec + 500) / 1000);
if (timeout >= 0 && timeout < cur_timeout) {
tv->tv_sec = timeout / 1000;
tv->tv_usec = (timeout % 1000) * 1000;
}
}
static void glib_select_poll(fd_set *rfds, fd_set *wfds, fd_set *xfds,
bool err)
{
GMainContext *context = g_main_context_default();
if (!err) {
int i;
for (i = 0; i < n_poll_fds; i++) {
GPollFD *p = &poll_fds[i];
if ((p->events & G_IO_IN) && FD_ISSET(p->fd, rfds)) {
p->revents |= G_IO_IN;
}
if ((p->events & G_IO_OUT) && FD_ISSET(p->fd, wfds)) {
p->revents |= G_IO_OUT;
}
if ((p->events & G_IO_ERR) && FD_ISSET(p->fd, xfds)) {
p->revents |= G_IO_ERR;
}
}
}
if (g_main_context_check(context, max_priority, poll_fds, n_poll_fds)) {
g_main_context_dispatch(context);
}
}
#ifdef _WIN32
/***********************************************************/
/* Polling handling */
typedef struct PollingEntry {
PollingFunc *func;
void *opaque;
struct PollingEntry *next;
} PollingEntry;
static PollingEntry *first_polling_entry;
int qemu_add_polling_cb(PollingFunc *func, void *opaque)
{
PollingEntry **ppe, *pe;
pe = g_malloc0(sizeof(PollingEntry));
pe->func = func;
pe->opaque = opaque;
for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
*ppe = pe;
return 0;
}
void qemu_del_polling_cb(PollingFunc *func, void *opaque)
{
PollingEntry **ppe, *pe;
for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
pe = *ppe;
if (pe->func == func && pe->opaque == opaque) {
*ppe = pe->next;
g_free(pe);
break;
}
}
}
/***********************************************************/
/* Wait objects support */
typedef struct WaitObjects {
int num;
HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
} WaitObjects;
static WaitObjects wait_objects = {0};
int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
{
WaitObjects *w = &wait_objects;
if (w->num >= MAXIMUM_WAIT_OBJECTS) {
return -1;
}
w->events[w->num] = handle;
w->func[w->num] = func;
w->opaque[w->num] = opaque;
w->num++;
return 0;
}
void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
{
int i, found;
WaitObjects *w = &wait_objects;
found = 0;
for (i = 0; i < w->num; i++) {
if (w->events[i] == handle) {
found = 1;
}
if (found) {
w->events[i] = w->events[i + 1];
w->func[i] = w->func[i + 1];
w->opaque[i] = w->opaque[i + 1];
}
}
if (found) {
w->num--;
}
}
static void os_host_main_loop_wait(int *timeout)
{
int ret, ret2, i;
PollingEntry *pe;
/* XXX: need to suppress polling by better using win32 events */
ret = 0;
for (pe = first_polling_entry; pe != NULL; pe = pe->next) {
ret |= pe->func(pe->opaque);
}
if (ret == 0) {
int err;
WaitObjects *w = &wait_objects;
qemu_mutex_unlock_iothread();
ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
qemu_mutex_lock_iothread();
if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
if (w->func[ret - WAIT_OBJECT_0]) {
w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
}
/* Check for additional signaled events */
for (i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
/* Check if event is signaled */
ret2 = WaitForSingleObject(w->events[i], 0);
if (ret2 == WAIT_OBJECT_0) {
if (w->func[i]) {
w->func[i](w->opaque[i]);
}
} else if (ret2 != WAIT_TIMEOUT) {
err = GetLastError();
fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
}
}
} else if (ret != WAIT_TIMEOUT) {
err = GetLastError();
fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
}
}
*timeout = 0;
}
#else
static inline void os_host_main_loop_wait(int *timeout)
{
}
#endif
int main_loop_wait(int nonblocking)
{
fd_set rfds, wfds, xfds;
int ret, nfds;
struct timeval tv;
int timeout;
if (nonblocking) {
timeout = 0;
} else {
timeout = qemu_calculate_timeout();
qemu_bh_update_timeout(&timeout);
}
os_host_main_loop_wait(&timeout);
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
/* poll any events */
/* XXX: separate device handlers from system ones */
nfds = -1;
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&xfds);
#ifdef CONFIG_SLIRP
slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
#endif
qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
glib_select_fill(&nfds, &rfds, &wfds, &xfds, &tv);
if (timeout > 0) {
qemu_mutex_unlock_iothread();
}
ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
if (timeout > 0) {
qemu_mutex_lock_iothread();
}
glib_select_poll(&rfds, &wfds, &xfds, (ret < 0));
qemu_iohandler_poll(&rfds, &wfds, &xfds, ret);
#ifdef CONFIG_SLIRP
slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
#endif
qemu_run_all_timers();
/* Check bottom-halves last in case any of the earlier events triggered
them. */
qemu_bh_poll();
return ret;
}
+351
View File
@@ -0,0 +1,351 @@
/*
* QEMU System Emulator
*
* Copyright (c) 2003-2008 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_MAIN_LOOP_H
#define QEMU_MAIN_LOOP_H 1
#ifdef SIGRTMIN
#define SIG_IPI (SIGRTMIN+4)
#else
#define SIG_IPI SIGUSR1
#endif
/**
* qemu_init_main_loop: Set up the process so that it can run the main loop.
*
* This includes setting up signal handlers. It should be called before
* any other threads are created. In addition, threads other than the
* main one should block signals that are trapped by the main loop.
* For simplicity, you can consider these signals to be safe: SIGUSR1,
* SIGUSR2, thread signals (SIGFPE, SIGILL, SIGSEGV, SIGBUS) and real-time
* signals if available. Remember that Windows in practice does not have
* signals, though.
*/
int qemu_init_main_loop(void);
/**
* main_loop_wait: Run one iteration of the main loop.
*
* If @nonblocking is true, poll for events, otherwise suspend until
* one actually occurs. The main loop usually consists of a loop that
* repeatedly calls main_loop_wait(false).
*
* Main loop services include file descriptor callbacks, bottom halves
* and timers (defined in qemu-timer.h). Bottom halves are similar to timers
* that execute immediately, but have a lower overhead and scheduling them
* is wait-free, thread-safe and signal-safe.
*
* It is sometimes useful to put a whole program in a coroutine. In this
* case, the coroutine actually should be started from within the main loop,
* so that the main loop can run whenever the coroutine yields. To do this,
* you can use a bottom half to enter the coroutine as soon as the main loop
* starts:
*
* void enter_co_bh(void *opaque) {
* QEMUCoroutine *co = opaque;
* qemu_coroutine_enter(co, NULL);
* }
*
* ...
* QEMUCoroutine *co = qemu_coroutine_create(coroutine_entry);
* QEMUBH *start_bh = qemu_bh_new(enter_co_bh, co);
* qemu_bh_schedule(start_bh);
* while (...) {
* main_loop_wait(false);
* }
*
* (In the future we may provide a wrapper for this).
*
* @nonblocking: Whether the caller should block until an event occurs.
*/
int main_loop_wait(int nonblocking);
/**
* qemu_notify_event: Force processing of pending events.
*
* Similar to signaling a condition variable, qemu_notify_event forces
* main_loop_wait to look at pending events and exit. The caller of
* main_loop_wait will usually call it again very soon, so qemu_notify_event
* also has the side effect of recalculating the sets of file descriptors
* that the main loop waits for.
*
* Calling qemu_notify_event is rarely necessary, because main loop
* services (bottom halves and timers) call it themselves. One notable
* exception occurs when using qemu_set_fd_handler2 (see below).
*/
void qemu_notify_event(void);
#ifdef _WIN32
/* return TRUE if no sleep should be done afterwards */
typedef int PollingFunc(void *opaque);
/**
* qemu_add_polling_cb: Register a Windows-specific polling callback
*
* Currently, under Windows some events are polled rather than waited for.
* Polling callbacks do not ensure that @func is called timely, because
* the main loop might wait for an arbitrarily long time. If possible,
* you should instead create a separate thread that does a blocking poll
* and set a Win32 event object. The event can then be passed to
* qemu_add_wait_object.
*
* Polling callbacks really have nothing Windows specific in them, but
* as they are a hack and are currenly not necessary under POSIX systems,
* they are only available when QEMU is running under Windows.
*
* @func: The function that does the polling, and returns 1 to force
* immediate completion of main_loop_wait.
* @opaque: A pointer-size value that is passed to @func.
*/
int qemu_add_polling_cb(PollingFunc *func, void *opaque);
/**
* qemu_del_polling_cb: Unregister a Windows-specific polling callback
*
* This function removes a callback that was registered with
* qemu_add_polling_cb.
*
* @func: The function that was passed to qemu_add_polling_cb.
* @opaque: A pointer-size value that was passed to qemu_add_polling_cb.
*/
void qemu_del_polling_cb(PollingFunc *func, void *opaque);
/* Wait objects handling */
typedef void WaitObjectFunc(void *opaque);
/**
* qemu_add_wait_object: Register a callback for a Windows handle
*
* Under Windows, the iohandler mechanism can only be used with sockets.
* QEMU must use the WaitForMultipleObjects API to wait on other handles.
* This function registers a #HANDLE with QEMU, so that it will be included
* in the main loop's calls to WaitForMultipleObjects. When the handle
* is in a signaled state, QEMU will call @func.
*
* @handle: The Windows handle to be observed.
* @func: A function to be called when @handle is in a signaled state.
* @opaque: A pointer-size value that is passed to @func.
*/
int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
/**
* qemu_del_wait_object: Unregister a callback for a Windows handle
*
* This function removes a callback that was registered with
* qemu_add_wait_object.
*
* @func: The function that was passed to qemu_add_wait_object.
* @opaque: A pointer-size value that was passed to qemu_add_wait_object.
*/
void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
#endif
/* async I/O support */
typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
typedef int IOCanReadHandler(void *opaque);
typedef void IOHandler(void *opaque);
/**
* qemu_set_fd_handler2: Register a file descriptor with the main loop
*
* This function tells the main loop to wake up whenever one of the
* following conditions is true:
*
* 1) if @fd_write is not %NULL, when the file descriptor is writable;
*
* 2) if @fd_read is not %NULL, when the file descriptor is readable.
*
* @fd_read_poll can be used to disable the @fd_read callback temporarily.
* This is useful to avoid calling qemu_set_fd_handler2 every time the
* client becomes interested in reading (or dually, stops being interested).
* A typical example is when @fd is a listening socket and you want to bound
* the number of active clients. Remember to call qemu_notify_event whenever
* the condition may change from %false to %true.
*
* The callbacks that are set up by qemu_set_fd_handler2 are level-triggered.
* If @fd_read does not read from @fd, or @fd_write does not write to @fd
* until its buffers are full, they will be called again on the next
* iteration.
*
* @fd: The file descriptor to be observed. Under Windows it must be
* a #SOCKET.
*
* @fd_read_poll: A function that returns 1 if the @fd_read callback
* should be fired. If the function returns 0, the main loop will not
* end its iteration even if @fd becomes readable.
*
* @fd_read: A level-triggered callback that is fired if @fd is readable
* at the beginning of a main loop iteration, or if it becomes readable
* during one.
*
* @fd_write: A level-triggered callback that is fired when @fd is writable
* at the beginning of a main loop iteration, or if it becomes writable
* during one.
*
* @opaque: A pointer-sized value that is passed to @fd_read_poll,
* @fd_read and @fd_write.
*/
int qemu_set_fd_handler2(int fd,
IOCanReadHandler *fd_read_poll,
IOHandler *fd_read,
IOHandler *fd_write,
void *opaque);
/**
* qemu_set_fd_handler: Register a file descriptor with the main loop
*
* This function tells the main loop to wake up whenever one of the
* following conditions is true:
*
* 1) if @fd_write is not %NULL, when the file descriptor is writable;
*
* 2) if @fd_read is not %NULL, when the file descriptor is readable.
*
* The callbacks that are set up by qemu_set_fd_handler are level-triggered.
* If @fd_read does not read from @fd, or @fd_write does not write to @fd
* until its buffers are full, they will be called again on the next
* iteration.
*
* @fd: The file descriptor to be observed. Under Windows it must be
* a #SOCKET.
*
* @fd_read: A level-triggered callback that is fired if @fd is readable
* at the beginning of a main loop iteration, or if it becomes readable
* during one.
*
* @fd_write: A level-triggered callback that is fired when @fd is writable
* at the beginning of a main loop iteration, or if it becomes writable
* during one.
*
* @opaque: A pointer-sized value that is passed to @fd_read and @fd_write.
*/
int qemu_set_fd_handler(int fd,
IOHandler *fd_read,
IOHandler *fd_write,
void *opaque);
typedef struct QEMUBH QEMUBH;
typedef void QEMUBHFunc(void *opaque);
/**
* qemu_bh_new: Allocate a new bottom half structure.
*
* Bottom halves are lightweight callbacks whose invocation is guaranteed
* to be wait-free, thread-safe and signal-safe. The #QEMUBH structure
* is opaque and must be allocated prior to its use.
*/
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
/**
* qemu_bh_schedule: Schedule a bottom half.
*
* Scheduling a bottom half interrupts the main loop and causes the
* execution of the callback that was passed to qemu_bh_new.
*
* Bottom halves that are scheduled from a bottom half handler are instantly
* invoked. This can create an infinite loop if a bottom half handler
* schedules itself.
*
* @bh: The bottom half to be scheduled.
*/
void qemu_bh_schedule(QEMUBH *bh);
/**
* qemu_bh_cancel: Cancel execution of a bottom half.
*
* Canceling execution of a bottom half undoes the effect of calls to
* qemu_bh_schedule without freeing its resources yet. While cancellation
* itself is also wait-free and thread-safe, it can of course race with the
* loop that executes bottom halves unless you are holding the iothread
* mutex. This makes it mostly useless if you are not holding the mutex.
*
* @bh: The bottom half to be canceled.
*/
void qemu_bh_cancel(QEMUBH *bh);
/**
*qemu_bh_delete: Cancel execution of a bottom half and free its resources.
*
* Deleting a bottom half frees the memory that was allocated for it by
* qemu_bh_new. It also implies canceling the bottom half if it was
* scheduled.
*
* @bh: The bottom half to be deleted.
*/
void qemu_bh_delete(QEMUBH *bh);
#ifdef CONFIG_POSIX
/**
* qemu_add_child_watch: Register a child process for reaping.
*
* Under POSIX systems, a parent process must read the exit status of
* its child processes using waitpid, or the operating system will not
* free some of the resources attached to that process.
*
* This function directs the QEMU main loop to observe a child process
* and call waitpid as soon as it exits; the watch is then removed
* automatically. It is useful whenever QEMU forks a child process
* but will find out about its termination by other means such as a
* "broken pipe".
*
* @pid: The pid that QEMU should observe.
*/
int qemu_add_child_watch(pid_t pid);
#endif
/**
* qemu_mutex_lock_iothread: Lock the main loop mutex.
*
* This function locks the main loop mutex. The mutex is taken by
* qemu_init_main_loop and always taken except while waiting on
* external events (such as with select). The mutex should be taken
* by threads other than the main loop thread when calling
* qemu_bh_new(), qemu_set_fd_handler() and basically all other
* functions documented in this file.
*/
void qemu_mutex_lock_iothread(void);
/**
* qemu_mutex_unlock_iothread: Unlock the main loop mutex.
*
* This function unlocks the main loop mutex. The mutex is taken by
* qemu_init_main_loop and always taken except while waiting on
* external events (such as with select). The mutex should be unlocked
* as soon as possible by threads other than the main loop thread,
* because it prevents the main loop from processing callbacks,
* including timers and bottom halves.
*/
void qemu_mutex_unlock_iothread(void);
/* internal interfaces */
void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds);
void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc);
void qemu_bh_schedule_idle(QEMUBH *bh);
int qemu_bh_poll(void);
void qemu_bh_update_timeout(int *timeout);
#endif
-123
View File
@@ -48,129 +48,6 @@ int setenv(const char *name, const char *value, int overwrite)
return result;
}
/***********************************************************/
/* Polling handling */
typedef struct PollingEntry {
PollingFunc *func;
void *opaque;
struct PollingEntry *next;
} PollingEntry;
static PollingEntry *first_polling_entry;
int qemu_add_polling_cb(PollingFunc *func, void *opaque)
{
PollingEntry **ppe, *pe;
pe = g_malloc0(sizeof(PollingEntry));
pe->func = func;
pe->opaque = opaque;
for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
*ppe = pe;
return 0;
}
void qemu_del_polling_cb(PollingFunc *func, void *opaque)
{
PollingEntry **ppe, *pe;
for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
pe = *ppe;
if (pe->func == func && pe->opaque == opaque) {
*ppe = pe->next;
g_free(pe);
break;
}
}
}
/***********************************************************/
/* Wait objects support */
typedef struct WaitObjects {
int num;
HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
} WaitObjects;
static WaitObjects wait_objects = {0};
int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
{
WaitObjects *w = &wait_objects;
if (w->num >= MAXIMUM_WAIT_OBJECTS)
return -1;
w->events[w->num] = handle;
w->func[w->num] = func;
w->opaque[w->num] = opaque;
w->num++;
return 0;
}
void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
{
int i, found;
WaitObjects *w = &wait_objects;
found = 0;
for (i = 0; i < w->num; i++) {
if (w->events[i] == handle)
found = 1;
if (found) {
w->events[i] = w->events[i + 1];
w->func[i] = w->func[i + 1];
w->opaque[i] = w->opaque[i + 1];
}
}
if (found)
w->num--;
}
void os_host_main_loop_wait(int *timeout)
{
int ret, ret2, i;
PollingEntry *pe;
/* XXX: need to suppress polling by better using win32 events */
ret = 0;
for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
ret |= pe->func(pe->opaque);
}
if (ret == 0) {
int err;
WaitObjects *w = &wait_objects;
qemu_mutex_unlock_iothread();
ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
qemu_mutex_lock_iothread();
if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
if (w->func[ret - WAIT_OBJECT_0])
w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
/* Check for additional signaled events */
for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
/* Check if event is signaled */
ret2 = WaitForSingleObject(w->events[i], 0);
if(ret2 == WAIT_OBJECT_0) {
if (w->func[i])
w->func[i](w->opaque[i]);
} else if (ret2 == WAIT_TIMEOUT) {
} else {
err = GetLastError();
fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
}
}
} else if (ret == WAIT_TIMEOUT) {
} else {
err = GetLastError();
fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
}
}
*timeout = 0;
}
static BOOL WINAPI qemu_ctrl_handler(DWORD type)
{
exit(STATUS_CONTROL_C_EXIT);
+1 -11
View File
@@ -7,6 +7,7 @@
#include "qemu-config.h"
#include "qobject.h"
#include "qstring.h"
#include "main-loop.h"
/* character device */
@@ -237,15 +238,4 @@ void qemu_chr_close_mem(CharDriverState *chr);
QString *qemu_chr_mem_to_qs(CharDriverState *chr);
size_t qemu_chr_mem_osize(const CharDriverState *chr);
/* async I/O support */
int qemu_set_fd_handler2(int fd,
IOCanReadHandler *fd_read_poll,
IOHandler *fd_read,
IOHandler *fd_write,
void *opaque);
int qemu_set_fd_handler(int fd,
IOHandler *fd_read,
IOHandler *fd_write,
void *opaque);
#endif
+4 -33
View File
@@ -13,7 +13,6 @@
typedef struct QEMUTimer QEMUTimer;
typedef struct QEMUFile QEMUFile;
typedef struct QEMUBH QEMUBH;
typedef struct DeviceState DeviceState;
struct Monitor;
@@ -96,6 +95,10 @@ static inline char *realpath(const char *path, char *resolved_path)
}
#endif
/* icount */
void configure_icount(const char *option);
extern int use_icount;
/* FIXME: Remove NEED_CPU_H. */
#ifndef NEED_CPU_H
@@ -113,23 +116,6 @@ static inline char *realpath(const char *path, char *resolved_path)
int qemu_main(int argc, char **argv, char **envp);
#endif
/* bottom halves */
typedef void QEMUBHFunc(void *opaque);
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
void qemu_bh_schedule(QEMUBH *bh);
/* Bottom halfs that are scheduled from a bottom half handler are instantly
* invoked. This can create an infinite loop if a bottom half handler
* schedules itself. qemu_bh_schedule_idle() avoids this infinite loop by
* ensuring that the bottom half isn't executed until the next main loop
* iteration.
*/
void qemu_bh_schedule_idle(QEMUBH *bh);
void qemu_bh_cancel(QEMUBH *bh);
void qemu_bh_delete(QEMUBH *bh);
int qemu_bh_poll(void);
void qemu_bh_update_timeout(int *timeout);
void qemu_get_timedate(struct tm *tm, int offset);
int qemu_timedate_diff(struct tm *tm);
@@ -183,16 +169,12 @@ const char *path(const char *pathname);
void *qemu_oom_check(void *ptr);
void qemu_mutex_lock_iothread(void);
void qemu_mutex_unlock_iothread(void);
int qemu_open(const char *name, int flags, ...);
ssize_t qemu_write_full(int fd, const void *buf, size_t count)
QEMU_WARN_UNUSED_RESULT;
void qemu_set_cloexec(int fd);
#ifndef _WIN32
int qemu_add_child_watch(pid_t pid);
int qemu_eventfd(int pipefd[2]);
int qemu_pipe(int pipefd[2]);
#endif
@@ -207,14 +189,6 @@ int qemu_pipe(int pipefd[2]);
void QEMU_NORETURN hw_error(const char *fmt, ...) GCC_FMT_ATTR(1, 2);
/* IO callbacks. */
typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
typedef int IOCanReadHandler(void *opaque);
typedef void IOHandler(void *opaque);
void qemu_iohandler_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds);
void qemu_iohandler_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds, int rc);
struct ParallelIOArg {
void *buffer;
int count;
@@ -276,9 +250,6 @@ void cpu_exec_init_all(void);
void cpu_save(QEMUFile *f, void *opaque);
int cpu_load(QEMUFile *f, void *opaque, int version_id);
/* Force QEMU to process pending events */
void qemu_notify_event(void);
/* Unblock cpu */
void qemu_cpu_kick(void *env);
void qemu_cpu_kick_self(void);
+1
View File
@@ -26,6 +26,7 @@
#include "qemu-coroutine.h"
#include "qemu-coroutine-int.h"
#include "qemu-queue.h"
#include "main-loop.h"
#include "trace.h"
static QTAILQ_HEAD(, Coroutine) unlock_bh_queue =
-4
View File
@@ -26,10 +26,6 @@
#ifndef QEMU_OS_POSIX_H
#define QEMU_OS_POSIX_H
static inline void os_host_main_loop_wait(int *timeout)
{
}
void os_set_line_buffering(void);
void os_set_proc_name(const char *s);
void os_setup_signal_handling(void);
+1 -16
View File
@@ -28,26 +28,11 @@
#include <windows.h>
#include <winsock2.h>
#include "main-loop.h"
/* Declaration of ffs() is missing in MinGW's strings.h. */
int ffs(int i);
/* Polling handling */
/* return TRUE if no sleep should be done afterwards */
typedef int PollingFunc(void *opaque);
int qemu_add_polling_cb(PollingFunc *func, void *opaque);
void qemu_del_polling_cb(PollingFunc *func, void *opaque);
/* Wait objects handling */
typedef void WaitObjectFunc(void *opaque);
int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque);
void os_host_main_loop_wait(int *timeout);
static inline void os_setup_signal_handling(void) {}
static inline void os_daemonize(void) {}
static inline void os_setup_post(void) {}
+89 -402
View File
File diff suppressed because it is too large Load Diff
+7 -24
View File
@@ -2,6 +2,7 @@
#define QEMU_TIMER_H
#include "qemu-common.h"
#include "main-loop.h"
#include "notify.h"
#include <time.h>
#include <sys/time.h>
@@ -38,6 +39,9 @@ extern QEMUClock *vm_clock;
extern QEMUClock *host_clock;
int64_t qemu_get_clock_ns(QEMUClock *clock);
int64_t qemu_clock_has_timers(QEMUClock *clock);
int64_t qemu_clock_expired(QEMUClock *clock);
int64_t qemu_clock_deadline(QEMUClock *clock);
void qemu_clock_enable(QEMUClock *clock, int enabled);
void qemu_clock_warp(QEMUClock *clock);
@@ -49,19 +53,18 @@ QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale,
QEMUTimerCB *cb, void *opaque);
void qemu_free_timer(QEMUTimer *ts);
void qemu_del_timer(QEMUTimer *ts);
void qemu_mod_timer_ns(QEMUTimer *ts, int64_t expire_time);
void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
int qemu_timer_pending(QEMUTimer *ts);
int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time);
uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts);
void qemu_run_all_timers(void);
int qemu_alarm_pending(void);
int64_t qemu_next_icount_deadline(void);
void configure_alarms(char const *opt);
void configure_icount(const char *option);
int qemu_calculate_timeout(void);
void init_clocks(void);
int init_timer_alarm(void);
void quit_timers(void);
int64_t cpu_get_ticks(void);
void cpu_enable_ticks(void);
@@ -150,12 +153,8 @@ void ptimer_run(ptimer_state *s, int oneshot);
void ptimer_stop(ptimer_state *s);
/* icount */
int64_t qemu_icount_round(int64_t count);
extern int64_t qemu_icount;
extern int use_icount;
extern int icount_time_shift;
extern int64_t qemu_icount_bias;
int64_t cpu_get_icount(void);
int64_t cpu_get_clock(void);
/*******************************************/
/* host CPU ticks (if available) */
@@ -311,22 +310,6 @@ static inline int64_t cpu_get_real_ticks (void)
}
#endif
#ifdef NEED_CPU_H
/* Deterministic execution requires that IO only be performed on the last
instruction of a TB so that interrupts take effect immediately. */
static inline int can_do_io(CPUState *env)
{
if (!use_icount)
return 1;
/* If not executing code then assume we are ok. */
if (!env->current_tb)
return 1;
return env->can_do_io != 0;
}
#endif
#ifdef CONFIG_PROFILER
static inline int64_t profile_getclock(void)
{
+25
View File
@@ -81,6 +81,7 @@
#include "migration.h"
#include "qemu_socket.h"
#include "qemu-queue.h"
#include "qemu-timer.h"
#include "cpus.h"
#define SELF_ANNOUNCE_ROUNDS 5
@@ -712,6 +713,30 @@ uint64_t qemu_get_be64(QEMUFile *f)
return v;
}
/* timer */
void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
{
uint64_t expire_time;
expire_time = qemu_timer_expire_time_ns(ts);
qemu_put_be64(f, expire_time);
}
void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
{
uint64_t expire_time;
expire_time = qemu_get_be64(f);
if (expire_time != -1) {
qemu_mod_timer_ns(ts, expire_time);
} else {
qemu_del_timer(ts);
}
}
/* bool */
static int get_bool(QEMUFile *f, void *pv, size_t size)

Some files were not shown because too many files have changed in this diff Show More