On Sun, Sep 13, 2026 at 2:37 PM Irtaza Hyder
<[email protected]> wrote:
>
> In the [QEMU Internals Overall Architecture 
> Blogpost](https://blog.vmsplice.net/2011/03/qemu-internals-overall-architecture-and.html),
>  the following is stated:
> > Although many I/O operations can be performed in a non-blocking fashion, 
> > there are system calls which have no non-blocking equivalent. Furthermore, 
> > sometimes long-running computations simply hog the CPU and are difficult to 
> > break up into callbacks. In these cases dedicated worker threads can be 
> > used to carefully move these tasks out of core QEMU.
>
> The blog stated example implementations are no longer available in QEMU 11 to 
> gain insight on how worker threads are used.
>
> For my use case, I am trying to trigger external file descriptor writes and 
> wait for the corresponding read based on vCPU instructions (i.e. 
> register/MMIO rmw operations). In my current implementation register 
> read/write operations are redirected to the following function:
> ``` C
> MemTxResult fd_mmio_rmw(hwaddr addr, bool is_write, int bytes,
>                         uint64_t wdata, uint64_t *rdata,
>                         CharFrontend *fe)
> {
>     int chardev_status;
>
>     if (!qemu_chr_fe_backend_open(fe)) {
>         /* Charbackend is not open */
>         return MEMTX_ERROR;
>     }
>
>     chardev_status = qemu_chr_fe_write_all(fe, (uint8_t *)wdata, bytes);
>     if (chardev_status == -1) {
>         /* Unable to write to socket */
>         return MEMTX_ERROR;
>     }
>
>     chardev_status = qemu_chr_fe_read_all(fe, (uint8_t*)rdata, bytes);
>     if (chardev_status < 0) {
>         return MEMTX_ERROR;
>     }
>     return MEMTX_OK;
> }
> ```
> But this function blocks the main event loop due to the blocking chardev 
> frontend APIs. How can:

Hi Irtaza,
Doing blocking I/O in a MemoryRegionOps .read() or .write() function
is fundamentally a problem. I say blocking because your code example
suggests that the rmw function not only needs to initiate I/O but also
needs to wait for it to complete. That can take an unbounded amount of
time. The vCPU is blocked during this time, which is a performance
problem and can cause problems inside the guest if this takes a long
time (e.g. Linux can complain about hung tasks and Windows can
bluescreen).

The first thing to do is check whether it's possible to avoid this
altogether. Can you write the device emulation code in a way that does
not block the vCPU? The answer depends on the MMIO interface your are
implementing.

In some cases it's unavoidable (e.g. out-of-process device emulation).

> 1. The function be deferred to a worker thread as mentioned in the blog, 
> while keeping the vCPU triggering this request halted but the main event loop 
> running?

The issue here is the Big QEMU Lock (BQL) that protects most state in
QEMU. The vCPU thread running the rmw function holds the BQL and other
threads (including the main loop thread) cannot run during this time.

There is an API to avoid taking the BQL during a MemoryRegionOps
callback: memory_region_enable_lockless_io(). If you are careful when
writing your rmw function, you could write blocking code and use this
to prevent the other vCPU threads and the main loop thread from
blocking.

hw/ppc/spapr_rng.c:h_random() uses a similar approach but without
memory_region_enable_lockless_io():
1. Initiate I/O
2. bql_unlock()
3. Wait for I/O completion
4. bql_lock()

> 2. The worker threads be synchronized with the main loop (i.e. how would it 
> inform the main loop to give control to vCPU executing instructions ONLY 
> after the FD read is completed)?

This is probably not necessary if you use the BQL techniques mentioned above.

Stefan

Reply via email to