Skip to content

monitor: /pause suspends only the SystemC kernel — QEMU vCPUs and the virtual clock keep running under multithread sync policies #88

Description

@Jordanplus

Summary

The monitor's /pause route calls sc_core::sc_suspend_all() and nothing else. Under multithread-* sync policies (tcg_mode = "MULTI"), the QEMU vCPU threads and the QEMU virtual clock are not stopped: the guest keeps executing while the simulation is nominally "paused", and on /continue SystemC time jumps forward by roughly the wall-clock duration of the pause.

  • /pause handler:
    CROW_ROUTE(m_app, "/pause")
    ([&]() {
    crow::json::wvalue ret;
    m_sc.run_on_sysc([&] {
    sc_core::sc_suspend_all();
    ret["sc_time_stamp"] = sc_core::sc_time_stamp().to_seconds();
    });
    return ret;
    });
  • /continue handler:
    CROW_ROUTE(m_app, "/continue")
    ([&]() {
    crow::json::wvalue ret;
    m_sc.run_on_sysc([&] {
    sc_core::sc_unsuspend_all();
    ret["sc_time_stamp"] = sc_core::sc_time_stamp().to_seconds();
    });
    return ret;
    });

The docs describe the feature as "Pause and resume the simulation" (docs/monitor.md#L12), while the debugging guide already warns "Do not use /pause" (docs/monitor-debugging-guide.md#L262-L264) — this issue is about closing that gap one way or the other.

Reproduction

Any platform using a multithread-* sync policy with the monitor enabled (e.g. the in-tree platforms/ubuntu aarch64 configuration, which uses sync_policy = "multithread-unconstrained": conf_aarch64.lua#L77):

  1. Boot the platform with the monitor enabled and let Linux start booting.
  2. curl http://localhost:18088/pause
  3. Observe the guest serial console keeps printing — the vCPUs are still running.
  4. Wait N seconds (e.g. 60–120 s), then curl http://localhost:18088/continue.
  5. Compare curl http://localhost:18088/sc_time before step 2 and after step 4: SystemC time jumps forward by roughly the wall-clock pause duration (we observed a ~107 s jump after a ~107 s pause), because the vCPUs' quantum-keeper local time kept advancing with the QEMU virtual clock and SystemC then catches up on resume.

Suggestion

Either:

  1. Make /pause also stop the QEMU side. The libqemu-cxx wrappers already exist:

    Ordering note from our experiments: stop the vCPUs before suspending the SystemC kernel — a vCPU blocked mid-b_transport against an already-suspended kernel cannot park — and resume in the reverse order (sc_unsuspend_all() first, then vm_start()).

  2. Or prominently document that /pause is SystemC-only and that guest execution continues under multithread policies (and reconcile docs/monitor.md#L12 with the guide's "Do not use /pause" warning).

Workaround (no QBox change required)

Pass a QMP socket to the embedded QEMU via the QemuInstance qemu_args parameter (qemu-instance.h#L327), e.g. qemu_args = "-qmp tcp:127.0.0.1:<port>,server=on,wait=off", and compose the two:

  • pause = QMP stop first, then /pause
  • resume = /continue first, then QMP cont

Validated under a guest MMIO flood: three pause/continue cycles, each < 0.01 s, resume time-jump 0.000 s, no deadlock.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions