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
