XenDomainWatcher::XenDomainWatcher( LogHelper *logHelper ) : xsh_( NULL ), xci_( NULL ), introduceToken_( "introduce" ), releaseToken_( "release" ), logHelper_( logHelper ) { xsh_ = xs_open( 0 ); if ( !xsh_ ) throw Exception( "xs_open() failed" ); if ( !xs_watch( xsh_, "@introduceDomain", introduceToken_.c_str() ) ) { xs_close( xsh_ ); throw Exception( "xs_watch() failed" ); } if ( !xs_watch( xsh_, "@releaseDomain", releaseToken_.c_str() ) ) { xs_unwatch( xsh_, "@introduceDomain", introduceToken_.c_str() ); xs_close( xsh_ ); throw Exception( "xs_watch() failed" ); } xci_ = xc_interface_open( NULL, NULL, 0 ); if ( !xci_ ) { xs_unwatch( xsh_, "@introduceDomain", introduceToken_.c_str() ); xs_unwatch( xsh_, "@releaseDomain", releaseToken_.c_str() ); xs_close( xsh_ ); throw Exception( "xc_interface_init() failed" ); } }
XenDomainWatcher::~XenDomainWatcher() { xs_unwatch( xsh_, "@introduceDomain", introduceToken_.c_str() ); xs_unwatch( xsh_, "@releaseDomain", releaseToken_.c_str() ); xs_close( xsh_ ); xc_interface_close( xci_ ); }
char* clickos_read_handler(int domid, char *elem, char *attr) { char *ctrlpath = NULL, *elempath = NULL; char *rpath = NULL, *wpath = NULL; char *value; int err; unsigned int len = 0; struct pollfd fds[1]; if (!xs) { xenstore_init(domid); } asprintf(&ctrlpath, "/local/domain/%d/clickos/0/control", domid); asprintf(&elempath, "/local/domain/%d/clickos/0/elements", domid); asprintf(&wpath, "%s/read/%s/%s", ctrlpath, elem, attr); asprintf(&rpath, "%s/%s/%s", elempath, elem, attr); th = xs_transaction_start(xs); xenstore_write(wpath, " "); xs_transaction_end(xs, th, 0); err = xs_watch(xs, rpath, "lock"); if (!err) { printf("Error setting a watch\n"); return NULL; } fds[0].fd = xs_fileno(xs); fds[0].events = (POLLIN); while (len <= 0) { if (poll(fds, 1, 1000) <= 0) { continue; } retry_wh: th = xs_transaction_start(xs); //value = xenstore_read(rpath); value = xs_read(xs, XBT_NULL, rpath, &len); //printf("read: len %d value %s\n", len, value); if (!xs_transaction_end(xs, th, 0)) { if (errno == EAGAIN) goto retry_wh; } usleep(5000); } err = xs_unwatch(xs, rpath, "lock"); th = xs_transaction_start(xs); xs_write(xs, th, rpath, "", 0); err = xs_transaction_end(xs, th, 0); return value; }
static void release_shutdown_watch(checkpoint_state* s) { char buf[16]; if (!s->xsh) return; if (!s->watching_shutdown) return; snprintf(buf, sizeof(buf), "%u", s->domid); if (!xs_unwatch(s->xsh, "@releaseDomain", buf)) fprintf(stderr, "Could not release shutdown watch\n"); s->watching_shutdown = 0; }
void xs_node_unwatch(struct xs_handle *xsh, const char *node, const char *key, const char *token, Error **errp) { char *path; path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) : g_strdup(key); trace_xs_node_unwatch(path); if (!xs_unwatch(xsh, path, token)) { error_setg_errno(errp, errno, "failed to unwatch node '%s'", path); } g_free(path); }
/* Helper to determine if a backend device is in Created state */ static int xenfb_backend_created(struct xenfb_device *dev) { unsigned int state; unsigned int dummy; char **vec; vec = xs_read_watch(dev->xenfb->xsh, &dummy); if (!vec) return -1; free(vec); state = xenfb_read_state(dev->xenfb->xsh, dev->nodename); if (!((1 <<state) & ((1 << XenbusStateUnknown) | (1 << XenbusStateInitialising) | (1 << XenbusStateClosed) #if 1 /* TODO fudging state to permit restarting; to be removed */ | (1 << XenbusStateInitWait) | (1 << XenbusStateConnected) | (1 << XenbusStateClosing) #endif ))) { fprintf(stderr, "FB: Carry on waiting\n"); return 1; } xs_unwatch(dev->xenfb->xsh, dev->nodename, ""); switch (state) { #if 1 case XenbusStateInitWait: case XenbusStateConnected: printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */ #endif case XenbusStateInitialising: case XenbusStateClosing: case XenbusStateClosed: break; default: fprintf(stderr, "Wrong state %d\n", state); return -1; } xenfb_switch_state(dev, XenbusStateInitWait); if (xenfb_hotplug(dev) < 0) return -1; return 0; }
/* * Unsubscribe from a subscription to the status of a hotplug variable of * a device. */ int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle, const char *devtype, const char *inst, const char *token) { int rc = 0; char *path; path = get_device_variable_path(devtype, inst, "hotplug-status"); if (path == NULL) return -1; if (0 == xs_unwatch(handle, path, token)) rc = -2; free(path); return rc; }
/* adapted from the eponymous function in xc_save */ static int switch_qemu_logdirty(checkpoint_state *s, int enable) { char path[128]; char *tail, *cmd, *response; char **vec; unsigned int len; sprintf(path, "/local/domain/0/device-model/%u/logdirty/", s->domid); tail = path + strlen(path); strcpy(tail, "ret"); if (!xs_watch(s->xsh, path, "qemu-logdirty-ret")) { s->errstr = "error watching qemu logdirty return"; return -1; } /* null fire. XXX unify with shutdown watch! */ vec = xs_read_watch(s->xsh, &len); free(vec); strcpy(tail, "cmd"); cmd = enable ? "enable" : "disable"; if (!xs_write(s->xsh, XBT_NULL, path, cmd, strlen(cmd))) { s->errstr = "error signalling qemu logdirty"; return -1; } vec = xs_read_watch(s->xsh, &len); free(vec); strcpy(tail, "ret"); xs_unwatch(s->xsh, path, "qemu-logdirty-ret"); response = xs_read(s->xsh, XBT_NULL, path, &len); if (!len || strcmp(response, cmd)) { if (len) free(response); s->errstr = "qemu logdirty command failed"; return -1; } free(response); fprintf(stderr, "qemu logdirty mode: %s\n", cmd); return 0; }
/* Helper to determine if a frontend device is in Initialized state */ static int xenfb_frontend_initialized(struct xenfb_device *dev) { unsigned int state; unsigned int dummy; char **vec; vec = xs_read_watch(dev->xenfb->xsh, &dummy); if (!vec) return -1; free(vec); state = xenfb_read_state(dev->xenfb->xsh, dev->otherend); if (!((1 << state) & ((1 << XenbusStateUnknown) | (1 << XenbusStateInitialised) #if 1 /* TODO fudging state to permit restarting; to be removed */ | (1 << XenbusStateConnected) #endif ))) { fprintf(stderr, "FB: Carry on waiting\n"); return 1; } xs_unwatch(dev->xenfb->xsh, dev->otherend, ""); switch (state) { #if 1 case XenbusStateConnected: printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */ #endif case XenbusStateInitialised: break; default: return -1; } if (xenfb_bind(dev) < 0) return -1; return 0; }
static void test_many_watches(void) { HANDLE events[64]; int handles[64]; int i; char buf[64]; for (i = 0; i < 64; i++) { events[i] = CreateEvent(NULL, FALSE, FALSE, NULL); if (events[i] == INVALID_HANDLE_VALUE) win_err(0, "CreateEvent() %d in test_many_watches", i); } for (i = 0; i < 64; i++) { sprintf(buf, "data/test/key%d", i); handles[i] = xs_watch(xs_handle, buf, events[i]); if (handles[i] == -1) { fail_test(__LINE__, "couldn't watch %s: %d", buf, GetLastError()); } else { /* Wait for the watch to go idle. */ while (WaitForSingleObject(events[i], 100) != WAIT_TIMEOUT) ; } } /* Make sure that the watches all fire. */ for (i = 0; i < 64; i++) { sprintf(buf, "data/test/key%d", i); xs_write(xs_handle, buf, "foo"); if (WaitForSingleObject(events[i], 100) != WAIT_OBJECT_0) fail_test(__LINE__, "Watch %d on %s failed to fire", i, buf); } /* Cancel the watches and close the events. */ for (i = 0; i < 64; i++) { if (handles[i] >= 0) xs_unwatch(xs_handle, handles[i]); CloseHandle(events[i]); } }
/* * The caller must hold the lock on the privateData * associated with the 'conn' parameter. */ int xenStoreRemoveWatch(virConnectPtr conn, const char *path, const char *token) { size_t i; xenStoreWatchListPtr list; xenUnifiedPrivatePtr priv = conn->privateData; if (priv->xshandle == NULL) return -1; list = priv->xsWatchList; if (!list) return -1; for (i = 0; i < list->count; i++) { if (STREQ(list->watches[i]->path, path) && STREQ(list->watches[i]->token, token)) { if (!xs_unwatch(priv->xshandle, list->watches[i]->path, list->watches[i]->token)) { VIR_DEBUG("WARNING: Could not remove watch"); /* Not fatal, continue */ } VIR_FREE(list->watches[i]->path); VIR_FREE(list->watches[i]->token); VIR_FREE(list->watches[i]); VIR_DELETE_ELEMENT(list->watches, i, list->count); return 0; } } return -1; }
bool XenDomainWatcher::waitForDomainsOrTimeout( std::list<DomainInfo> &domains, int ms ) { struct pollfd fd; bool ret = false; fd.revents = 0; fd.fd = xs_fileno( xsh_ ); fd.events = POLLIN | POLLERR; int rc = poll( &fd, 1, ms ); domains.clear(); if ( rc == 0 ) return false; // timeout if ( fd.revents & POLLIN ) { unsigned int num; char **vec = xs_read_watch( xsh_, &num ); if ( vec && introduceToken_ == vec[XS_WATCH_TOKEN] ) { int domid = 1; xc_dominfo_t dominfo; int err = -1; while ( ( err = xc_domain_getinfo( xci_, domid, 1, &dominfo ) ) == 1 ) { domid = dominfo.domid + 1; if ( xs_is_domain_introduced( xsh_, dominfo.domid ) ) { // New domain if ( domIds_.find( dominfo.domid ) == domIds_.end() ) { domIds_.insert( dominfo.domid ); std::stringstream ss; ss << "/local/domain/" << dominfo.domid << "/name"; std::string path = ss.str(); errno = 0; char *name = static_cast<char *>( xs_read_timeout( xsh_, XBT_NULL, path.c_str(), NULL, 1 ) ); if ( !name && errno && logHelper_ ) logHelper_->error( std::string( "xs_read() error reading " ) + ss.str() + ": " + strerror( errno ) ); if ( name ) { // domain running or new domain w name set ss.str( "" ); ss << "/local/domain/" << dominfo.domid << "/console/tty"; path = ss.str(); DomainInfo domain; errno = 0; void *console = xs_read_timeout( xsh_, XBT_NULL, path.c_str(), NULL, 1 ); if ( !console && errno && logHelper_ ) logHelper_->error( std::string( "xs_read() error reading " ) + ss.str() + ": " + strerror( errno ) ); if ( console ) { free( console ); domain.isAlreadyRunning = true; } else { domain.isAlreadyRunning = false; } domain.name = name; free( name ); domains.push_back( domain ); ret = true; } else { // new domain, name not yet set ss.str( "" ); ss << "dom" << dominfo.domid; xs_watch( xsh_, path.c_str(), ss.str().c_str() ); } } } } if ( err == -1 && ( errno == EACCES || errno == EPERM ) ) throw Exception( "access denied for xc_domain_getinfo()" ); } if ( vec && releaseToken_ == vec[XS_WATCH_TOKEN] ) { int domid = 1; xc_dominfo_t dominfo; while ( xc_domain_getinfo( xci_, domid, 1, &dominfo ) == 1 ) { domid = dominfo.domid + 1; if ( !xs_is_domain_introduced( xsh_, dominfo.domid ) ) domIds_.erase( dominfo.domid ); } } if ( vec && !strncmp( vec[XS_WATCH_TOKEN], "dom", 3 ) ) { int domid = 1; if ( sscanf( vec[XS_WATCH_TOKEN], "dom%u", &domid ) == 1 ) { char *name = static_cast<char *>( xs_read_timeout( xsh_, XBT_NULL, vec[XS_WATCH_PATH], NULL, 1 ) ); if ( name ) { DomainInfo domain; domain.isAlreadyRunning = false; domain.name = name; free( name ); domains.push_back( domain ); xs_unwatch( xsh_, vec[XS_WATCH_PATH], vec[XS_WATCH_TOKEN] ); ret = true; } } } free( vec ); } return ret; }
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; }
int remove_base_watch(struct xs_handle *h) { if (!xs_unwatch(h, "/vss", "vss")) return -EINVAL; return 0; }
int __cdecl main() { char *vm_path, *uuid, *t; size_t l; char **contents; unsigned count; HANDLE xs_handle2; HANDLE event; HANDLE event2; int watch_h; int watch_h2; int i; DWORD status; xs_handle = xs_domain_open(); if (!xs_handle) win_err(1, "openning xenstore interface"); /* Try to give ourselves a clean place to start */ xs_remove(xs_handle, "data/test"); /* Check basic xenstore reads with relative path... */ vm_path = xs_read(xs_handle, "vm", NULL); if (!vm_path) win_err(1, "reading vm path"); if (vm_path[0] != '/') { fail_test(__LINE__, "expected vm path to be absolute, got %s", vm_path); } /* and with an absolute path. */ uuid = gather_read(&l, vm_path, "uuid", NULL); if (!uuid) win_err(1, "reading uuid"); if (l != 36) { fail_test(__LINE__, "uuid length was %d bytes, expected 36"); } if (strlen(uuid) != 36) { fail_test(__LINE__, "uuid was %s, not right length (%d, should be 36), returned length %d", uuid, strlen(uuid), l); } /* Make sure read error sets a suitable code. */ xs_read_expected_error(__LINE__, "non_existent", ERROR_FILE_NOT_FOUND); xs_read_expected_error(__LINE__, "invalid\\path", ERROR_INVALID_PARAMETER); xs_read_expected_error(__LINE__, "/local/domain/0/name", ERROR_ACCESS_DENIED); /* Test basic xs_write functionality. */ if (!xs_write(xs_handle, "data/test/key1", "data1")) { fail_test(__LINE__, "write data/test/key1 failed with %lx", GetLastError()); } else { t = xs_read(xs_handle, "data/test/key1", &l); if (!t) { fail_test(__LINE__, "error reading from data/test/key1: %lx", GetLastError()); } else { if (l != 5) { fail_test(__LINE__, "manifest length wrong reading data/test/key1: %d should be 5.", l); } if (strcmp(t, "data1")) { fail_test(__LINE__, "got wrong data reading data/test/key1: %s should be data1.", t); } free(t); } } xs_write_expected_error(__LINE__, "foo", "bar", ERROR_ACCESS_DENIED); xs_write_expected_error(__LINE__, "/foo", "bar", ERROR_ACCESS_DENIED); /* Try a very large write and make sure that it fails in the expected way. */ t = malloc(65536); memset(t, 'a', 65536); t[65535] = 0; xs_write_expected_error(__LINE__,"data/test/key1", t, ERROR_DISK_FULL); free(t); /* Test that read and write work for keys containing nul bytes. */ if (!xs_write_bin(xs_handle, "data/test/key1", "xxx\0yyy", 7)) { fail_test(__LINE__, "failed to write nul bytes (%d)", GetLastError()); } t = xs_read(xs_handle, "data/test/key1", &l); if (!t) { fail_test(__LINE__, "failed to read nul bytes (%d)", GetLastError()); } else { if (l != 7) { fail_test(__LINE__, "read with nuls: expected 7, got %d.\n", l); } else if (memcmp(t, "xxx\0yyy", 7)) { fail_test(__LINE__, "bad data from read with nuls: %s", t); } free(t); } if (!xs_remove(xs_handle, "data/test/key1")) { fail_test(__LINE__, "failed to remove data/test/key1 (%d)", GetLastError()); } xs_read_expected_error(__LINE__, "data/test/key1", ERROR_FILE_NOT_FOUND); xs_ls_expected_error(__LINE__, "data/test/key1", ERROR_FILE_NOT_FOUND); if (!xs_write(xs_handle, "data/test/key1", "data1")) { fail_test(__LINE__, "failed to rewrite data/test/key1"); } contents = xs_directory(xs_handle, "data/test/key1", &count); if (!contents) { fail_test(__LINE__, "failed to ls data/test/key1: %x", GetLastError()); } else if (count != 0) { fail_test(__LINE__, "ls data/test/key1 had %d items", count); free(contents); } else { free(contents); } if (!xs_write(xs_handle, "data/test/key1/key2", "data2")) { fail_test(__LINE__, "failed to rewrite data/test/key1/key2"); } contents = xs_directory(xs_handle, "data/test/key1", &count); if (!contents) { fail_test(__LINE__, "failed to ls data/test/key1: %x", GetLastError()); } else if (count != 1) { fail_test(__LINE__, "ls data/test/key1 had %d items", count); free(contents); } else if (strcmp(contents[0], "key2")) { fail_test(__LINE__, "ls data/test/key1 gave unexpected result %s", contents[0]); } xs_remove(xs_handle, "data/test"); /* Looks like most of the basic functionality works. Try * transactions. */ xs_handle2 = xs_domain_open(); if (!xs_handle2) win_err(1, "couldn't re-open domain interface"); if (!xs_write(xs_handle, "data/test/key1", "before")) fail_test(__LINE__, "failed to write to data/test/key1: %x", GetLastError()); if (!xs_transaction_start(xs_handle2)) win_err(1, "couldn't open a transaction on second handle"); if (!xs_write(xs_handle2, "data/test/key1", "after")) fail_test(__LINE__, "failed to write to data/test/key1 under transaction: %x", GetLastError()); if (!xs_transaction_end(xs_handle2, FALSE)) fail_test(__LINE__, "failed to write to end transaction: %x", GetLastError()); if (strcmp(xs_read(xs_handle, "data/test/key1", NULL), "after")) fail_test(__LINE__, "transaction didn't stick"); /* Now try aborting the transaction. */ if (!xs_write(xs_handle, "data/test/key1", "before")) fail_test(__LINE__, "failed to write to data/test/key1: %x", GetLastError()); if (!xs_transaction_start(xs_handle2)) win_err(1, "couldn't open a transaction on second handle"); if (!xs_write(xs_handle2, "data/test/key1", "after")) fail_test(__LINE__, "failed to write to data/test/key1 under transaction: %x", GetLastError()); if (!xs_transaction_end(xs_handle2, TRUE)) fail_test(__LINE__, "failed to write to end transaction: %x", GetLastError()); if (strcmp(xs_read(xs_handle, "data/test/key1", NULL), "before")) fail_test(__LINE__, "transaction didn't abort"); /* Try to arrange that the transaction fails. */ if (!xs_write(xs_handle, "data/test/key1", "before")) fail_test(__LINE__, "failed to write to data/test/key1: %x", GetLastError()); if (!xs_transaction_start(xs_handle2)) win_err(1, "couldn't open a transaction on second handle"); if (!xs_write(xs_handle2, "data/test/key1", "after")) fail_test(__LINE__, "failed to write to data/test/key1 under transaction: %x", GetLastError()); if (!xs_write(xs_handle, "data/test/key1", "other")) fail_test(__LINE__, "failed to write to data/test/key1: %x", GetLastError()); if (xs_transaction_end(xs_handle2, FALSE)) fail_test(__LINE__, "transaction succeeded when it shouldn't", GetLastError()); if (strcmp(xs_read(xs_handle, "data/test/key1", NULL), "other")) fail_test(__LINE__, "transaction did something strange"); if (!xs_write(xs_handle, "data/test/key1", "before1")) fail_test(__LINE__, "failed to write to data/test/key1: %x", GetLastError()); if (!xs_write(xs_handle, "data/test/key2", "before2")) fail_test(__LINE__, "failed to write to data/test/key2: %x", GetLastError()); if (!xs_transaction_start(xs_handle2)) win_err(1, "couldn't open a transaction on second handle"); if (!xs_write(xs_handle2, "data/test/key1", "after")) fail_test(__LINE__, "failed to write to data/test/key1 under transaction: %x", GetLastError()); t = xs_read(xs_handle2, "data/test/key2", NULL); if (!t) { fail_test(__LINE__, "failed to read data/test/key2 under transaction: %x", GetLastError()); } else { if (strcmp(t, "before2")) fail_test(__LINE__, "got wrong thing reading dtaa/test/key2 (%s)", t); free(t); } if (!xs_write(xs_handle, "data/test/key2", "other")) fail_test(__LINE__, "failed to write to data/test/key1: %x", GetLastError()); if (xs_transaction_end(xs_handle2, FALSE)) fail_test(__LINE__, "transaction succeeded when it shouldn't", GetLastError()); if (strcmp(xs_read(xs_handle, "data/test/key1", NULL), "before1")) fail_test(__LINE__, "transaction did something strange"); xs_daemon_close(xs_handle2); /* Try a couple of transaction error cases. */ xs_handle2 = xs_domain_open(); if (!xs_handle2) win_err(1, "couldn't re-open domain interface a second time"); if (!xs_transaction_start(xs_handle2)) win_err(1, "couldn't open a transaction for re-test"); if (xs_transaction_start(xs_handle2)) { fail_test(__LINE__, "openned two transactions on same handle"); } xs_daemon_close(xs_handle2); xs_handle2 = xs_domain_open(); if (!xs_handle2) win_err(1, "couldn't re-open domain interface a third time"); if (xs_transaction_end(xs_handle2, FALSE)) { fail_test(__LINE__, "ended transaction without starting it"); } if (!xs_transaction_start(xs_handle2)) win_err(1, "couldn't open a transaction for re-test"); if (!xs_transaction_end(xs_handle2, FALSE)) fail_test(__LINE__, "failed to end transaction"); if (xs_transaction_end(xs_handle2, FALSE)) { fail_test(__LINE__, "double-ended transaction"); } xs_daemon_close(xs_handle2); /* Transactions appear to be working, at least in their most basic form. Have a go at watches. */ event = CreateEvent(NULL, FALSE, FALSE, NULL); watch_h = xs_watch(xs_handle, "data/test/key1", event); if (watch_h < 0) { fail_test(__LINE__, "couldn't watch data/test/key1"); } else { while (WaitForSingleObject(event, 100) != WAIT_TIMEOUT) ; xs_write(xs_handle, "data/test/key1", "foo"); if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) fail_test(__LINE__, "failed wait for data/test/key1: %x", GetLastError()); xs_write(xs_handle, "data/test/key1", "foo"); if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) fail_test(__LINE__, "failed wait for data/test/key1: %x", GetLastError()); xs_write(xs_handle, "data/test/key1", "foo"); if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) fail_test(__LINE__, "failed wait for data/test/key1: %x", GetLastError()); status = WaitForSingleObject(event, 2000); if (status != WAIT_TIMEOUT) fail_test(__LINE__, "should have timed out waiting for data/test/key1 (%d, %d)", status, GetLastError()); if (!xs_unwatch(xs_handle, watch_h)) fail_test(__LINE__, "failed to unwatch"); } /* Create two watches on the same key, kill one of them, and then make sure that the other one still works. */ watch_h = xs_watch(xs_handle, "data/test/key1/subkey", event); if (watch_h < 0) { fail_test(__LINE__, "couldn't watch data/test/key1/subkey"); } else { event2 = CreateEvent(NULL, FALSE, FALSE, NULL); watch_h2 = xs_watch(xs_handle, "data/test/key1/subkey", event); if (watch_h2 < 0) { fail_test(__LINE__, "couldn't double watch data/test/key1/subkey"); } else { if (!xs_unwatch(xs_handle, watch_h2)) fail_test(__LINE__, "failed to unwatch h2"); ResetEvent(event); xs_remove(xs_handle, "data/test/key1"); if (WaitForSingleObject(event, 5000) != WAIT_OBJECT_0) fail_test(__LINE__, "failed wait for data/test/key1: %x", GetLastError()); if (!xs_unwatch(xs_handle, watch_h)) fail_test(__LINE__, "failed to unwatch"); } } /* Watch a node, then modify it in a transaction, and check that the watch fires. */ watch_h = xs_watch(xs_handle, "data/test/key1", event); if (watch_h < 0) { fail_test(__LINE__, "couldn't watch data/test/key1"); } else { for (i = 0; i < 100; i++) { ResetEvent(event); do { if (!xs_transaction_start(xs_handle)) win_err(1, "couldn't open a transaction for watch test"); xs_write(xs_handle, "data/test/key1", "foo"); } while (!xs_transaction_end(xs_handle, FALSE)); if (WaitForSingleObject(event, 5000) != WAIT_OBJECT_0) fail_test(__LINE__, "failed wait for data/test/key1(%d): %x", i, GetLastError()); } if (!xs_unwatch(xs_handle, watch_h)) fail_test(__LINE__, "failed to unwatch"); } /* Make a lot of watches, make sure they all work. */ test_many_watches(); /* Try some different sized requests */ test_write_sizes(4096); xs_daemon_close(xs_handle); run_stress(); if (failed) { printf("failed\n"); return 1; } else { printf("passed\n"); return 0; } }
static int xenpaging_wait_for_event_or_timeout(struct xenpaging *paging) { xc_interface *xch = paging->xc_handle; xc_evtchn *xce = paging->vm_event.xce_handle; char **vec, *val; unsigned int num; struct pollfd fd[2]; int port; int rc; int timeout; /* Wait for event channel and xenstore */ fd[0].fd = xc_evtchn_fd(xce); fd[0].events = POLLIN | POLLERR; fd[1].fd = xs_fileno(paging->xs_handle); fd[1].events = POLLIN | POLLERR; /* No timeout while page-out is still in progress */ timeout = paging->use_poll_timeout ? 100 : 0; rc = poll(fd, 2, timeout); if ( rc < 0 ) { if (errno == EINTR) return 0; PERROR("Poll exited with an error"); return -1; } /* First check for guest shutdown */ if ( rc && fd[1].revents & POLLIN ) { DPRINTF("Got event from xenstore\n"); vec = xs_read_watch(paging->xs_handle, &num); if ( vec ) { DPRINTF("path '%s' token '%s'\n", vec[XS_WATCH_PATH], vec[XS_WATCH_TOKEN]); if ( strcmp(vec[XS_WATCH_TOKEN], watch_token) == 0 ) { /* If our guest disappeared, set interrupt flag and fall through */ if ( xs_is_domain_introduced(paging->xs_handle, paging->vm_event.domain_id) == false ) { xs_unwatch(paging->xs_handle, "@releaseDomain", watch_token); interrupted = SIGQUIT; /* No further poll result processing */ rc = 0; } } else if ( strcmp(vec[XS_WATCH_PATH], watch_target_tot_pages) == 0 ) { int ret, target_tot_pages; val = xs_read(paging->xs_handle, XBT_NULL, vec[XS_WATCH_PATH], NULL); if ( val ) { ret = sscanf(val, "%d", &target_tot_pages); if ( ret > 0 ) { /* KiB to pages */ target_tot_pages >>= 2; if ( target_tot_pages < 0 || target_tot_pages > paging->max_pages ) target_tot_pages = paging->max_pages; paging->target_tot_pages = target_tot_pages; /* Disable poll() delay while new target is not yet reached */ paging->use_poll_timeout = 0; DPRINTF("new target_tot_pages %d\n", target_tot_pages); } free(val); } }