vmi->driver.events_listen_ptr = &xen_events_listen;

used by:

status_t vmi_events_listen(vmi_instance_t vmi, uint32_t timeout)
{
#ifdef ENABLE_SAFETY_CHECKS
    if (!vmi)
        return VMI_FAILURE;
 
    if (!(vmi->init_flags & (VMI_INIT_EVENTS | VMI_INIT_DOMAINWATCH)))
        return VMI_FAILURE;
#endif
 
    return driver_events_listen(vmi, timeout);
}
 
status_t xen_events_listen(vmi_instance_t vmi, uint32_t timeout)
{
    xen_events_t *xe = xen_get_events(vmi);
    xen_instance_t *xen = xen_get_instance(vmi);
 
    int rc;
    status_t vrc = VMI_SUCCESS;
    uint32_t requests_processed = 0;
    bool needs_unmasking = 0;
 
#ifdef ENABLE_SAFETY_CHECKS
    if ( !xen ) {
        errprint("%s error: invalid xen_instance_t handle\n", __FUNCTION__);
        return VMI_FAILURE;
    }
    if ( !xe ) {
        errprint("%s error: invalid xen_events_t handle\n", __FUNCTION__);
        return VMI_FAILURE;
    }
#endif
 
    if (!vmi->shutting_down) {
        if ( !xe->external_poll ) {
            dbprint(VMI_DEBUG_XEN, "--Waiting for xen events...(%"PRIu32" ms)\n", timeout);
            if ( VMI_FAILURE == wait_for_event_or_timeout(vmi, timeout, &needs_unmasking) ) {
                errprint("Error while waiting for event.\n");
                return VMI_FAILURE;
            }
        } else
            needs_unmasking = timeout;
    }
 
#ifdef HAVE_LIBXENSTORE
    if ( (xe->fd[1].revents & POLLIN) && (vmi->init_flags & VMI_INIT_DOMAINWATCH) ) {
        /* We have a domain watch event */
        vrc = xe->process_xs_event[XS_EVENT_REASON_DOMAIN_WATCH](vmi);
    }
#endif
 
    if ( !(vmi->init_flags & VMI_INIT_EVENTS) )
        return vrc;
 
    vrc = xe->process_requests(vmi, &requests_processed);
#ifdef ENABLE_SAFETY_CHECKS
    if ( VMI_FAILURE == vrc )
        return VMI_FAILURE;
#endif
 
    /*
     * The only way to gracefully handle vmi_swap_events and vmi_clear_event requests
     * that were issued in a callback is to ensure no more requests
     * are in the ringpage. We do this by pausing the domain (all vCPUs)
     * and processing all reamining events on the ring. Once no more requests
     * are on the ring we can remove/swap the events.
     */
    if ( vmi->swap_events || (vmi->clear_events && g_hash_table_size(vmi->clear_events)) ) {
        uint32_t requests_processed_extra = 0;
        vmi_pause_vm(vmi);
 
        vrc = xe->process_requests(vmi, &requests_processed_extra);
#ifdef ENABLE_SAFETY_CHECKS
        if ( VMI_FAILURE == vrc )
            return VMI_FAILURE;
#endif
 
        requests_processed += requests_processed_extra;
 
        GSList *loop = vmi->swap_events;
        while (loop) {
            swap_wrapper_t *swap_wrapper = loop->data;
            swap_events(vmi, swap_wrapper->swap_from, swap_wrapper->swap_to,
                        swap_wrapper->free_routine);
            g_slice_free(swap_wrapper_t, swap_wrapper);
            loop = loop->next;
        }
 
        g_slist_free(vmi->swap_events);
        vmi->swap_events = NULL;
 
        g_hash_table_foreach_remove(vmi->clear_events, clear_events_full, vmi);
 
        vmi_resume_vm(vmi);
    }
 
    /*
     * Unmask event channel port now that we have finished processing
     * all requests that were on the ring.
     */
    if ( needs_unmasking ) {
        vrc = unmask_event(xen, xe);
#ifdef ENABLE_SAFETY_CHECKS
        if ( VMI_FAILURE == vrc )
            return VMI_FAILURE;
#endif
    }
 
    /*
     * Send notification to Xen that response(s) were placed on the ring
     *
     * Note: it is more performant to send notification after each event if
     * there are a lot of vCPUs assigned to the VM.
     */
    if (vmi->num_vcpus < 7 && requests_processed) {
        rc = xen->libxcw.xc_evtchn_notify(xe->xce_handle, xe->port);
 
#ifdef ENABLE_SAFETY_CHECKS
        if ( rc ) {
            errprint("Error resuming domain.\n");
            return VMI_FAILURE;
        }
#endif
    }
 
    return VMI_SUCCESS;
}

🌱 Back to Garden