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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions