From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:58430) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YEDVc-0002EE-Az for qemu-devel@nongnu.org; Thu, 22 Jan 2015 03:53:01 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YEDVa-0005u8-BP for qemu-devel@nongnu.org; Thu, 22 Jan 2015 03:53:00 -0500 Received: from mail.ispras.ru ([83.149.199.45]:36400) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YEDVa-0005sT-0d for qemu-devel@nongnu.org; Thu, 22 Jan 2015 03:52:58 -0500 From: Pavel Dovgalyuk Date: Thu, 22 Jan 2015 11:53:00 +0300 Message-ID: <20150122085300.5276.19453.stgit@PASHA-ISP.def.inno> In-Reply-To: <20150122085127.5276.53895.stgit@PASHA-ISP.def.inno> References: <20150122085127.5276.53895.stgit@PASHA-ISP.def.inno> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Subject: [Qemu-devel] [RFC PATCH v8 16/21] replay: bottom halves List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: peter.maydell@linaro.org, peter.crosthwaite@xilinx.com, alex.bennee@linaro.org, mark.burton@greensocs.com, real@ispras.ru, batuzovk@ispras.ru, maria.klimushenkova@ispras.ru, pavel.dovgaluk@ispras.ru, pbonzini@redhat.com, afaerber@suse.de, fred.konrad@greensocs.com This patch introduces bottom half event for replay queue. It saves the events into the queue and process them at the checkpoints and instructions execution. Signed-off-by: Pavel Dovgalyuk --- async.c | 24 +++++++++++++++++++++++- dma-helpers.c | 4 +++- hw/ide/ahci.c | 4 +++- hw/ide/core.c | 4 +++- hw/timer/arm_timer.c | 2 +- hw/usb/hcd-uhci.c | 2 +- include/block/aio.h | 18 ++++++++++++++++++ include/qemu/main-loop.h | 1 + main-loop.c | 5 +++++ replay/replay-events.c | 16 ++++++++++++++++ replay/replay-internal.h | 1 + replay/replay.h | 2 ++ stubs/replay.c | 4 ++++ 13 files changed, 81 insertions(+), 6 deletions(-) diff --git a/async.c b/async.c index bc6e83b..0c02ae2 100644 --- a/async.c +++ b/async.c @@ -27,6 +27,7 @@ #include "block/thread-pool.h" #include "qemu/main-loop.h" #include "qemu/atomic.h" +#include "replay/replay.h" /***********************************************************/ /* bottom halves (can be seen as timers which expire ASAP) */ @@ -39,6 +40,8 @@ struct QEMUBH { bool scheduled; bool idle; bool deleted; + bool replay; + uint64_t id; }; QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque) @@ -56,6 +59,21 @@ QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque) return bh; } +QEMUBH *aio_bh_new_replay(AioContext *ctx, QEMUBHFunc *cb, void *opaque, + uint64_t id) +{ + QEMUBH *bh = aio_bh_new(ctx, cb, opaque); + bh->replay = true; + bh->id = id; + return bh; +} + +void aio_bh_call(void *opaque) +{ + QEMUBH *bh = (QEMUBH *)opaque; + bh->cb(bh->opaque); +} + /* Multiple occurrences of aio_bh_poll cannot be called concurrently */ int aio_bh_poll(AioContext *ctx) { @@ -77,7 +95,11 @@ int aio_bh_poll(AioContext *ctx) if (!bh->idle) ret = 1; bh->idle = 0; - bh->cb(bh->opaque); + if (!bh->replay) { + aio_bh_call(bh); + } else { + replay_add_bh_event(bh, bh->id); + } } } diff --git a/dma-helpers.c b/dma-helpers.c index 6918572..357d7e9 100644 --- a/dma-helpers.c +++ b/dma-helpers.c @@ -13,6 +13,7 @@ #include "qemu/range.h" #include "qemu/thread.h" #include "qemu/main-loop.h" +#include "replay/replay.h" /* #define DEBUG_IOMMU */ @@ -96,7 +97,8 @@ static void continue_after_map_failure(void *opaque) { DMAAIOCB *dbs = (DMAAIOCB *)opaque; - dbs->bh = qemu_bh_new(reschedule_dma, dbs); + dbs->bh = qemu_bh_new_replay(reschedule_dma, dbs, + replay_get_current_step()); qemu_bh_schedule(dbs->bh); } diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 5651372..13d7f84 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -33,6 +33,7 @@ #include "internal.h" #include #include +#include "replay/replay.h" #define DEBUG_AHCI 0 @@ -1243,7 +1244,8 @@ static void ahci_cmd_done(IDEDMA *dma) if (!ad->check_bh) { /* maybe we still have something to process, check later */ - ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad); + ad->check_bh = qemu_bh_new_replay(ahci_check_cmd_bh, ad, + replay_get_current_step()); qemu_bh_schedule(ad->check_bh); } } diff --git a/hw/ide/core.c b/hw/ide/core.c index d4af5e2..d76244a 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -32,6 +32,7 @@ #include "sysemu/dma.h" #include "hw/block/block.h" #include "sysemu/block-backend.h" +#include "replay/replay.h" #include @@ -448,7 +449,8 @@ BlockAIOCB *ide_issue_trim(BlockBackend *blk, iocb = blk_aio_get(&trim_aiocb_info, blk, cb, opaque); iocb->blk = blk; - iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb); + iocb->bh = qemu_bh_new_replay(ide_trim_bh_cb, iocb, + replay_get_current_step()); iocb->ret = 0; iocb->qiov = qiov; iocb->i = -1; diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c index 1452910..97784a0 100644 --- a/hw/timer/arm_timer.c +++ b/hw/timer/arm_timer.c @@ -168,7 +168,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq) s->freq = freq; s->control = TIMER_CTRL_IE; - bh = qemu_bh_new(arm_timer_tick, s); + bh = qemu_bh_new_replay(arm_timer_tick, s, 0); s->timer = ptimer_init(bh); vmstate_register(NULL, -1, &vmstate_arm_timer, s); return s; diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 4a4215d..0d94143 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -1221,7 +1221,7 @@ static int usb_uhci_common_initfn(PCIDevice *dev) USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); } } - s->bh = qemu_bh_new(uhci_bh, s); + s->bh = qemu_bh_new_replay(uhci_bh, s, 0); s->frame_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, uhci_frame_timer, s); s->num_ports_vmstate = NB_PORTS; QTAILQ_INIT(&s->queues); diff --git a/include/block/aio.h b/include/block/aio.h index 82cdf78..ed76b43 100644 --- a/include/block/aio.h +++ b/include/block/aio.h @@ -35,6 +35,8 @@ struct BlockAIOCB { const AIOCBInfo *aiocb_info; BlockDriverState *bs; BlockCompletionFunc *cb; + bool replay; + uint64_t replay_step; void *opaque; int refcnt; }; @@ -144,6 +146,17 @@ void aio_context_release(AioContext *ctx); QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque); /** + * aio_bh_new_replay: Allocate a new bottom half structure for replay. + * + * This function calls aio_bh_new function and also fills replay parameters + * of the BH structure. BH created with this function in record/replay mode + * are executed through the replay queue only at checkpoints and instructions + * executions. + */ +QEMUBH *aio_bh_new_replay(AioContext *ctx, QEMUBHFunc *cb, void *opaque, + uint64_t id); + +/** * aio_notify: Force processing of pending events. * * Similar to signaling a condition variable, aio_notify forces @@ -159,6 +172,11 @@ QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque); void aio_notify(AioContext *ctx); /** + * aio_bh_call: Executes callback function of the specified BH. + */ +void aio_bh_call(void *opaque); + +/** * aio_bh_poll: Poll bottom halves for an AioContext. * * These are internal functions used by the QEMU main loop. diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h index 62c68c0..f5a98fe 100644 --- a/include/qemu/main-loop.h +++ b/include/qemu/main-loop.h @@ -306,6 +306,7 @@ void qemu_iohandler_fill(GArray *pollfds); void qemu_iohandler_poll(GArray *pollfds, int rc); QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); +QEMUBH *qemu_bh_new_replay(QEMUBHFunc *cb, void *opaque, uint64_t id); void qemu_bh_schedule_idle(QEMUBH *bh); #endif diff --git a/main-loop.c b/main-loop.c index d6e93c3..df99bcf 100644 --- a/main-loop.c +++ b/main-loop.c @@ -513,3 +513,8 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque) { return aio_bh_new(qemu_aio_context, cb, opaque); } + +QEMUBH *qemu_bh_new_replay(QEMUBHFunc *cb, void *opaque, uint64_t id) +{ + return aio_bh_new_replay(qemu_aio_context, cb, opaque, id); +} diff --git a/replay/replay-events.c b/replay/replay-events.c index dfd5efd..7e82b61 100755 --- a/replay/replay-events.c +++ b/replay/replay-events.c @@ -36,6 +36,9 @@ static bool replay_events_enabled = false; static void replay_run_event(Event *event) { switch (event->event_kind) { + case REPLAY_ASYNC_EVENT_BH: + aio_bh_call(event->opaque); + break; default: fprintf(stderr, "Replay: invalid async event ID (%d) in the queue\n", event->event_kind); @@ -122,6 +125,11 @@ void replay_add_event(ReplayAsyncEventKind event_kind, void *opaque) replay_add_event_internal(event_kind, opaque, NULL, 0); } +void replay_add_bh_event(void *bh, uint64_t id) +{ + replay_add_event_internal(REPLAY_ASYNC_EVENT_BH, bh, NULL, id); +} + /* Called with replay mutex locked */ void replay_save_events(int opt) { @@ -136,6 +144,9 @@ void replay_save_events(int opt) /* save event-specific data */ switch (event->event_kind) { + case REPLAY_ASYNC_EVENT_BH: + replay_put_qword(event->id); + break; } } @@ -167,6 +178,11 @@ void replay_read_events(int opt) } /* Execute some events without searching them in the queue */ switch (read_event_kind) { + case REPLAY_ASYNC_EVENT_BH: + if (read_id == -1) { + read_id = replay_get_qword(); + } + break; default: fprintf(stderr, "Unknown ID %d of replay event\n", read_event_kind); exit(1); diff --git a/replay/replay-internal.h b/replay/replay-internal.h index c0a5800..0e6ba2a 100755 --- a/replay/replay-internal.h +++ b/replay/replay-internal.h @@ -40,6 +40,7 @@ enum ReplayEvents { /* Asynchronous events IDs */ enum ReplayAsyncEventKind { + REPLAY_ASYNC_EVENT_BH, REPLAY_ASYNC_COUNT }; diff --git a/replay/replay.h b/replay/replay.h index 39822b4..073e105 100755 --- a/replay/replay.h +++ b/replay/replay.h @@ -106,5 +106,7 @@ bool replay_checkpoint(ReplayCheckpoint checkpoint); /*! Disables storing events in the queue */ void replay_disable_events(void); +/*! Adds BH event to the queue */ +void replay_add_bh_event(void *bh, uint64_t id); #endif diff --git a/stubs/replay.c b/stubs/replay.c index 1be3575..268f3e0 100755 --- a/stubs/replay.c +++ b/stubs/replay.c @@ -21,3 +21,7 @@ int runstate_is_running(void) { return 0; } + +void replay_add_bh_event(void *bh, uint64_t id) +{ +}