qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

replay-events.c (8273B)


      1 /*
      2  * replay-events.c
      3  *
      4  * Copyright (c) 2010-2015 Institute for System Programming
      5  *                         of the Russian Academy of Sciences.
      6  *
      7  * This work is licensed under the terms of the GNU GPL, version 2 or later.
      8  * See the COPYING file in the top-level directory.
      9  *
     10  */
     11 
     12 #include "qemu/osdep.h"
     13 #include "qemu/error-report.h"
     14 #include "sysemu/replay.h"
     15 #include "replay-internal.h"
     16 #include "block/aio.h"
     17 #include "ui/input.h"
     18 #include "hw/core/cpu.h"
     19 
     20 typedef struct Event {
     21     ReplayAsyncEventKind event_kind;
     22     void *opaque;
     23     void *opaque2;
     24     uint64_t id;
     25 
     26     QTAILQ_ENTRY(Event) events;
     27 } Event;
     28 
     29 static QTAILQ_HEAD(, Event) events_list = QTAILQ_HEAD_INITIALIZER(events_list);
     30 static bool events_enabled;
     31 
     32 /* Functions */
     33 
     34 static void replay_run_event(Event *event)
     35 {
     36     switch (event->event_kind) {
     37     case REPLAY_ASYNC_EVENT_BH:
     38         aio_bh_call(event->opaque);
     39         break;
     40     case REPLAY_ASYNC_EVENT_BH_ONESHOT:
     41         ((QEMUBHFunc *)event->opaque)(event->opaque2);
     42         break;
     43     case REPLAY_ASYNC_EVENT_INPUT:
     44         qemu_input_event_send_impl(NULL, (InputEvent *)event->opaque);
     45         qapi_free_InputEvent((InputEvent *)event->opaque);
     46         break;
     47     case REPLAY_ASYNC_EVENT_INPUT_SYNC:
     48         qemu_input_event_sync_impl();
     49         break;
     50     case REPLAY_ASYNC_EVENT_CHAR_READ:
     51         replay_event_char_read_run(event->opaque);
     52         break;
     53     case REPLAY_ASYNC_EVENT_BLOCK:
     54         aio_bh_call(event->opaque);
     55         break;
     56     case REPLAY_ASYNC_EVENT_NET:
     57         replay_event_net_run(event->opaque);
     58         break;
     59     default:
     60         error_report("Replay: invalid async event ID (%d) in the queue",
     61                     event->event_kind);
     62         exit(1);
     63         break;
     64     }
     65 }
     66 
     67 void replay_enable_events(void)
     68 {
     69     if (replay_mode != REPLAY_MODE_NONE) {
     70         events_enabled = true;
     71     }
     72 }
     73 
     74 bool replay_has_events(void)
     75 {
     76     return !QTAILQ_EMPTY(&events_list);
     77 }
     78 
     79 void replay_flush_events(void)
     80 {
     81     if (replay_mode == REPLAY_MODE_NONE) {
     82         return;
     83     }
     84 
     85     g_assert(replay_mutex_locked());
     86 
     87     while (!QTAILQ_EMPTY(&events_list)) {
     88         Event *event = QTAILQ_FIRST(&events_list);
     89         replay_run_event(event);
     90         QTAILQ_REMOVE(&events_list, event, events);
     91         g_free(event);
     92     }
     93 }
     94 
     95 void replay_disable_events(void)
     96 {
     97     if (replay_mode != REPLAY_MODE_NONE) {
     98         events_enabled = false;
     99         /* Flush events queue before waiting of completion */
    100         replay_flush_events();
    101     }
    102 }
    103 
    104 /*! Adds specified async event to the queue */
    105 void replay_add_event(ReplayAsyncEventKind event_kind,
    106                       void *opaque,
    107                       void *opaque2, uint64_t id)
    108 {
    109     assert(event_kind < REPLAY_ASYNC_COUNT);
    110 
    111     if (!replay_file || replay_mode == REPLAY_MODE_NONE
    112         || !events_enabled) {
    113         Event e;
    114         e.event_kind = event_kind;
    115         e.opaque = opaque;
    116         e.opaque2 = opaque2;
    117         e.id = id;
    118         replay_run_event(&e);
    119         return;
    120     }
    121 
    122     Event *event = g_new0(Event, 1);
    123     event->event_kind = event_kind;
    124     event->opaque = opaque;
    125     event->opaque2 = opaque2;
    126     event->id = id;
    127 
    128     g_assert(replay_mutex_locked());
    129     QTAILQ_INSERT_TAIL(&events_list, event, events);
    130     qemu_cpu_kick(first_cpu);
    131 }
    132 
    133 void replay_bh_schedule_event(QEMUBH *bh)
    134 {
    135     if (events_enabled) {
    136         uint64_t id = replay_get_current_icount();
    137         replay_add_event(REPLAY_ASYNC_EVENT_BH, bh, NULL, id);
    138     } else {
    139         qemu_bh_schedule(bh);
    140     }
    141 }
    142 
    143 void replay_bh_schedule_oneshot_event(AioContext *ctx,
    144     QEMUBHFunc *cb, void *opaque)
    145 {
    146     if (events_enabled) {
    147         uint64_t id = replay_get_current_icount();
    148         replay_add_event(REPLAY_ASYNC_EVENT_BH_ONESHOT, cb, opaque, id);
    149     } else {
    150         aio_bh_schedule_oneshot(ctx, cb, opaque);
    151     }
    152 }
    153 
    154 void replay_add_input_event(struct InputEvent *event)
    155 {
    156     replay_add_event(REPLAY_ASYNC_EVENT_INPUT, event, NULL, 0);
    157 }
    158 
    159 void replay_add_input_sync_event(void)
    160 {
    161     replay_add_event(REPLAY_ASYNC_EVENT_INPUT_SYNC, NULL, NULL, 0);
    162 }
    163 
    164 void replay_block_event(QEMUBH *bh, uint64_t id)
    165 {
    166     if (events_enabled) {
    167         replay_add_event(REPLAY_ASYNC_EVENT_BLOCK, bh, NULL, id);
    168     } else {
    169         qemu_bh_schedule(bh);
    170     }
    171 }
    172 
    173 static void replay_save_event(Event *event)
    174 {
    175     if (replay_mode != REPLAY_MODE_PLAY) {
    176         /* put the event into the file */
    177         g_assert(event->event_kind < REPLAY_ASYNC_COUNT);
    178         replay_put_event(EVENT_ASYNC + event->event_kind);
    179 
    180         /* save event-specific data */
    181         switch (event->event_kind) {
    182         case REPLAY_ASYNC_EVENT_BH:
    183         case REPLAY_ASYNC_EVENT_BH_ONESHOT:
    184             replay_put_qword(event->id);
    185             break;
    186         case REPLAY_ASYNC_EVENT_INPUT:
    187             replay_save_input_event(event->opaque);
    188             break;
    189         case REPLAY_ASYNC_EVENT_INPUT_SYNC:
    190             break;
    191         case REPLAY_ASYNC_EVENT_CHAR_READ:
    192             replay_event_char_read_save(event->opaque);
    193             break;
    194         case REPLAY_ASYNC_EVENT_BLOCK:
    195             replay_put_qword(event->id);
    196             break;
    197         case REPLAY_ASYNC_EVENT_NET:
    198             replay_event_net_save(event->opaque);
    199             break;
    200         default:
    201             error_report("Unknown ID %" PRId64 " of replay event", event->id);
    202             exit(1);
    203         }
    204     }
    205 }
    206 
    207 /* Called with replay mutex locked */
    208 void replay_save_events(void)
    209 {
    210     g_assert(replay_mutex_locked());
    211     while (!QTAILQ_EMPTY(&events_list)) {
    212         Event *event = QTAILQ_FIRST(&events_list);
    213         replay_save_event(event);
    214         replay_run_event(event);
    215         QTAILQ_REMOVE(&events_list, event, events);
    216         g_free(event);
    217     }
    218 }
    219 
    220 static Event *replay_read_event(void)
    221 {
    222     Event *event;
    223     ReplayAsyncEventKind event_kind = replay_state.data_kind - EVENT_ASYNC;
    224 
    225     /* Events that has not to be in the queue */
    226     switch (event_kind) {
    227     case REPLAY_ASYNC_EVENT_BH:
    228     case REPLAY_ASYNC_EVENT_BH_ONESHOT:
    229         if (replay_state.read_event_id == -1) {
    230             replay_state.read_event_id = replay_get_qword();
    231         }
    232         break;
    233     case REPLAY_ASYNC_EVENT_INPUT:
    234         event = g_new0(Event, 1);
    235         event->event_kind = event_kind;
    236         event->opaque = replay_read_input_event();
    237         return event;
    238     case REPLAY_ASYNC_EVENT_INPUT_SYNC:
    239         event = g_new0(Event, 1);
    240         event->event_kind = event_kind;
    241         event->opaque = 0;
    242         return event;
    243     case REPLAY_ASYNC_EVENT_CHAR_READ:
    244         event = g_new0(Event, 1);
    245         event->event_kind = event_kind;
    246         event->opaque = replay_event_char_read_load();
    247         return event;
    248     case REPLAY_ASYNC_EVENT_BLOCK:
    249         if (replay_state.read_event_id == -1) {
    250             replay_state.read_event_id = replay_get_qword();
    251         }
    252         break;
    253     case REPLAY_ASYNC_EVENT_NET:
    254         event = g_new0(Event, 1);
    255         event->event_kind = event_kind;
    256         event->opaque = replay_event_net_load();
    257         return event;
    258     default:
    259         error_report("Unknown ID %d of replay event", event_kind);
    260         exit(1);
    261         break;
    262     }
    263 
    264     QTAILQ_FOREACH(event, &events_list, events) {
    265         if (event->event_kind == event_kind
    266             && (replay_state.read_event_id == -1
    267                 || replay_state.read_event_id == event->id)) {
    268             break;
    269         }
    270     }
    271 
    272     if (event) {
    273         QTAILQ_REMOVE(&events_list, event, events);
    274     }
    275 
    276     return event;
    277 }
    278 
    279 /* Called with replay mutex locked */
    280 void replay_read_events(void)
    281 {
    282     g_assert(replay_mutex_locked());
    283     while (replay_state.data_kind >= EVENT_ASYNC
    284         && replay_state.data_kind <= EVENT_ASYNC_LAST) {
    285         Event *event = replay_read_event();
    286         if (!event) {
    287             break;
    288         }
    289         replay_finish_event();
    290         replay_state.read_event_id = -1;
    291         replay_run_event(event);
    292 
    293         g_free(event);
    294     }
    295 }
    296 
    297 void replay_init_events(void)
    298 {
    299     replay_state.read_event_id = -1;
    300 }
    301 
    302 void replay_finish_events(void)
    303 {
    304     events_enabled = false;
    305     replay_flush_events();
    306 }
    307 
    308 bool replay_events_enabled(void)
    309 {
    310     return events_enabled;
    311 }
    312 
    313 uint64_t blkreplay_next_id(void)
    314 {
    315     if (replay_events_enabled()) {
    316         return replay_state.block_request_id++;
    317     }
    318     return 0;
    319 }