]> xenbits.xensource.com Git - people/liuw/libxenctrl-split/mini-os.git/commitdiff
minios: refactor xenbus state machine
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 3 Jun 2009 10:09:14 +0000 (11:09 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 3 Jun 2009 10:09:14 +0000 (11:09 +0100)
Implement xenbus_wait_for_state_change and xenbus_switch_state and
change the various frontends to use the two functions and do proper
error checking.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
blkfront.c
fbfront.c
include/xenbus.h
netfront.c
pcifront.c
xenbus/xenbus.c

index 1534747acb52fc14bd0c2a84263e537bc8ea0875..bba1a2ffa654ada4ed2f544abc43e3722bab6ac8 100644 (file)
@@ -149,8 +149,12 @@ again:
         goto abort_transaction;
     }
 
-    err = xenbus_printf(xbt, nodename, "state", "%u",
-            4); /* connected */
+    snprintf(path, sizeof(path), "%s/state", nodename);
+    err = xenbus_switch_state(xbt, path, XenbusStateConnected);
+    if (err) {
+        message = "switching state";
+        goto abort_transaction;
+    }
 
 
     err = xenbus_transaction_end(xbt, 0, &retry);
@@ -179,6 +183,7 @@ done:
     dev->handle = strtoul(strrchr(nodename, '/')+1, NULL, 0);
 
     {
+        XenbusState state;
         char path[strlen(dev->backend) + 1 + 19 + 1];
         snprintf(path, sizeof(path), "%s/mode", dev->backend);
         msg = xenbus_read(XBT_NIL, path, &c);
@@ -196,7 +201,15 @@ done:
 
         xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
 
-        xenbus_wait_for_value(path, "4", &dev->events);
+        msg = NULL;
+        state = xenbus_read_integer(path);
+        while (msg == NULL && state < XenbusStateConnected)
+            msg = xenbus_wait_for_state_change(path, &state, &dev->events);
+        if (msg != NULL || state != XenbusStateConnected) {
+            printk("backend not available, state=%d\n", state);
+            xenbus_unwatch_path(XBT_NIL, path);
+            goto error;
+        }
 
         snprintf(path, sizeof(path), "%s/info", dev->backend);
         dev->info.info = xenbus_read_integer(path);
@@ -230,25 +243,48 @@ error:
 
 void shutdown_blkfront(struct blkfront_dev *dev)
 {
-    char* err;
-    char *nodename = dev->nodename;
+    char* err = NULL;
+    XenbusState state;
 
     char path[strlen(dev->backend) + 1 + 5 + 1];
+    char nodename[strlen(dev->nodename) + 1 + 5 + 1];
 
     blkfront_sync(dev);
 
-    printk("close blk: backend at %s\n",dev->backend);
+    printk("close blk: backend=%s node=%s\n", dev->backend, dev->nodename);
 
     snprintf(path, sizeof(path), "%s/state", dev->backend);
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
-    xenbus_wait_for_value(path, "5", &dev->events);
-
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
-    xenbus_wait_for_value(path, "6", &dev->events);
+    snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
 
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
-    xenbus_wait_for_value(path, "2", &dev->events);
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) {
+        printk("shutdown_blkfront: error changing state to %d: %s\n",
+                XenbusStateClosing, err);
+        goto close;
+    }
+    state = xenbus_read_integer(path);
+    while (err == NULL && state < XenbusStateClosing)
+        err = xenbus_wait_for_state_change(path, &state, &dev->events);
+
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) {
+        printk("shutdown_blkfront: error changing state to %d: %s\n",
+                XenbusStateClosed, err);
+        goto close;
+    }
+    state = xenbus_read_integer(path);
+    if (state < XenbusStateClosed)
+        xenbus_wait_for_state_change(path, &state, &dev->events);
+
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) {
+        printk("shutdown_blkfront: error changing state to %d: %s\n",
+                XenbusStateInitialising, err);
+        goto close;
+    }
+    err = NULL;
+    state = xenbus_read_integer(path);
+    while (err == NULL && (state < XenbusStateInitWait || state >= XenbusStateClosed))
+        err = xenbus_wait_for_state_change(path, &state, &dev->events);
 
+close:
     xenbus_unwatch_path(XBT_NIL, path);
 
     snprintf(path, sizeof(path), "%s/ring-ref", nodename);
index fe227d6ca50c2115c41ce439900b04073d62904b..355b8eef06fd6c949101feb823b6905143f5aa02 100644 (file)
--- a/fbfront.c
+++ b/fbfront.c
@@ -121,7 +121,8 @@ again:
         }
     }
 
-    err = xenbus_printf(xbt, nodename, "state", "%u", 3); /* initialized */
+    snprintf(path, sizeof(path), "%s/state", nodename);
+    err = xenbus_switch_state(xbt, path, XenbusStateInitialised);
     if (err)
         printk("error writing initialized: %s\n", err);
 
@@ -150,17 +151,33 @@ done:
     printk("backend at %s\n", dev->backend);
 
     {
+        XenbusState state;
         char path[strlen(dev->backend) + 1 + 6 + 1];
+        char frontpath[strlen(nodename) + 1 + 6 + 1];
 
         snprintf(path, sizeof(path), "%s/state", dev->backend);
 
         xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
 
-        xenbus_wait_for_value(path, "4", &dev->events);
+        err = NULL;
+        state = xenbus_read_integer(path);
+        while (err == NULL && state < XenbusStateConnected)
+            err = xenbus_wait_for_state_change(path, &state, &dev->events);
+        if (state != XenbusStateConnected) {
+            printk("backend not available, state=%d\n", state);
+            xenbus_unwatch_path(XBT_NIL, path);
+            goto error;
+        }
 
         printk("%s connected\n", dev->backend);
 
-        err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 4); /* connected */
+        snprintf(frontpath, sizeof(frontpath), "%s/state", nodename);
+        if((err = xenbus_switch_state(XBT_NIL, frontpath, XenbusStateConnected))
+            != NULL) {
+            printk("error switching state: %s\n", err);
+            xenbus_unwatch_path(XBT_NIL, path);
+            goto error;
+        }
     }
     unmask_evtchn(dev->evtchn);
 
@@ -211,24 +228,43 @@ int kbdfront_receive(struct kbdfront_dev *dev, union xenkbd_in_event *buf, int n
 
 void shutdown_kbdfront(struct kbdfront_dev *dev)
 {
-    char* err;
-    char *nodename = dev->nodename;
+    char* err = NULL;
+    XenbusState state;
 
     char path[strlen(dev->backend) + 1 + 5 + 1];
+    char nodename[strlen(dev->nodename) + 1 + 5 + 1];
 
     printk("close kbd: backend at %s\n",dev->backend);
 
     snprintf(path, sizeof(path), "%s/state", dev->backend);
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
-    xenbus_wait_for_value(path, "5", &dev->events);
-
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
-    xenbus_wait_for_value(path, "6", &dev->events);
-
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
+    snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) {
+        printk("shutdown_kbdfront: error changing state to %d: %s\n",
+                XenbusStateClosing, err);
+        goto close_kbdfront;
+    }
+    state = xenbus_read_integer(path);
+    while (err == NULL && state < XenbusStateClosing)
+        err = xenbus_wait_for_state_change(path, &state, &dev->events);
+
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) {
+        printk("shutdown_kbdfront: error changing state to %d: %s\n",
+                XenbusStateClosed, err);
+        goto close_kbdfront;
+    }
+    state = xenbus_read_integer(path);
+    if (state < XenbusStateClosed)
+        xenbus_wait_for_state_change(path, &state, &dev->events);
+
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) {
+        printk("shutdown_kbdfront: error changing state to %d: %s\n",
+                XenbusStateInitialising, err);
+        goto close_kbdfront;
+    }
     // does not work yet.
     //xenbus_wait_for_value(path, "2", &dev->events);
 
+close_kbdfront:
     xenbus_unwatch_path(XBT_NIL, path);
 
     snprintf(path, sizeof(path), "%s/page-ref", nodename);
@@ -432,8 +468,12 @@ again:
         goto abort_transaction;
     }
 
-    err = xenbus_printf(xbt, nodename, "state", "%u", 3); /* initialized */
-
+    snprintf(path, sizeof(path), "%s/state", nodename);
+    err = xenbus_switch_state(xbt, path, XenbusStateInitialised);
+    if (err) {
+        message = "switching state";
+        goto abort_transaction;
+    }
 
     err = xenbus_transaction_end(xbt, 0, &retry);
     if (retry) {
@@ -459,20 +499,36 @@ done:
     printk("backend at %s\n", dev->backend);
 
     {
+        XenbusState state;
         char path[strlen(dev->backend) + 1 + 14 + 1];
+        char frontpath[strlen(nodename) + 1 + 6 + 1];
 
         snprintf(path, sizeof(path), "%s/state", dev->backend);
 
         xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
 
-        xenbus_wait_for_value(path, "4", &dev->events);
+        err = NULL;
+        state = xenbus_read_integer(path);
+        while (err == NULL && state < XenbusStateConnected)
+            err = xenbus_wait_for_state_change(path, &state, &dev->events);
+        if (state != XenbusStateConnected) {
+            printk("backend not available, state=%d\n", state);
+            xenbus_unwatch_path(XBT_NIL, path);
+            goto error;
+        }
 
         printk("%s connected\n", dev->backend);
 
         snprintf(path, sizeof(path), "%s/request-update", dev->backend);
         dev->request_update = xenbus_read_integer(path);
 
-        err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 4); /* connected */
+        snprintf(frontpath, sizeof(frontpath), "%s/state", nodename);
+        if ((err = xenbus_switch_state(XBT_NIL, frontpath, XenbusStateConnected))
+            != NULL) {
+            printk("error switching state: %s\n", err);
+            xenbus_unwatch_path(XBT_NIL, path);
+            goto error;
+        }
     }
     unmask_evtchn(dev->evtchn);
 
@@ -551,24 +607,43 @@ void fbfront_resize(struct fbfront_dev *dev, int width, int height, int stride,
 
 void shutdown_fbfront(struct fbfront_dev *dev)
 {
-    char* err;
-    char *nodename = dev->nodename;
+    char* err = NULL;
+    XenbusState state;
 
     char path[strlen(dev->backend) + 1 + 5 + 1];
+    char nodename[strlen(dev->nodename) + 1 + 5 + 1];
 
     printk("close fb: backend at %s\n",dev->backend);
 
     snprintf(path, sizeof(path), "%s/state", dev->backend);
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
-    xenbus_wait_for_value(path, "5", &dev->events);
-
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
-    xenbus_wait_for_value(path, "6", &dev->events);
-
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
+    snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) {
+        printk("shutdown_fbfront: error changing state to %d: %s\n",
+                XenbusStateClosing, err);
+        goto close_fbfront;
+    }
+    state = xenbus_read_integer(path);
+    while (err == NULL && state < XenbusStateClosing)
+        err = xenbus_wait_for_state_change(path, &state, &dev->events);
+
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) {
+        printk("shutdown_fbfront: error changing state to %d: %s\n",
+                XenbusStateClosed, err);
+        goto close_fbfront;
+    }
+    state = xenbus_read_integer(path);
+    if (state < XenbusStateClosed)
+        xenbus_wait_for_state_change(path, &state, &dev->events);
+
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) {
+        printk("shutdown_fbfront: error changing state to %d: %s\n",
+                XenbusStateInitialising, err);
+        goto close_fbfront;
+    }
     // does not work yet
     //xenbus_wait_for_value(path, "2", &dev->events);
 
+close_fbfront:
     xenbus_unwatch_path(XBT_NIL, path);
 
     snprintf(path, sizeof(path), "%s/page-ref", nodename);
index 30a1c081432c8c4f00ea142bfcf4c79f99469e45..de618fcfa5a32158332c6b1737f94471fd7bcfbd 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef XENBUS_H__
 #define XENBUS_H__
 
+#include <xen/io/xenbus.h>
+
 typedef unsigned long xenbus_transaction_t;
 #define XBT_NIL ((xenbus_transaction_t)0)
 
@@ -27,6 +29,8 @@ extern struct wait_queue_head xenbus_watch_queue;
 void xenbus_wait_for_watch(xenbus_event_queue *queue);
 char **xenbus_wait_for_watch_return(xenbus_event_queue *queue);
 char* xenbus_wait_for_value(const char *path, const char *value, xenbus_event_queue *queue);
+char *xenbus_wait_for_state_change(const char* path, XenbusState *state, xenbus_event_queue *queue);
+char *xenbus_switch_state(xenbus_transaction_t xbt, const char* path, XenbusState state);
 
 /* When no token is provided, use a global queue. */
 #define XENBUS_WATCH_PATH_TOKEN "xenbus_watch_path"
index a23576937781a6eb7db26550b5e97a40ab299013..ea092df0741ea75de3e0552c1135151e631d47c0 100644 (file)
@@ -405,9 +405,12 @@ again:
         goto abort_transaction;
     }
 
-    err = xenbus_printf(xbt, nodename, "state", "%u",
-            4); /* connected */
-
+    snprintf(path, sizeof(path), "%s/state", nodename);
+    err = xenbus_switch_state(xbt, path, XenbusStateConnected);
+    if (err) {
+        message = "switching state";
+        goto abort_transaction;
+    }
 
     err = xenbus_transaction_end(xbt, 0, &retry);
     if (retry) {
@@ -437,12 +440,21 @@ done:
     printk("mac is %s\n",dev->mac);
 
     {
+        XenbusState state;
         char path[strlen(dev->backend) + 1 + 5 + 1];
         snprintf(path, sizeof(path), "%s/state", dev->backend);
 
         xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
 
-        xenbus_wait_for_value(path, "4", &dev->events);
+        err = NULL;
+        state = xenbus_read_integer(path);
+        while (err == NULL && state < XenbusStateConnected)
+            err = xenbus_wait_for_state_change(path, &state, &dev->events);
+        if (state != XenbusStateConnected) {
+            printk("backend not avalable, state=%d\n", state);
+            xenbus_unwatch_path(XBT_NIL, path);
+            goto error;
+        }
 
         if (ip) {
             snprintf(path, sizeof(path), "%s/ip", dev->backend);
@@ -490,24 +502,46 @@ int netfront_tap_open(char *nodename) {
 
 void shutdown_netfront(struct netfront_dev *dev)
 {
-    char* err;
-    char *nodename = dev->nodename;
+    char* err = NULL;
+    XenbusState state;
 
     char path[strlen(dev->backend) + 1 + 5 + 1];
+    char nodename[strlen(dev->nodename) + 1 + 5 + 1];
 
     printk("close network: backend at %s\n",dev->backend);
 
     snprintf(path, sizeof(path), "%s/state", dev->backend);
+    snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
 
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
-    xenbus_wait_for_value(path, "5", &dev->events);
-
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
-    xenbus_wait_for_value(path, "6", &dev->events);
-
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
-    xenbus_wait_for_value(path, "2", &dev->events);
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) {
+        printk("shutdown_netfront: error changing state to %d: %s\n",
+                XenbusStateClosing, err);
+        goto close;
+    }
+    state = xenbus_read_integer(path);
+    while (err == NULL && state < XenbusStateClosing)
+        err = xenbus_wait_for_state_change(path, &state, &dev->events);
+
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) {
+        printk("shutdown_netfront: error changing state to %d: %s\n",
+                XenbusStateClosed, err);
+        goto close;
+    }
+    state = xenbus_read_integer(path);
+    if (state < XenbusStateClosed)
+        xenbus_wait_for_state_change(path, &state, &dev->events);
+
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) {
+        printk("shutdown_netfront: error changing state to %d: %s\n",
+                XenbusStateInitialising, err);
+        goto close;
+    }
+    err = NULL;
+    state = xenbus_read_integer(path);
+    while (err == NULL && (state < XenbusStateInitWait || state >= XenbusStateClosed))
+        err = xenbus_wait_for_state_change(path, &state, &dev->events);
 
+close:
     xenbus_unwatch_path(XBT_NIL, path);
 
     snprintf(path, sizeof(path), "%s/tx-ring-ref", nodename);
index 5b68d86b5686995be3582bae828dd37559db371e..70ea89b82db31ea199c74cb9a262e7125f8fa85a 100644 (file)
@@ -111,9 +111,12 @@ again:
         goto abort_transaction;
     }
 
-    err = xenbus_printf(xbt, nodename, "state", "%u",
-            3); /* initialised */
-
+    snprintf(path, sizeof(path), "%s/state", nodename);
+    err = xenbus_switch_state(xbt, path, XenbusStateInitialised);
+    if (err) {
+        message = "switching state";
+        goto abort_transaction;
+    }
 
     err = xenbus_transaction_end(xbt, 0, &retry);
     if (retry) {
@@ -140,13 +143,29 @@ done:
 
     {
         char path[strlen(dev->backend) + 1 + 5 + 1];
+        char frontpath[strlen(nodename) + 1 + 5 + 1];
+        XenbusState state;
         snprintf(path, sizeof(path), "%s/state", dev->backend);
 
         xenbus_watch_path_token(XBT_NIL, path, path, &dev->events);
 
-        xenbus_wait_for_value(path, "4", &dev->events);
+        err = NULL;
+        state = xenbus_read_integer(path);
+        while (err == NULL && state < XenbusStateConnected)
+            err = xenbus_wait_for_state_change(path, &state, &dev->events);
+        if (state != XenbusStateConnected) {
+            printk("backend not avalable, state=%d\n", state);
+            xenbus_unwatch_path(XBT_NIL, path);
+            goto error;
+        }
 
-        xenbus_printf(xbt, nodename, "state", "%u", 4); /* connected */
+        snprintf(frontpath, sizeof(frontpath), "%s/state", nodename);
+        if ((err = xenbus_switch_state(XBT_NIL, frontpath, XenbusStateConnected))
+            != NULL) {
+            printk("error switching state %s\n", err);
+            xenbus_unwatch_path(XBT_NIL, path);
+            goto error;
+        }
     }
     unmask_evtchn(dev->evtchn);
 
@@ -190,23 +209,45 @@ void pcifront_scan(struct pcifront_dev *dev, void (*func)(unsigned int domain, u
 
 void shutdown_pcifront(struct pcifront_dev *dev)
 {
-    char* err;
-    char *nodename = dev->nodename;
+    char* err = NULL;
+    XenbusState state;
 
     char path[strlen(dev->backend) + 1 + 5 + 1];
+    char nodename[strlen(dev->nodename) + 1 + 5 + 1];
 
     printk("close pci: backend at %s\n",dev->backend);
 
     snprintf(path, sizeof(path), "%s/state", dev->backend);
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 5); /* closing */
-    xenbus_wait_for_value(path, "5", &dev->events);
-
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 6);
-    xenbus_wait_for_value(path, "6", &dev->events);
-
-    err = xenbus_printf(XBT_NIL, nodename, "state", "%u", 1);
-    xenbus_wait_for_value(path, "2", &dev->events);
+    snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename);
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) {
+        printk("shutdown_pcifront: error changing state to %d: %s\n",
+                XenbusStateClosing, err);
+        goto close_pcifront;
+    }
+    state = xenbus_read_integer(path);
+    while (err == NULL && state < XenbusStateClosing)
+        err = xenbus_wait_for_state_change(path, &state, &dev->events);
+
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) {
+        printk("shutdown_pcifront: error changing state to %d: %s\n",
+                XenbusStateClosed, err);
+        goto close_pcifront;
+    }
+    state = xenbus_read_integer(path);
+    if (state < XenbusStateClosed)
+        xenbus_wait_for_state_change(path, &state, &dev->events);
+
+    if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) {
+        printk("shutdown_pcifront: error changing state to %d: %s\n",
+                XenbusStateInitialising, err);
+        goto close_pcifront;
+    }
+    err = NULL;
+    state = xenbus_read_integer(path);
+    while (err == NULL && (state < XenbusStateInitWait || state >= XenbusStateClosed))
+        err = xenbus_wait_for_state_change(path, &state, &dev->events);
 
+close_pcifront:
     xenbus_unwatch_path(XBT_NIL, path);
 
     snprintf(path, sizeof(path), "%s/info-ref", nodename);
index 5ed42a3da75db4b308ed576c3c926e9e935bd84c..958e010dab3bb3deecb98a59555c6f3562d408dd 100644 (file)
@@ -120,6 +120,70 @@ char* xenbus_wait_for_value(const char* path, const char* value, xenbus_event_qu
     return NULL;
 }
 
+char *xenbus_switch_state(xenbus_transaction_t xbt, const char* path, XenbusState state)
+{
+    char *current_state;
+    char *msg = NULL;
+    char *msg2 = NULL;
+    char value[2];
+    XenbusState rs;
+    int xbt_flag = 0;
+    int retry = 0;
+
+    do {
+        if (xbt == XBT_NIL) {
+            xenbus_transaction_start(&xbt);
+            xbt_flag = 1;
+        }
+
+        msg = xenbus_read(xbt, path, &current_state);
+        if (msg) goto exit;
+
+        rs = (XenbusState) (current_state[0] - '0');
+        free(current_state);
+        if (rs == state) {
+            msg = NULL;
+            goto exit;
+        }
+
+        snprintf(value, 2, "%d", state);
+        msg = xenbus_write(xbt, path, value);
+
+exit:
+        if (xbt_flag)
+            msg2 = xenbus_transaction_end(xbt, 0, &retry);
+        if (msg == NULL && msg2 != NULL)
+            msg = msg2;
+    } while (retry);
+
+    return msg;
+}
+
+char *xenbus_wait_for_state_change(const char* path, XenbusState *state, xenbus_event_queue *queue)
+{
+    if (!queue)
+        queue = &xenbus_events;
+    for(;;)
+    {
+        char *res, *msg;
+        XenbusState rs;
+
+        msg = xenbus_read(XBT_NIL, path, &res);
+        if(msg) return msg;
+
+        rs = (XenbusState) (res[0] - 48);
+        free(res);
+
+        if (rs == *state)
+            xenbus_wait_for_watch(queue);
+        else {
+            *state = rs;
+            break;
+        }
+    }
+    return NULL;
+}
+
 
 static void xenbus_thread_func(void *ign)
 {