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;
}