static int evtchn_suspend(checkpoint_state* s) { int rc; rc = xc_evtchn_notify(s->xce, s->suspend_evtchn); if (rc < 0) { snprintf(errbuf, sizeof(errbuf), "failed to notify suspend event channel: %d", rc); s->errstr = errbuf; return -1; } do if (!(rc = pollfd(s, xc_evtchn_fd(s->xce)))) rc = xc_evtchn_pending(s->xce); while (rc >= 0 && rc != s->suspend_evtchn); if (rc <= 0) return -1; if (xc_evtchn_unmask(s->xce, s->suspend_evtchn) < 0) { snprintf(errbuf, sizeof(errbuf), "failed to unmask suspend notification channel: %d", rc); s->errstr = errbuf; return -1; } return 0; }
void libxenvchan_close(struct libxenvchan *ctrl) { if (!ctrl) return; if (ctrl->read.order >= PAGE_SHIFT) munmap(ctrl->read.buffer, 1 << ctrl->read.order); if (ctrl->write.order >= PAGE_SHIFT) munmap(ctrl->write.buffer, 1 << ctrl->write.order); if (ctrl->ring) { if (ctrl->is_server) { ctrl->ring->srv_live = 0; xc_gntshr_munmap(ctrl->gntshr, ctrl->ring, PAGE_SIZE); } else { ctrl->ring->cli_live = 0; xc_gnttab_munmap(ctrl->gnttab, ctrl->ring, PAGE_SIZE); } } if (ctrl->event) { if (ctrl->event_port >= 0 && ctrl->ring) xc_evtchn_notify(ctrl->event, ctrl->event_port); xc_evtchn_close(ctrl->event); } if (ctrl->is_server) { if (ctrl->gntshr) xc_gntshr_close(ctrl->gntshr); } else { if (ctrl->gnttab) xc_gnttab_close(ctrl->gnttab); } free(ctrl); }
static void handle_aio_events(struct fs_mount *mount) { int fd, ret, count, i, notify; evtchn_port_t port; /* AIO control block for the evtchn file destriptor */ struct aiocb evtchn_cb; const struct aiocb * cb_list[mount->nr_entries]; int request_ids[mount->nr_entries]; /* Prepare the AIO control block for evtchn */ fd = xc_evtchn_fd(mount->evth); bzero(&evtchn_cb, sizeof(struct aiocb)); evtchn_cb.aio_fildes = fd; evtchn_cb.aio_nbytes = sizeof(port); evtchn_cb.aio_buf = &port; assert(aio_read(&evtchn_cb) == 0); wait_again: /* Create list of active AIO requests */ count = 0; for(i=0; i<mount->nr_entries; i++) if(mount->requests[i].active) { cb_list[count] = &mount->requests[i].aiocb; request_ids[count] = i; count++; } /* Add the event channel at the end of the list. Event channel needs to be * handled last as it exits this function. */ cb_list[count] = &evtchn_cb; request_ids[count] = -1; count++; /* Block till an AIO requset finishes, or we get an event */ while(1) { int ret = aio_suspend(cb_list, count, NULL); if (!ret) break; assert(errno == EINTR); } for(i=0; i<count; i++) if(aio_error(cb_list[i]) != EINPROGRESS) { if(request_ids[i] >= 0) dispatch_response(mount, request_ids[i]); else goto read_event_channel; } RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&mount->ring, notify); printf("Pushed responces and notify=%d\n", notify); if(notify) xc_evtchn_notify(mount->evth, mount->local_evtchn); goto wait_again; read_event_channel: assert(aio_return(&evtchn_cb) == sizeof(evtchn_port_t)); assert(xc_evtchn_unmask(mount->evth, mount->local_evtchn) >= 0); }
CAMLprim value stub_eventchn_notify(value xce, value port) { if(xc_evtchn_notify(_H(xce), Int_val(port)) == -1) caml_failwith("evtchn notify failed"); return Val_unit; }
static void xenfb_on_kbd_event(struct xenfb *xenfb) { struct xenkbd_page *page = xenfb->kbd.page; /* We don't understand any keyboard events, so just ignore them. */ if (page->out_prod == page->out_cons) return; page->out_cons = page->out_prod; xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); }
CAMLprim value stub_eventchn_notify(value xce, value port) { CAMLparam2(xce, port); if(xc_evtchn_notify(_H(xce), Int_val(port)) == -1) { perror("xc_evtchn_notify"); caml_failwith(strerror(errno)); } CAMLreturn(Val_unit); }
CAMLprim value stub_eventchn_notify(value xce, value port) { CAMLparam2(xce, port); int rc; rc = xc_evtchn_notify(_H(xce), Int_val(port)); if (rc == -1) caml_failwith("evtchn notify failed"); CAMLreturn(Val_unit); }
static inline int send_notify(struct libxenvchan *ctrl, uint8_t bit) { uint8_t *notify, prev; xen_mb(); /* caller updates indexes /before/ we decode to notify */ notify = ctrl->is_server ? &ctrl->ring->srv_notify : &ctrl->ring->cli_notify; prev = __sync_fetch_and_and(notify, ~bit); if (prev & bit) return xc_evtchn_notify(ctrl->event, ctrl->event_port); else return 0; }
static void xenfb_on_fb_event(struct xenfb *xenfb) { uint32_t prod, cons; struct xenfb_page *page = xenfb->fb.page; prod = page->out_prod; if (prod == page->out_cons) return; xen_rmb(); /* ensure we see ring contents up to prod */ for (cons = page->out_cons; cons != prod; cons++) { union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons); int x, y, w, h; switch (event->type) { case XENFB_TYPE_UPDATE: x = MAX(event->update.x, 0); y = MAX(event->update.y, 0); w = MIN(event->update.width, xenfb->width - x); h = MIN(event->update.height, xenfb->height - y); if (w < 0 || h < 0) { fprintf(stderr, "%s bogus update ignored\n", xenfb->fb.nodename); break; } if (x != event->update.x || y != event->update.y || w != event->update.width || h != event->update.height) { fprintf(stderr, "%s bogus update clipped\n", xenfb->fb.nodename); } xenfb_guest_copy(xenfb, x, y, w, h); break; case XENFB_TYPE_RESIZE: if (xenfb_configure_fb(xenfb, xenfb->fb_len, event->resize.width, event->resize.height, event->resize.depth, xenfb->fb_len, event->resize.offset, event->resize.stride) < 0) break; if (xenfb->ds->dpy_resize_shared) dpy_resize_shared(xenfb->ds, xenfb->width, xenfb->height, xenfb->depth, xenfb->row_stride, xenfb->pixels + xenfb->offset); else dpy_resize(xenfb->ds, xenfb->width, xenfb->height); xenfb_invalidate(xenfb); break; } } xen_mb(); /* ensure we're done with ring contents */ page->out_cons = cons; xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port); }
static void xenfb_send_event(struct xenfb *xenfb, union xenfb_in_event *event) { uint32_t prod; struct xenfb_page *page = xenfb->fb.page; prod = page->in_prod; /* caller ensures !xenfb_queue_full() */ xen_mb(); /* ensure ring space available */ XENFB_IN_RING_REF(page, prod) = *event; xen_wmb(); /* ensure ring contents visible */ page->in_prod = prod + 1; xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port); }
static void writeRaw(ivc_connection_t *con, void *buffer, uint32_t size) { uint32_t off = con->output->produced % con->outsize; void *basep = (void*)((uintptr_t)con->outbuf + off); if(off + size > con->outsize) { uint32_t part1sz = con->outsize - off; memcpy(basep, buffer, part1sz); memcpy(con->outbuf, (void*)((uintptr_t)buffer + part1sz), size - part1sz); } else { memcpy(basep, buffer, size); } con->output->produced = (con->output->produced + size) % con->outmod; __sync_synchronize(); xc_evtchn_notify(con->iface->ec, con->port); }
static int process_render(struct userdata *u) { pa_assert(u); if (u->memchunk.length <= 0) pa_sink_render(u->sink, ioring->usable_buffer_space, &u->memchunk); pa_assert(u->memchunk.length > 0); xc_evtchn_notify(xce, xen_evtchn_port); for (;;) { ssize_t l; void *p; p = pa_memblock_acquire(u->memchunk.memblock); /* xen: write data to ring buffer & notify backend */ l = ring_write(ioring, (uint8_t*)p + u->memchunk.index, u->memchunk.length); pa_memblock_release(u->memchunk.memblock); pa_assert(l != 0); if (l < 0) { if (errno == EINTR) continue; else if (errno == EAGAIN) return 0; else { pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno)); return -1; } } else { u->memchunk.index += (size_t) l; u->memchunk.length -= (size_t) l; if (u->memchunk.length <= 0) { pa_memblock_unref(u->memchunk.memblock); pa_memchunk_reset(&u->memchunk); } } return 0; } }
static int suspend_guest(xc_interface *xch, xc_evtchn *xce, int domid, int *evtchn, int *lockfd) { int port, rc, suspend_evtchn = -1; *lockfd = -1; if (!evtchn) return -1; port = xs_suspend_evtchn_port(domid); if (port < 0) { fprintf(stderr, "DOM%d: No suspend port, try live migration\n", domid); goto failed; } suspend_evtchn = xc_suspend_evtchn_init_exclusive(xch, xce, domid, port, lockfd); if (suspend_evtchn < 0) { fprintf(stderr, "Suspend evtchn initialization failed\n"); goto failed; } *evtchn = suspend_evtchn; rc = xc_evtchn_notify(xce, suspend_evtchn); if (rc < 0) { fprintf(stderr, "Failed to notify suspend channel: errno %d\n", rc); goto failed; } if (xc_await_suspend(xch, xce, suspend_evtchn) < 0) { fprintf(stderr, "Suspend Failed\n"); goto failed; } return 0; failed: if (suspend_evtchn != -1) xc_suspend_evtchn_release(xch, xce, domid, suspend_evtchn, lockfd); return -1; }
static void xen_cleanup() { char keybuf[64]; /*XXX hardcoded*/ munmap((void*)gref.index, 4096); set_state(XenbusStateClosing); /* send one last event to unblock the backend */ xc_evtchn_notify(xce, xen_evtchn_port); /* close xen interfaces */ xc_evtchn_close(xce); xc_interface_close(xch); /* delete xenstore keys */ publish_param_int("state", XenbusStateClosed); snprintf(keybuf, sizeof(keybuf), "device/audio/%d", device_id); xs_rm(xsh, 0, keybuf); xs_daemon_close(xsh); }
static void readRaw(ivc_connection_t *con, void *buffer, uint32_t size) { uint32_t off = con->input->consumed % con->insize; void *basep = (void*)((uintptr_t)con->inbuf + off); if(off + size > con->insize) { /* we need to split this up, as we're wrapping around */ uint32_t part1sz = con->insize - off; memcpy(buffer, basep, part1sz); memcpy((void*)((uintptr_t)buffer + part1sz), con->inbuf, size - part1sz); } else { /* we can just write it in directly here */ memcpy(buffer, basep, size); } con->input->consumed = (con->input->consumed + size) % con->inmod; __sync_synchronize(); xc_evtchn_notify(con->iface->ec, con->port); }
/* Send an event to the keyboard frontend driver */ static int xenfb_kbd_event(struct xenfb *xenfb, union xenkbd_in_event *event) { uint32_t prod; struct xenkbd_page *page = xenfb->kbd.page; if (xenfb->kbd.state != XenbusStateConnected) return 0; prod = page->in_prod; if (prod - page->in_cons == XENKBD_IN_RING_LEN) { errno = EAGAIN; return -1; } xen_mb(); /* ensure ring space available */ XENKBD_IN_RING_REF(page, prod) = *event; xen_wmb(); /* ensure ring contents visible */ page->in_prod = prod + 1; return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); }
/** * Issue a suspend request to a dedicated event channel in the guest, and * receive the acknowledgement from the subscribe event channel. */ static int evtchn_suspend(void) { int rc; rc = xc_evtchn_notify(si.xce, si.suspend_evtchn); if (rc < 0) { warnx("failed to notify suspend request channel: %d", rc); return 0; } if (await_suspend() < 0) { warnx("suspend failed"); return 0; } /* notify xend that it can do device migration */ printf("suspended\n"); fflush(stdout); return 1; }
static void xenfb_on_fb_event(struct xenfb *xenfb) { uint32_t prod, cons; struct xenfb_page *page = xenfb->fb.page; prod = page->out_prod; if (prod == page->out_cons) return; rmb(); /* ensure we see ring contents up to prod */ for (cons = page->out_cons; cons != prod; cons++) { union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons); int x, y, w, h; switch (event->type) { case XENFB_TYPE_UPDATE: x = MAX(event->update.x, 0); y = MAX(event->update.y, 0); w = MIN(event->update.width, xenfb->width - x); h = MIN(event->update.height, xenfb->height - y); if (w < 0 || h < 0) { fprintf(stderr, "%s bogus update ignored\n", xenfb->fb.nodename); break; } if (x != event->update.x || y != event->update.y || w != event->update.width || h != event->update.height) { fprintf(stderr, "%s bogus update clipped\n", xenfb->fb.nodename); break; } xenfb_guest_copy(xenfb, x, y, w, h); break; } } mb(); /* ensure we're done with ring contents */ page->out_cons = cons; xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port); }
libvchan_t *libvchan_client_init(int domain, int port) { char xs_path[255]; char xs_path_watch[255]; libvchan_t *ctrl; xc_interface *xc_handle; struct xs_handle *xs; char **vec; unsigned int count, len; char *dummy = NULL; char *own_domid = NULL; xc_handle = xc_interface_open(NULL, NULL, 0); if (!xc_handle) { /* error already logged by xc_interface_open */ goto err; } /* wait for server to appear */ xs = xs_open(0); if (!xs) { perror("xs_open"); goto err_xc; } len = 0; if (!xs_watch(xs, "domid", "domid")) { fprintf(stderr, "Cannot setup xenstore watch\n"); goto err_xs; } if (!xs_watch(xs, "@releaseDomain", "release")) { fprintf(stderr, "Cannot setup xenstore watch\n"); goto err_xs; } while (!dummy || !len) { vec = xs_read_watch(xs, &count); if (vec) { if (strcmp(vec[XS_WATCH_TOKEN], "domid") == 0) { /* domid have changed */ if (own_domid) { free(own_domid); own_domid = NULL; xs_unwatch(xs, xs_path_watch, xs_path_watch); } } free(vec); } if (!own_domid) { /* construct xenstore path on first iteration and on every domid * change detected (save+restore case) */ own_domid = xs_read(xs, 0, "domid", &len); if (!own_domid) { fprintf(stderr, "Cannot get own domid\n"); goto err_xs; } if (atoi(own_domid) == domain) { fprintf(stderr, "Loopback vchan connection not supported\n"); free(own_domid); goto err_xs; } snprintf(xs_path, sizeof(xs_path), "/local/domain/%d/data/vchan/%s/%d", domain, own_domid, port); /* watch on this key as we might not have access to the whole directory */ snprintf(xs_path_watch, sizeof(xs_path_watch), "%s/event-channel", xs_path); if (!xs_watch(xs, xs_path_watch, xs_path_watch)) { fprintf(stderr, "Cannot setup watch on %s\n", xs_path_watch); free(own_domid); goto err_xs; } } dummy = xs_read(xs, 0, xs_path_watch, &len); if (dummy) free(dummy); else { if (!libvchan__check_domain_alive(xc_handle, domain)) { fprintf(stderr, "domain dead\n"); goto err_xs; } } } if (own_domid) free(own_domid); xs_close(xs); ctrl = malloc(sizeof(*ctrl)); if (!ctrl) return NULL; ctrl->xs_path = NULL; ctrl->xenvchan = libxenvchan_client_init(NULL, domain, xs_path); if (!ctrl->xenvchan) { free(ctrl); return NULL; } ctrl->xenvchan->blocking = 1; /* notify server */ xc_evtchn_notify(ctrl->xenvchan->event, ctrl->xenvchan->event_port); ctrl->remote_domain = domain; ctrl->xc_handle = xc_handle; return ctrl; err_xs: xs_close(xs); err_xc: xc_interface_close(xc_handle); err: return NULL; }
static int do_notify(struct libvchan *ctrl) { return xc_evtchn_notify(ctrl->evfd, ctrl->evport); }
static void *handle_mount(void *data) { int more, notify; struct fs_mount *mount = (struct fs_mount *)data; printf("Starting a thread for mount: %d\n", mount->mount_id); allocate_request_array(mount); for(;;) { int nr_consumed=0; RING_IDX cons, rp; struct fsif_request *req; handle_aio_events(mount); moretodo: rp = mount->ring.sring->req_prod; xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ while ((cons = mount->ring.req_cons) != rp) { int i; struct fs_op *op; printf("Got a request at %d (of %d)\n", cons, RING_SIZE(&mount->ring)); req = RING_GET_REQUEST(&mount->ring, cons); printf("Request type=%d\n", req->type); for(i=0;;i++) { op = fsops[i]; if(op == NULL) { /* We've reached the end of the array, no appropirate * handler found. Warn, ignore and continue. */ printf("WARN: Unknown request type: %d\n", req->type); mount->ring.req_cons++; break; } if(op->type == req->type) { /* There needs to be a dispatch handler */ assert(op->dispatch_handler != NULL); op->dispatch_handler(mount, req); break; } } nr_consumed++; } printf("Backend consumed: %d requests\n", nr_consumed); RING_FINAL_CHECK_FOR_REQUESTS(&mount->ring, more); if(more) goto moretodo; RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&mount->ring, notify); printf("Pushed responces and notify=%d\n", notify); if(notify) xc_evtchn_notify(mount->evth, mount->local_evtchn); } printf("Destroying thread for mount: %d\n", mount->mount_id); xc_gnttab_munmap(mount->gnth, mount->ring.sring, 1); xc_gnttab_close(mount->gnth); xc_evtchn_unbind(mount->evth, mount->local_evtchn); xc_evtchn_close(mount->evth); free(mount->frontend); pthread_exit(NULL); }
int xen_be_send_notify(struct XenDevice *xendev) { return xc_evtchn_notify(xendev->evtchndev, xendev->local_port); }