Skip to content

vcpu_run_loop has no embedder progress callback for UI/event pumps #244

Description

@doanbaotrung

vcpu_run_loop has no embedder progress callback for UI/event pumps

Description

vcpu_run_loop() currently owns guest execution until the guest exits,
times out, or hits a fatal condition. This works well for normal command-line
guest programs, but it is difficult for embedders that need to service host-side
event sources while the guest remains alive.

For example, an embedder may need to periodically run a host event pump,
flush pending host-side callbacks, or service synthetic devices from the same
thread that owns the vCPU. Since vcpu_run_loop() does not expose a progress
or idle callback, the embedder cannot safely do this while the guest is running.

Running the vCPU loop on a worker thread is not a reliable workaround because
some host hypervisor backends require vCPU operations to remain on the thread
that created/owns the vCPU.

Current Behavior

The public loop shape is effectively:

int vcpu_run_loop(hv_vcpu_t vcpu,
                  hv_vcpu_exit_t *vexit,
                  guest_t *g,
                  bool verbose,
                  int timeout_sec,
                  int *wait_status);

Once called, control does not return to the embedder until guest termination or
timeout. The embedder has no opportunity to perform periodic host-side work
between guest exits, syscalls, HVC handling, signal checks, or timer wakeups.

Expected Behavior

vcpu_run_loop() should optionally allow an embedder to run a small callback
from inside the loop on the same host thread as the vCPU.

The callback should be optional and preserve current behavior when unset.

Possible API shape:

typedef bool (*vcpu_embedder_tick_fn)(guest_t *g, void *opaque);

typedef struct vcpu_run_hooks {
    vcpu_embedder_tick_fn tick;
    void *opaque;
} vcpu_run_hooks_t;

int vcpu_run_loop_ex(hv_vcpu_t vcpu,
                     hv_vcpu_exit_t *vexit,
                     guest_t *g,
                     bool verbose,
                     int timeout_sec,
                     int *wait_status,
                     const vcpu_run_hooks_t *hooks);

The existing vcpu_run_loop() could remain as a compatibility wrapper around
vcpu_run_loop_ex(..., NULL).

Suggested Semantics

The callback could run at safe progress points such as:

  • after handling a guest exit
  • after syscall/HVC dispatch completes
  • after signal/timer checks
  • before sleeping or returning to hv_vcpu_run()

The callback should:

  • run on the same host thread as hv_vcpu_run()
  • be optional
  • avoid changing behavior for existing callers
  • return whether it performed work, if that is useful for scheduling decisions

Why This Is Needed

Some embedders need to keep host-side state machines alive while guest code is
still running. Without a callback, those embedders must choose between:

  • blocking forever inside vcpu_run_loop()
  • using a timeout and repeatedly re-entering the loop
  • moving the vCPU loop to another thread, which can conflict with hypervisor
    thread-affinity constraints
  • patching elfuse locally

An optional in-loop callback would provide a cleaner and more general embedding
interface without affecting normal Linux binary execution.

Compatibility

This can be implemented without changing current users by keeping the existing
vcpu_run_loop() signature and adding a new extended API or optional hooks
structure.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions