WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH 6/11] Xenstore watch rework

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH 6/11] Xenstore watch rework
From: Rusty Russell <rusty@xxxxxxxxxxxxxxx>
Date: Thu, 04 Aug 2005 22:31:39 +1000
Delivery-date: Thu, 04 Aug 2005 12:32:34 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Rusty Russell <rusty@xxxxxxxxxxxxxxx>
# Node ID b0de1894df67ac7c7d905bf61cdf0210b42752cc
# Parent  ba5d5bd28edf8bce89bdf9fc64047ee4f1dceded
Xenstore watch rework
Change watches to all fire simultaneously, removing priority argument.
Watches no longer fired back to connection/domain which caused event.
Fix up testsuite to match
Use state enum, rather than return value inside daemon to determine blockage

Signed-off-by: Rusty Russell <rusty@xxxxxxxxxxxxxxx>

diff -r ba5d5bd28edf -r b0de1894df67 
linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_probe.c
--- a/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Thu Aug  4 
10:43:03 2005
+++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Thu Aug  4 
11:39:03 2005
@@ -800,7 +800,6 @@
 {
         static int init_done = 0;
        static struct xenbus_watch watch = { .node = "/", 
-                                            .priority = 0, 
                                             .callback = test_callback };
 
         if(init_done) return;
diff -r ba5d5bd28edf -r b0de1894df67 
linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_xs.c
--- a/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_xs.c    Thu Aug  4 
10:43:03 2005
+++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_xs.c    Thu Aug  4 
11:39:03 2005
@@ -321,18 +321,14 @@
        return xs_single(XS_GETDOMAINPATH, domid_str, NULL);
 }
 
-static int xs_watch(const char *path, const char *token, unsigned int priority)
-{
-       char prio[32];
-       struct kvec iov[3];
-
-       sprintf(prio, "%u", priority);
+static int xs_watch(const char *path, const char *token)
+{
+       struct kvec iov[2];
+
        iov[0].iov_base = (void *)path;
        iov[0].iov_len = strlen(path) + 1;
        iov[1].iov_base = (void *)token;
        iov[1].iov_len = strlen(token) + 1;
-       iov[2].iov_base = prio;
-       iov[2].iov_len = strlen(prio) + 1;
 
        return xs_error(xs_talkv(XS_WATCH, iov, ARRAY_SIZE(iov), NULL));
 }
@@ -393,7 +389,7 @@
        BUG_ON(find_watch(token));
 
        down(&xs_lock);
-       err = xs_watch(watch->node, token, watch->priority);
+       err = xs_watch(watch->node, token);
        up(&xs_lock);
        if (!err)
                list_add(&watch->list, &watches);
diff -r ba5d5bd28edf -r b0de1894df67 
linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h
--- a/linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h  Thu Aug  4 10:43:03 2005
+++ b/linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h  Thu Aug  4 11:39:03 2005
@@ -117,7 +117,6 @@
 {
        struct list_head list;
        char *node;
-       unsigned int priority;
        void (*callback)(struct xenbus_watch *, const char *node);
 };
 
diff -r ba5d5bd28edf -r b0de1894df67 tools/python/xen/lowlevel/xs/xs.c
--- a/tools/python/xen/lowlevel/xs/xs.c Thu Aug  4 10:43:03 2005
+++ b/tools/python/xen/lowlevel/xs/xs.c Thu Aug  4 11:39:03 2005
@@ -343,7 +343,6 @@
 #define xspy_watch_doc "\n"                                            \
        "Watch a path, get notifications when it changes.\n"            \
        " path     [string] : xenstore path.\n"                         \
-       " priority [int]    : watch priority (default 0).\n"            \
        " token    [string] : returned in watch notification.\n"        \
        "\n"                                                            \
        "Returns: [int] 0 on success.\n"                                \
@@ -352,10 +351,9 @@
 
 static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds)
 {
-    static char *kwd_spec[] = { "path", "priority", "token", NULL };
+    static char *kwd_spec[] = { "path", "token", NULL };
     static char *arg_spec = "s|is";
     char *path = NULL;
-    int priority = 0;
     char *token = "";
 
     struct xs_handle *xh = xshandle(self);
@@ -365,9 +363,9 @@
     if (!xh)
        goto exit;
     if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, 
-                                     &path, &priority, &token))
-        goto exit;
-    xsval = xs_watch(xh, path, token, priority);
+                                     &path, &token))
+        goto exit;
+    xsval = xs_watch(xh, path, token);
     val = pyvalue_int(xsval);
  exit:
     return val;
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/Makefile
--- a/tools/xenstore/Makefile   Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/Makefile   Thu Aug  4 11:39:03 2005
@@ -42,9 +42,8 @@
 xs_test: xs_test.o xs_lib.o utils.o
 xs_random: xs_random.o xs_test_lib.o xs_lib.o talloc.o utils.o
 xs_stress: xs_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o
-xs_watch_stress: xs_watch_stress.o xs_test_lib.o xs_lib.o talloc.o utils.o
 
-xs_test.o xs_stress.o xs_watch_stress.o xenstored_core_test.o 
xenstored_watch_test.o xenstored_transaction_test.o xenstored_domain_test.o 
xs_random.o xs_test_lib.o talloc_test.o fake_libxc.o: CFLAGS=$(BASECFLAGS) 
$(TESTFLAGS)
+xs_test.o xs_stress.o xenstored_core_test.o xenstored_watch_test.o 
xenstored_transaction_test.o xenstored_domain_test.o xs_random.o xs_test_lib.o 
talloc_test.o fake_libxc.o: CFLAGS=$(BASECFLAGS) $(TESTFLAGS)
 
 xenstored_%_test.o: xenstored_%.c
        $(COMPILE.c) -o $@ $<
@@ -66,7 +65,7 @@
 
 clean: testsuite-clean
        rm -f *.o *.opic *.a
-       rm -f xen xenstored xs_random xs_stress xs_watch_stress
+       rm -f xen xenstored xs_random xs_stress
        rm -f xs_test xenstored_test xs_dom0_test
        -$(RM) $(PROG_DEP)
 
@@ -86,11 +85,9 @@
        $(TESTENV) ./xs_random --fast /tmp/xs_random 100000 $(RANDSEED)
        $(TESTENV) ./xs_random --fail /tmp/xs_random 10000 $(RANDSEED)
 
-stresstest: xs_stress xs_watch_stress xenstored_test
+stresstest: xs_stress xenstored_test
        rm -rf $(TESTDIR)/store $(TESTDIR)/transactions
        export $(TESTENV); PID=`./xenstored_test --output-pid 
--trace-file=/tmp/trace`; ./xs_stress 5000; ret=$$?; kill $$PID; exit $$ret
-       rm -rf $(TESTDIR)/store $(TESTDIR)/transactions
-       export $(TESTENV); PID=`./xenstored_test --output-pid`; 
./xs_watch_stress; ret=$$?; kill $$PID; exit $$ret
 
 xs_dom0_test: xs_dom0_test.o utils.o
        $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxc -o $@
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/testsuite/07watch.sh
--- a/tools/xenstore/testsuite/07watch.sh       Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/testsuite/07watch.sh       Thu Aug  4 11:39:03 2005
@@ -3,20 +3,20 @@
 # Watch something, write to it, check watch has fired.
 [ "`echo -e 'write /test create contents' | ./xs_test 2>&1`" = "" ]
 
-[ "`echo -e '1 watch /test token 100
+[ "`echo -e '1 watch /test token
 2 write /test create contents2
 1 waitwatch
 1 ackwatch token' | ./xs_test 2>&1`" = "1:/test:token" ]
 
 # Check that reads don't set it off.
-[ "`echo -e '1 watch /test token 100
+[ "`echo -e '1 watch /test token
 2 read /test
 1 waitwatch' | ./xs_test 2>&1`" = "2:contents2
 1:waitwatch timeout" ]
 
 # mkdir, setperm and rm should (also tests watching dirs)
 [ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ]
-[ "`echo -e '1 watch /dir token 100
+[ "`echo -e '1 watch /dir token
 2 mkdir /dir/newdir
 1 waitwatch
 1 ackwatch token
@@ -29,18 +29,23 @@
 1:/dir/newdir:token
 1:/dir/newdir:token" ]
 
+# We don't get a watch from our own commands.
+[ "`echo -e 'watch /dir token
+mkdir /dir/newdir
+waitwatch' | ./xs_test 2>&1`" = "waitwatch timeout" ]
+
 # ignore watches while doing commands, should work.
-[ "`echo -e 'watch /dir token 100
-write /dir/test create contents
+[ "`echo -e 'watch /dir token
+1 write /dir/test create contents
 read /dir/test
 waitwatch
 ackwatch token' | ./xs_test 2>&1`" = "contents
 /dir/test:token" ]
 
-# watch priority /test.
-[ "`echo -e '1 watch /dir token1 1
-3 watch /dir token3 3
-2 watch /dir token2 2
+# watch priority test: all simultaneous
+[ "`echo -e '1 watch /dir token1
+3 watch /dir token3
+2 watch /dir token2
 write /dir/test create contents
 3 waitwatch
 3 ackwatch token3
@@ -52,8 +57,8 @@
 1:/dir/test:token1" ]
 
 # If one dies (without acking), the other should still get ack.
-[ "`echo -e '1 watch /dir token1 0
-2 watch /dir token2 1
+[ "`echo -e '1 watch /dir token1
+2 watch /dir token2
 write /dir/test create contents
 2 waitwatch
 2 close
@@ -62,40 +67,40 @@
 1:/dir/test:token1" ]
 
 # If one dies (without reading at all), the other should still get ack.
-[ "`echo -e '1 watch /dir token1 0
-2 watch /dir token2 1
+[ "`echo -e '1 watch /dir token1
+2 watch /dir token2
 write /dir/test create contents
 2 close
 1 waitwatch
 1 ackwatch token1' | ./xs_test 2>&1`" = "1:/dir/test:token1" ]
 
 # unwatch
-[ "`echo -e '1 watch /dir token1 0
+[ "`echo -e '1 watch /dir token1
 1 unwatch /dir token1
-1 watch /dir token2 0
+1 watch /dir token2
 2 write /dir/test2 create contents
 1 waitwatch
 1 unwatch /dir token2' | ./xs_test 2>&1`" = "1:/dir/test2:token2" ]
 
 # unwatch while watch pending.  Next watcher gets the event.
-[ "`echo -e '1 watch /dir token1 0
-2 watch /dir token2 1
+[ "`echo -e '1 watch /dir token1
+2 watch /dir token2
 write /dir/test create contents
 2 unwatch /dir token2
 1 waitwatch
 1 ackwatch token1' | ./xs_test 2>&1`" = "1:/dir/test:token1" ]
 
 # unwatch while watch pending.  Should clear this so we get next event.
-[ "`echo -e '1 watch /dir token1 0
+[ "`echo -e '1 watch /dir token1
 write /dir/test create contents
 1 unwatch /dir token1
-1 watch /dir/test token2 0
+1 watch /dir/test token2
 write /dir/test none contents2
 1 waitwatch
 1 ackwatch token2' | ./xs_test 2>&1`" = "1:/dir/test:token2" ]
 
 # check we only get notified once.
-[ "`echo -e '1 watch /test token 100
+[ "`echo -e '1 watch /test token
 2 write /test create contents2
 1 waitwatch
 1 ackwatch token
@@ -103,7 +108,7 @@
 1:waitwatch timeout" ]
 
 # watches are queued in order.
-[ "`echo -e '1 watch / token 100
+[ "`echo -e '1 watch / token
 2 write /test1 create contents
 2 write /test2 create contents
 2 write /test3 create contents
@@ -117,7 +122,7 @@
 1:/test3:token" ]
 
 # Creation of subpaths should be covered correctly.
-[ "`echo -e '1 watch / token 100
+[ "`echo -e '1 watch / token
 2 write /test/subnode create contents2
 2 write /test/subnode/subnode create contents2
 1 waitwatch
@@ -129,22 +134,22 @@
 1:waitwatch timeout" ]
 
 # Watch event must have happened before we registered interest.
-[ "`echo -e '1 watch / token 100
+[ "`echo -e '1 watch / token
 2 write /test/subnode create contents2
-2 watch / token2 0
+1 watch / token2 0
 1 waitwatch
 1 ackwatch token
-2 waitwatch' | ./xs_test 2>&1`" = "1:/test/subnode:token
-2:waitwatch timeout" ]
+1 waitwatch' | ./xs_test 2>&1`" = "1:/test/subnode:token
+1:waitwatch timeout" ]
 
 # Rm fires notification on child.
-[ "`echo -e '1 watch /test/subnode token 100
+[ "`echo -e '1 watch /test/subnode token
 2 rm /test
 1 waitwatch
 1 ackwatch token' | ./xs_test 2>&1`" = "1:/test/subnode:token" ]
 
 # Watch should not double-send after we ack, even if we did something in 
between.
-[ "`echo -e '1 watch /test2 token 100
+[ "`echo -e '1 watch /test2 token
 2 write /test2/foo create contents2
 1 waitwatch
 1 read /test2/foo
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/testsuite/08transaction.sh
--- a/tools/xenstore/testsuite/08transaction.sh Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/testsuite/08transaction.sh Thu Aug  4 11:39:03 2005
@@ -45,27 +45,27 @@
 sleep 1
 rm /test/entry1
 commit
-dir /test' | ./xs_test`" = "" ]
+dir /test' | ./xs_test --no-timeout`" = "" ]
 
 # ... as long as noone is waiting.
 [ "`echo -e '1 start /test
 2 mkdir /test/dir
 1 mkdir /test/dir
 1 dir /test
-1 commit' | ./xs_test 2>&1`" = "1:dir
+1 commit' | ./xs_test --no-timeout 2>&1`" = "1:dir
 FATAL: 1: commit: Connection timed out" ]
 
 # Events inside transactions don't trigger watches until (successful) commit.
-[ "`echo -e '1 watch /test token 100
+[ "`echo -e '1 watch /test token
 2 start /test
 2 mkdir /test/dir/sub
 1 waitwatch' | ./xs_test 2>&1`" = "1:waitwatch timeout" ]
-[ "`echo -e '1 watch /test token 100
+[ "`echo -e '1 watch /test token
 2 start /test
 2 mkdir /test/dir/sub
 2 abort
 1 waitwatch' | ./xs_test 2>&1`" = "1:waitwatch timeout" ]
-[ "`echo -e '1 watch /test token 100
+[ "`echo -e '1 watch /test token
 2 start /test
 2 mkdir /test/dir/sub
 2 commit
@@ -73,7 +73,7 @@
 1 ackwatch token' | ./xs_test 2>&1`" = "1:/test/dir/sub:token" ]
 
 # Rm inside transaction works like rm outside: children get notified.
-[ "`echo -e '1 watch /test/dir/sub token 100
+[ "`echo -e '1 watch /test/dir/sub token
 2 start /test
 2 rm /test/dir
 2 commit
diff -r ba5d5bd28edf -r b0de1894df67 
tools/xenstore/testsuite/10domain-homedir.sh
--- a/tools/xenstore/testsuite/10domain-homedir.sh      Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/testsuite/10domain-homedir.sh      Thu Aug  4 11:39:03 2005
@@ -13,7 +13,7 @@
 # Place a watch using a relative path: expect relative answer.
 [ "`echo 'introduce 1 100 7 /home
 1 mkdir foo
-1 watch foo token 0
+1 watch foo token
 write /home/foo/bar create contents
 1 waitwatch
 1 ackwatch token' | ./xs_test 2>&1`" = "handle is 1
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/testsuite/11domain-watch.sh
--- a/tools/xenstore/testsuite/11domain-watch.sh        Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/testsuite/11domain-watch.sh        Thu Aug  4 11:39:03 2005
@@ -6,7 +6,7 @@
 [ "`echo -e 'mkdir /dir' | ./xs_test 2>&1`" = "" ]
 
 [ "`echo -e 'introduce 1 100 7 /my/home
-1 watch /test token 100
+1 watch /test token
 write /test create contents2
 1 waitwatch
 1 ackwatch token
@@ -16,8 +16,8 @@
 
 # ignore watches while doing commands, should work.
 [ "`echo -e 'introduce 1 100 7 /my/home
-1 watch /dir token 100
-1 write /dir/test create contents
+1 watch /dir token
+write /dir/test create contents
 1 read /dir/test
 1 waitwatch
 1 ackwatch token
@@ -27,9 +27,9 @@
 
 # unwatch
 [ "`echo -e 'introduce 1 100 7 /my/home
-1 watch /dir token1 0
+1 watch /dir token1
 1 unwatch /dir token1
-1 watch /dir token2 0
+1 watch /dir token2
 2 write /dir/test2 create contents
 1 waitwatch
 1 unwatch /dir token2
@@ -39,8 +39,8 @@
 # unwatch while watch pending.
 [ "`echo -e 'introduce 1 100 7 /my/home
 introduce 2 101 8 /my/secondhome
-1 watch /dir token1 0
-2 watch /dir token2 1
+1 watch /dir token1
+2 watch /dir token2
 write /dir/test create contents
 2 unwatch /dir token2
 1 waitwatch
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/testsuite/12readonly.sh
--- a/tools/xenstore/testsuite/12readonly.sh    Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/testsuite/12readonly.sh    Thu Aug  4 11:39:03 2005
@@ -9,7 +9,7 @@
 
 [ "`echo 'read /test
 getperm /test
-watch /test token 0
+watch /test token
 unwatch /test token 
 start /
 commit
@@ -27,7 +27,7 @@
 
 # Check that watches work like normal.
 set -m
-[ "`echo 'watch / token 0
+[ "`echo 'watch / token
 waitwatch
 ackwatch token' | ./xs_test --readonly 2>&1`" = "/test:token" ] &
 
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_core.c
--- a/tools/xenstore/xenstored_core.c   Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/xenstored_core.c   Thu Aug  4 11:39:03 2005
@@ -51,7 +51,7 @@
 #include "xenstored_domain.h"
 
 static bool verbose;
-static LIST_HEAD(connections);
+LIST_HEAD(connections);
 static int tracefd = -1;
 
 #ifdef TESTING
@@ -335,7 +335,7 @@
        list_for_each_entry(i, &connections, list) {
                if (i->domain)
                        continue;
-               if (!i->blocked)
+               if (i->state == OK)
                        FD_SET(i->fd, inset);
                if (i->out)
                        FD_SET(i->fd, outset);
@@ -471,8 +471,7 @@
        return i;
 }
 
-/* Returns "false", meaning "connection is not blocked". */
-bool send_reply(struct connection *conn, enum xsd_sockmsg_type type,
+void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
                const void *data, unsigned int len)
 {
        struct buffered_data *bdata;
@@ -493,16 +492,15 @@
                conn->waiting_reply = bdata;
        } else
                conn->out = bdata;
-       return false;
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
-bool send_ack(struct connection *conn, enum xsd_sockmsg_type type)
-{
-       return send_reply(conn, type, "OK", sizeof("OK"));
-}
-
-bool send_error(struct connection *conn, int error)
+void send_ack(struct connection *conn, enum xsd_sockmsg_type type)
+{
+       send_reply(conn, type, "OK", sizeof("OK"));
+}
+
+void send_error(struct connection *conn, int error)
 {
        unsigned int i;
 
@@ -511,7 +509,7 @@
                        corrupt(conn, "Unknown error %i (%s)", error,
                                strerror(error));
 
-       return send_reply(conn, XS_ERROR, xsd_errors[i].errstring,
+       send_reply(conn, XS_ERROR, xsd_errors[i].errstring,
                          strlen(xsd_errors[i].errstring) + 1);
 }
 
@@ -797,7 +795,7 @@
        return false;
 }
 
-static bool send_directory(struct connection *conn, const char *node)
+static void send_directory(struct connection *conn, const char *node)
 {
        char *path, *reply = talloc_strdup(node, "");
        unsigned int reply_len = 0;
@@ -805,13 +803,17 @@
        struct dirent *dirent;
 
        node = canonicalize(conn, node);
-       if (!check_node_perms(conn, node, XS_PERM_READ))
-               return send_error(conn, errno);
+       if (!check_node_perms(conn, node, XS_PERM_READ)) {
+               send_error(conn, errno);
+               return;
+       }
 
        path = node_dir(conn->transaction, node);
        dir = talloc_opendir(path);
-       if (!dir)
-               return send_error(conn, errno);
+       if (!dir) {
+               send_error(conn, errno);
+               return;
+       }
 
        while ((dirent = readdir(*dir)) != NULL) {
                int len = strlen(dirent->d_name) + 1;
@@ -824,32 +826,35 @@
                reply_len += len;
        }
 
-       return send_reply(conn, XS_DIRECTORY, reply, reply_len);
-}
-
-static bool do_read(struct connection *conn, const char *node)
+       send_reply(conn, XS_DIRECTORY, reply, reply_len);
+}
+
+static void do_read(struct connection *conn, const char *node)
 {
        char *value;
        unsigned int size;
        int *fd;
 
        node = canonicalize(conn, node);
-       if (!check_node_perms(conn, node, XS_PERM_READ))
-               return send_error(conn, errno);
+       if (!check_node_perms(conn, node, XS_PERM_READ)) {
+               send_error(conn, errno);
+               return;
+       }
 
        fd = talloc_open(node_datafile(conn->transaction, node), O_RDONLY, 0);
        if (!fd) {
                /* Data file doesn't exist?  We call that a directory */
                if (errno == ENOENT)
                        errno = EISDIR;
-               return send_error(conn, errno);
+               send_error(conn, errno);
+               return;
        }
 
        value = read_all(fd, &size);
        if (!value)
-               return send_error(conn, errno);
-
-       return send_reply(conn, XS_READ, value, size);
+               send_error(conn, errno);
+       else
+               send_reply(conn, XS_READ, value, size);
 }
 
 /* Create a new directory.  Optionally put data in it (if data != NULL) */
@@ -893,7 +898,7 @@
 }
 
 /* path, flags, data... */
-static bool do_write(struct connection *conn, struct buffered_data *in)
+static void do_write(struct connection *conn, struct buffered_data *in)
 {
        unsigned int offset, datalen;
        char *vec[2];
@@ -902,15 +907,19 @@
        struct stat st;
 
        /* Extra "strings" can be created by binary data. */
-       if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec))
-               return send_error(conn, EINVAL);
+       if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
+               send_error(conn, EINVAL);
+               return;
+       }
 
        node = canonicalize(conn, vec[0]);
-       if (!within_transaction(conn->transaction, node))
-               return send_error(conn, EROFS);
+       if (!within_transaction(conn->transaction, node)) {
+               send_error(conn, EROFS);
+               return;
+       }
 
        if (transaction_block(conn, node))
-               return true;
+               return;
 
        offset = strlen(vec[0]) + strlen(vec[1]) + 2;
        datalen = in->used - offset;
@@ -921,193 +930,244 @@
                mode = XS_PERM_WRITE|XS_PERM_CREATE;
        else if (streq(vec[1], XS_WRITE_CREATE_EXCL))
                mode = XS_PERM_WRITE|XS_PERM_CREATE;
-       else
-               return send_error(conn, EINVAL);
-
-       if (!check_node_perms(conn, node, mode))
-               return send_error(conn, errno);
+       else {
+               send_error(conn, EINVAL);
+               return;
+       }
+
+       if (!check_node_perms(conn, node, mode)) {
+               send_error(conn, errno);
+               return;
+       }
 
        if (lstat(node_dir(conn->transaction, node), &st) != 0) {
                /* Does not exist... */
-               if (errno != ENOENT)
-                       return send_error(conn, errno);
+               if (errno != ENOENT) {
+                       send_error(conn, errno);
+                       return;
+               }
 
                /* Not going to create it? */
-               if (!(mode & XS_PERM_CREATE))
-                       return send_error(conn, ENOENT);
-
-               if (!new_directory(conn, node, in->buffer + offset, datalen))
-                       return send_error(conn, errno);
+               if (!(mode & XS_PERM_CREATE)) {
+                       send_error(conn, ENOENT);
+                       return;
+               }
+
+               if (!new_directory(conn, node, in->buffer + offset, datalen)) {
+                       send_error(conn, errno);
+                       return;
+               }
        } else {
                /* Exists... */
-               if (streq(vec[1], XS_WRITE_CREATE_EXCL))
-                       return send_error(conn, EEXIST);
+               if (streq(vec[1], XS_WRITE_CREATE_EXCL)) {
+                       send_error(conn, EEXIST);
+                       return;
+               }
 
                tmppath = tempfile(node_datafile(conn->transaction, node),
                                   in->buffer + offset, datalen);
-               if (!tmppath)
-                       return send_error(conn, errno);
+               if (!tmppath) {
+                       send_error(conn, errno);
+                       return;
+               }
 
                commit_tempfile(tmppath);
        }
 
        add_change_node(conn->transaction, node, false);
+       fire_watches(conn, node, false);
        send_ack(conn, XS_WRITE);
-       fire_watches(conn->transaction, node, false);
-       return false;
-}
-
-static bool do_mkdir(struct connection *conn, const char *node)
+}
+
+static void do_mkdir(struct connection *conn, const char *node)
 {
        node = canonicalize(conn, node);
-       if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_CREATE))
-               return send_error(conn, errno);
-
-       if (!within_transaction(conn->transaction, node))
-               return send_error(conn, EROFS);
+       if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_CREATE)) {
+               send_error(conn, errno);
+               return;
+       }
+
+       if (!within_transaction(conn->transaction, node)) {
+               send_error(conn, EROFS);
+               return;
+       }
 
        if (transaction_block(conn, node))
-               return true;
-
-       if (!new_directory(conn, node, NULL, 0))
-               return send_error(conn, errno);
+               return;
+
+       if (!new_directory(conn, node, NULL, 0)) {
+               send_error(conn, errno);
+               return;
+       }
 
        add_change_node(conn->transaction, node, false);
+       fire_watches(conn, node, false);
        send_ack(conn, XS_MKDIR);
-       fire_watches(conn->transaction, node, false);
-       return false;
-}
-
-static bool do_rm(struct connection *conn, const char *node)
+}
+
+static void do_rm(struct connection *conn, const char *node)
 {
        char *tmppath, *path;
 
        node = canonicalize(conn, node);
-       if (!check_node_perms(conn, node, XS_PERM_WRITE))
-               return send_error(conn, errno);
-
-       if (!within_transaction(conn->transaction, node))
-               return send_error(conn, EROFS);
+       if (!check_node_perms(conn, node, XS_PERM_WRITE)) {
+               send_error(conn, errno);
+               return;
+       }
+
+       if (!within_transaction(conn->transaction, node)) {
+               send_error(conn, EROFS);
+               return;
+       }
 
        if (transaction_block(conn, node))
-               return true;
-
-       if (streq(node, "/"))
-               return send_error(conn, EINVAL);
+               return;
+
+       if (streq(node, "/")) {
+               send_error(conn, EINVAL);
+               return;
+       }
 
        /* We move the directory to temporary name, destructor cleans up. */
        path = node_dir(conn->transaction, node);
        tmppath = talloc_asprintf(node, "%s.tmp", path);
        talloc_set_destructor(tmppath, destroy_path);
 
-       if (rename(path, tmppath) != 0)
-               return send_error(conn, errno);
+       if (rename(path, tmppath) != 0) {
+               send_error(conn, errno);
+               return;
+       }
 
        add_change_node(conn->transaction, node, true);
+       fire_watches(conn, node, true);
        send_ack(conn, XS_RM);
-       fire_watches(conn->transaction, node, true);
-       return false;
-}
-
-static bool do_get_perms(struct connection *conn, const char *node)
+}
+
+static void do_get_perms(struct connection *conn, const char *node)
 {
        struct xs_permissions *perms;
        char *strings;
        unsigned int len, num;
 
        node = canonicalize(conn, node);
-       if (!check_node_perms(conn, node, XS_PERM_READ))
-               return send_error(conn, errno);
+       if (!check_node_perms(conn, node, XS_PERM_READ)) {
+               send_error(conn, errno);
+               return;
+       }
 
        perms = get_perms(conn->transaction, node, &num);
-       if (!perms)
-               return send_error(conn, errno);
+       if (!perms) {
+               send_error(conn, errno);
+               return;
+       }
 
        strings = perms_to_strings(node, perms, num, &len);
        if (!strings)
-               return send_error(conn, errno);
-
-       return send_reply(conn, XS_GET_PERMS, strings, len);
-}
-
-static bool do_set_perms(struct connection *conn, struct buffered_data *in)
+               send_error(conn, errno);
+       else
+               send_reply(conn, XS_GET_PERMS, strings, len);
+}
+
+static void do_set_perms(struct connection *conn, struct buffered_data *in)
 {
        unsigned int num;
        char *node;
        struct xs_permissions *perms;
 
        num = xs_count_strings(in->buffer, in->used);
-       if (num < 2)
-               return send_error(conn, EINVAL);
+       if (num < 2) {
+               send_error(conn, EINVAL);
+               return;
+       }
 
        /* First arg is node name. */
        node = canonicalize(conn, in->buffer);
        in->buffer += strlen(in->buffer) + 1;
        num--;
 
-       if (!within_transaction(conn->transaction, node))
-               return send_error(conn, EROFS);
+       if (!within_transaction(conn->transaction, node)) {
+               send_error(conn, EROFS);
+               return;
+       }
 
        if (transaction_block(conn, node))
-               return true;
+               return;
 
        /* We must own node to do this (tools can do this too). */
-       if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_OWNER))
-               return send_error(conn, errno);
+       if (!check_node_perms(conn, node, XS_PERM_WRITE|XS_PERM_OWNER)) {
+               send_error(conn, errno);
+               return;
+       }
 
        perms = talloc_array(node, struct xs_permissions, num);
-       if (!xs_strings_to_perms(perms, num, in->buffer))
-               return send_error(conn, errno);
-
-       if (!set_perms(conn->transaction, node, perms, num))
-               return send_error(conn, errno);
+       if (!xs_strings_to_perms(perms, num, in->buffer)) {
+               send_error(conn, errno);
+               return;
+       }
+
+       if (!set_perms(conn->transaction, node, perms, num)) {
+               send_error(conn, errno);
+               return;
+       }
+
        add_change_node(conn->transaction, node, false);
+       fire_watches(conn, node, false);
        send_ack(conn, XS_SET_PERMS);
-       fire_watches(conn->transaction, node, false);
-       return false;
 }
 
 /* Process "in" for conn: "in" will vanish after this conversation, so
  * we can talloc off it for temporary variables.  May free "conn".
- * Returns true if can't complete due to block.
  */
-static bool process_message(struct connection *conn, struct buffered_data *in)
+static void process_message(struct connection *conn, struct buffered_data *in)
 {
        switch (in->hdr.msg.type) {
        case XS_DIRECTORY:
-               return send_directory(conn, onearg(in));
+               send_directory(conn, onearg(in));
+               break;
 
        case XS_READ:
-               return do_read(conn, onearg(in));
+               do_read(conn, onearg(in));
+               break;
 
        case XS_WRITE:
-               return do_write(conn, in);
+               do_write(conn, in);
+               break;
 
        case XS_MKDIR:
-               return do_mkdir(conn, onearg(in));
+               do_mkdir(conn, onearg(in));
+               break;
 
        case XS_RM:
-               return do_rm(conn, onearg(in));
+               do_rm(conn, onearg(in));
+               break;
 
        case XS_GET_PERMS:
-               return do_get_perms(conn, onearg(in));
+               do_get_perms(conn, onearg(in));
+               break;
 
        case XS_SET_PERMS:
-               return do_set_perms(conn, in);
+               do_set_perms(conn, in);
+               break;
 
        case XS_SHUTDOWN:
                /* FIXME: Implement gentle shutdown too. */
                /* Only tools can do this. */
-               if (conn->id != 0)
-                       return send_error(conn, EACCES);
-               if (!conn->can_write)
-                       return send_error(conn, EROFS);
+               if (conn->id != 0) {
+                       send_error(conn, EACCES);
+                       break;
+               }
+               if (!conn->can_write) {
+                       send_error(conn, EROFS);
+                       break;
+               }
                send_ack(conn, XS_SHUTDOWN);
                /* Everything hangs off auto-free context, freed at exit. */
                exit(0);
 
+       case XS_DEBUG:
+               if (streq(in->buffer, "print"))
+                       xprintf("debug: %s", in->buffer + get_string(in, 0));
 #ifdef TESTING
-       case XS_DEBUG: {
                /* For testing, we allow them to set id. */
                if (streq(in->buffer, "setid")) {
                        conn->id = atoi(in->buffer + get_string(in, 0));
@@ -1118,39 +1178,45 @@
                        send_ack(conn, XS_DEBUG);
                        failtest = true;
                }
-               return false;
-       }
 #endif /* TESTING */
+               break;
 
        case XS_WATCH:
-               return do_watch(conn, in);
+               do_watch(conn, in);
+               break;
 
        case XS_WATCH_ACK:
-               return do_watch_ack(conn, onearg(in));
+               do_watch_ack(conn, onearg(in));
+               break;
 
        case XS_UNWATCH:
-               return do_unwatch(conn, in);
+               do_unwatch(conn, in);
+               break;
 
        case XS_TRANSACTION_START:
-               return do_transaction_start(conn, onearg(in));
+               do_transaction_start(conn, onearg(in));
+               break;
 
        case XS_TRANSACTION_END:
-               return do_transaction_end(conn, onearg(in));
+               do_transaction_end(conn, onearg(in));
+               break;
 
        case XS_INTRODUCE:
-               return do_introduce(conn, in);
+               do_introduce(conn, in);
+               break;
 
        case XS_RELEASE:
-               return do_release(conn, onearg(in));
+               do_release(conn, onearg(in));
+               break;
 
        case XS_GETDOMAINPATH:
-               return do_get_domain_path(conn, onearg(in));
+               do_get_domain_path(conn, onearg(in));
+               break;
 
        case XS_WATCH_EVENT:
        default:
                eprintf("Client unknown operation %i", in->hdr.msg.type);
                send_error(conn, ENOSYS);
-               return false;
        }
 }
 
@@ -1164,6 +1230,8 @@
        struct buffered_data *in = NULL;
        enum xsd_sockmsg_type type = conn->in->hdr.msg.type;
        jmp_buf talloc_fail;
+
+       assert(conn->state == OK);
 
        /* For simplicity, we kill the connection on OOM. */
        talloc_set_fail_handler(out_of_mem, &talloc_fail);
@@ -1187,7 +1255,9 @@
         */
        in = talloc_steal(talloc_autofree_context(), conn->in);
        conn->in = new_buffer(conn);
-       if (process_message(conn, in)) {
+       process_message(conn, in);
+
+       if (conn->state == BLOCKED) {
                /* Blocked by transaction: queue for re-xmit. */
                talloc_free(conn->in);
                conn->in = in;
@@ -1210,7 +1280,7 @@
        int bytes;
        struct buffered_data *in;
 
-       assert(!conn->blocked);
+       assert(conn->state == OK);
        in = conn->in;
 
        /* Not finished header yet? */
@@ -1267,13 +1337,17 @@
        struct connection *i, *tmp;
 
        list_for_each_entry_safe(i, tmp, &connections, list) {
-               if (!i->blocked)
-                       continue;
-
-               if (!transaction_covering_node(i->blocked)) {
-                       talloc_free(i->blocked);
-                       i->blocked = NULL;
-                       consider_message(i);
+               switch (i->state) {
+               case BLOCKED:
+                       if (!transaction_covering_node(i->blocked_by)) {
+                               talloc_free(i->blocked_by);
+                               i->blocked_by = NULL;
+                               i->state = OK;
+                               consider_message(i);
+                       }
+                       break;
+               case OK:
+                       break;
                }
        }
 
@@ -1294,7 +1368,8 @@
        if (!new)
                return NULL;
 
-       new->blocked = false;
+       new->state = OK;
+       new->blocked_by = NULL;
        new->out = new->waiting_reply = NULL;
        new->fd = -1;
        new->id = 0;
@@ -1303,6 +1378,7 @@
        new->write = write;
        new->read = read;
        new->can_write = true;
+       INIT_LIST_HEAD(&new->watches);
 
        talloc_set_fail_handler(out_of_mem, &talloc_fail);
        if (setjmp(talloc_fail)) {
@@ -1371,12 +1447,14 @@
 
        list_for_each_entry(i, &connections, list) {
                printf("Connection %p:\n", i);
+               printf("    state = %s\n",
+                      i->state == OK ? "OK"
+                      : i->state == BLOCKED ? "BLOCKED"
+                      : "INVALID");
                if (i->id)
                        printf("    id = %i\n", i->id);
-               if (i->blocked)
-                       printf("    blocked on = %s\n", i->blocked);
-               if (i->waiting_for_ack)
-                       printf("    waiting_for_ack TRUE\n");
+               if (i->blocked_by)
+                       printf("    blocked on = %s\n", i->blocked_by);
                if (!i->in->inhdr || i->in->used)
                        printf("    got %i bytes of %s\n",
                               i->in->used, i->in->inhdr ? "header" : "data");
@@ -1431,7 +1509,6 @@
        permfile = talloc_strdup(root, "/tool/xenstored");
        if (!set_perms(NULL, permfile, &perms, 1))
                barf_perror("Could not create permissions on %s", permfile);
-
        talloc_free(root);
        if (mkdir(xs_daemon_transactions(), 0750) != 0)
                barf_perror("Could not create transaction dir %s",
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_core.h
--- a/tools/xenstore/xenstored_core.h   Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/xenstored_core.h   Thu Aug  4 11:39:03 2005
@@ -47,6 +47,14 @@
 typedef int connwritefn_t(struct connection *, const void *, unsigned int);
 typedef int connreadfn_t(struct connection *, void *, unsigned int);
 
+enum state
+{
+       /* Blocked by transaction. */
+       BLOCKED,
+       /* Completed */
+       OK,
+};
+
 struct connection
 {
        struct list_head list;
@@ -57,8 +65,11 @@
        /* Who am I?  0 for socket connections. */
        domid_t id;
 
-       /* Are we blocked waiting for a transaction to end?  Contains node. */
-       char *blocked;
+       /* Blocked on transaction? */
+       enum state state;
+
+       /* Node we are waiting for (if state == BLOCKED) */
+       char *blocked_by;
 
        /* Is this a read-only connection? */
        bool can_write;
@@ -81,10 +92,14 @@
        /* The domain I'm associated with, if any. */
        struct domain *domain;
 
+       /* My watches. */
+       struct list_head watches;
+
        /* Methods for communicating over this connection: write can be NULL */
        connwritefn_t *write;
        connreadfn_t *read;
 };
+extern struct list_head connections;
 
 /* Return length of string (including nul) at this offset. */
 unsigned int get_string(const struct buffered_data *data,
@@ -100,14 +115,14 @@
 /* Create a new buffer with lifetime of context. */
 struct buffered_data *new_buffer(void *ctx);
 
-bool send_reply(struct connection *conn, enum xsd_sockmsg_type type,
-                const void *data, unsigned int len);
+void send_reply(struct connection *conn, enum xsd_sockmsg_type type,
+               const void *data, unsigned int len);
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
-bool send_ack(struct connection *conn, enum xsd_sockmsg_type type);
+void send_ack(struct connection *conn, enum xsd_sockmsg_type type);
 
 /* Send an error: error is usually "errno". */
-bool send_error(struct connection *conn, int error);
+void send_error(struct connection *conn, int error);
 
 /* Canonicalize this path if possible. */
 char *canonicalize(struct connection *conn, const char *node);
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_domain.c
--- a/tools/xenstore/xenstored_domain.c Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/xenstored_domain.c Thu Aug  4 11:39:03 2005
@@ -239,7 +239,8 @@
         * careful that handle_input/handle_output can destroy conn.
         */
        while ((domain = find_domain(port)) != NULL) {
-               if (!domain->conn->blocked && buffer_has_input(domain->input))
+               if (domain->conn->state == OK
+                   && buffer_has_input(domain->input))
                        handle_input(domain->conn);
                else if (domain->conn->out
                         && buffer_has_output_room(domain->output))
@@ -287,33 +288,42 @@
 }
 
 /* domid, mfn, evtchn, path */
-bool do_introduce(struct connection *conn, struct buffered_data *in)
+void do_introduce(struct connection *conn, struct buffered_data *in)
 {
        struct domain *domain;
        char *vec[4];
 
-       if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec))
-               return send_error(conn, EINVAL);
-
-       if (conn->id != 0)
-               return send_error(conn, EACCES);
-
-       if (!conn->can_write)
-               return send_error(conn, EROFS);
+       if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
+               send_error(conn, EINVAL);
+               return;
+       }
+
+       if (conn->id != 0) {
+               send_error(conn, EACCES);
+               return;
+       }
+
+       if (!conn->can_write) {
+               send_error(conn, EROFS);
+               return;
+       }
 
        /* Sanity check args. */
-       if ((atoi(vec[2]) <= 0) || !is_valid_nodename(vec[3]))
-               return send_error(conn, EINVAL);
+       if ((atoi(vec[2]) <= 0) || !is_valid_nodename(vec[3])) {
+               send_error(conn, EINVAL);
+               return;
+       }
        /* Hang domain off "in" until we're finished. */
        domain = new_domain(in, atoi(vec[0]), atol(vec[1]), atol(vec[2]),
                            vec[3]);
-       if (!domain)
-               return send_error(conn, errno);
+       if (!domain) {
+               send_error(conn, errno);
+               return;
+       }
 
        /* Now domain belongs to its connection. */
        talloc_steal(domain->conn, domain);
-
-       return send_ack(conn, XS_INTRODUCE);
+       send_ack(conn, XS_INTRODUCE);
 }
 
 static struct domain *find_domain_by_domid(domid_t domid)
@@ -328,39 +338,51 @@
 }
 
 /* domid */
-bool do_release(struct connection *conn, const char *domid_str)
+void do_release(struct connection *conn, const char *domid_str)
 {
        struct domain *domain;
        domid_t domid;
 
-       if (!domid_str)
-               return send_error(conn, EINVAL);
+       if (!domid_str) {
+               send_error(conn, EINVAL);
+               return;
+       }
 
        domid = atoi(domid_str);
-       if (!domid)
-               return send_error(conn, EINVAL);
-
-       if (conn->id != 0)
-               return send_error(conn, EACCES);
+       if (!domid) {
+               send_error(conn, EINVAL);
+               return;
+       }
+
+       if (conn->id != 0) {
+               send_error(conn, EACCES);
+               return;
+       }
 
        domain = find_domain_by_domid(domid);
-       if (!domain)
-               return send_error(conn, ENOENT);
-
-       if (!domain->conn)
-               return send_error(conn, EINVAL);
-
-       talloc_free(domain->conn);
-       return send_ack(conn, XS_RELEASE);
-}
-
-bool do_get_domain_path(struct connection *conn, const char *domid_str)
+       if (!domain) {
+               send_error(conn, ENOENT);
+               return;
+       }
+
+       if (!domain->conn) {
+               send_error(conn, EINVAL);
+               return;
+       }
+
+        talloc_free(domain->conn);
+       send_ack(conn, XS_RELEASE);
+}
+
+void do_get_domain_path(struct connection *conn, const char *domid_str)
 {
        struct domain *domain;
        domid_t domid;
 
-       if (!domid_str)
-               return send_error(conn, EINVAL);
+       if (!domid_str) {
+               send_error(conn, EINVAL);
+               return;
+       }
 
        domid = atoi(domid_str);
        if (domid == DOMID_SELF)
@@ -368,11 +390,11 @@
        else
                domain = find_domain_by_domid(domid);
 
-       if (!domain)
-               return send_error(conn, ENOENT);
-
-       return send_reply(conn, XS_GETDOMAINPATH, domain->path,
-                         strlen(domain->path) + 1);
+       if (!domain) 
+               send_error(conn, ENOENT);
+       else
+               send_reply(conn, XS_GETDOMAINPATH, domain->path,
+                          strlen(domain->path) + 1);
 }
 
 static int close_xc_handle(void *_handle)
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_domain.h
--- a/tools/xenstore/xenstored_domain.h Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/xenstored_domain.h Thu Aug  4 11:39:03 2005
@@ -22,13 +22,13 @@
 void handle_event(int event_fd);
 
 /* domid, mfn, eventchn, path */
-bool do_introduce(struct connection *conn, struct buffered_data *in);
+void do_introduce(struct connection *conn, struct buffered_data *in);
 
 /* domid */
-bool do_release(struct connection *conn, const char *domid_str);
+void do_release(struct connection *conn, const char *domid_str);
 
 /* domid */
-bool do_get_domain_path(struct connection *conn, const char *domid_str);
+void do_get_domain_path(struct connection *conn, const char *domid_str);
 
 /* Returns the event channel handle */
 int domain_init(void);
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_transaction.c
--- a/tools/xenstore/xenstored_transaction.c    Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/xenstored_transaction.c    Thu Aug  4 11:39:03 2005
@@ -114,7 +114,8 @@
        trans = transaction_covering_node(node);
        if (trans) {
                start_transaction_timeout(trans);
-               conn->blocked = talloc_strdup(conn, node);
+               conn->state = BLOCKED;
+               conn->blocked_by = talloc_strdup(conn, node);
                return true;
        }
        return false;
@@ -239,20 +240,24 @@
        return true;
 }
 
-bool do_transaction_start(struct connection *conn, const char *node)
+void do_transaction_start(struct connection *conn, const char *node)
 {
        struct transaction *transaction;
        char *dir;
 
-       if (conn->transaction)
-               return send_error(conn, EBUSY);
+       if (conn->transaction) {
+               send_error(conn, EBUSY);
+               return;
+       }
 
        node = canonicalize(conn, node);
-       if (!check_node_perms(conn, node, XS_PERM_READ))
-               return send_error(conn, errno);
+       if (!check_node_perms(conn, node, XS_PERM_READ)) {
+               send_error(conn, errno);
+               return;
+       }
 
        if (transaction_block(conn, node))
-               return true;
+               return;
 
        dir = node_dir_outside_transaction(node);
 
@@ -270,18 +275,19 @@
        talloc_set_destructor(transaction, destroy_transaction);
        trace_create(transaction, "transaction");
 
-       if (!copy_dir(dir, transaction->divert))
-               return send_error(conn, errno);
+       if (!copy_dir(dir, transaction->divert)) {
+               send_error(conn, errno);
+               return;
+       }
 
        talloc_steal(conn, transaction);
        conn->transaction = transaction;
-       return send_ack(transaction->conn, XS_TRANSACTION_START);
+       send_ack(transaction->conn, XS_TRANSACTION_START);
 }
 
 static bool commit_transaction(struct transaction *trans)
 {
        char *tmp, *dir;
-       struct changed_node *i;
 
        /* Move: orig -> .old, repl -> orig.  Cleanup deletes .old. */
        dir = node_dir_outside_transaction(trans->node);
@@ -294,39 +300,44 @@
                        trans->divert, dir);
 
        trans->divert = tmp;
-
-       /* Fire off the watches for everything that changed. */
-       list_for_each_entry(i, &trans->changes, list)
-               fire_watches(NULL, i->node, i->recurse);
        return true;
 }
 
-bool do_transaction_end(struct connection *conn, const char *arg)
-{
-       if (!arg || (!streq(arg, "T") && !streq(arg, "F")))
-               return send_error(conn, EINVAL);
-
-       if (!conn->transaction)
-               return send_error(conn, ENOENT);
+void do_transaction_end(struct connection *conn, const char *arg)
+{
+       struct changed_node *i;
+       struct transaction *trans;
+
+       if (!arg || (!streq(arg, "T") && !streq(arg, "F"))) {
+               send_error(conn, EINVAL);
+               return;
+       }
+
+       if (!conn->transaction) {
+               send_error(conn, ENOENT);
+               return;
+       }
+
+       /* Set to NULL so fire_watches sends events. */
+       trans = conn->transaction;
+       conn->transaction = NULL;
+       /* Attach transaction to arg for auto-cleanup */
+       talloc_steal(arg, trans);
 
        if (streq(arg, "T")) {
-               if (conn->transaction->destined_to_fail) {
+               if (trans->destined_to_fail) {
                        send_error(conn, ETIMEDOUT);
-                       goto failed;
+                       return;
                }
-               if (!commit_transaction(conn->transaction)) {
+               if (!commit_transaction(trans)) {
                        send_error(conn, errno);
-                       goto failed;
+                       return;
                }
-       }
-
-       talloc_free(conn->transaction);
-       conn->transaction = NULL;
-       return send_ack(conn, XS_TRANSACTION_END);
-
-failed:
-       talloc_free(conn->transaction);
-       conn->transaction = NULL;
-       return false;
-}
-
+
+               /* Fire off the watches for everything that changed. */
+               list_for_each_entry(i, &trans->changes, list)
+                       fire_watches(conn, i->node, i->recurse);
+       }
+       send_ack(conn, XS_TRANSACTION_END);
+}
+
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_transaction.h
--- a/tools/xenstore/xenstored_transaction.h    Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/xenstored_transaction.h    Thu Aug  4 11:39:03 2005
@@ -22,8 +22,8 @@
 
 struct transaction;
 
-bool do_transaction_start(struct connection *conn, const char *node);
-bool do_transaction_end(struct connection *conn, const char *arg);
+void do_transaction_start(struct connection *conn, const char *node);
+void do_transaction_end(struct connection *conn, const char *arg);
 
 /* Is node covered by this transaction? */
 bool within_transaction(struct transaction *trans, const char *node);
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_watch.c
--- a/tools/xenstore/xenstored_watch.c  Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/xenstored_watch.c  Thu Aug  4 11:39:03 2005
@@ -33,69 +33,36 @@
 #include "xenstored_domain.h"
 
 /* FIXME: time out unacked watches. */
-
-/* We create this if anyone is interested "node", then we pass it from
- * watch to watch as each connection acks it.
- */
 struct watch_event
 {
-       /* The watch we are firing for (watch->events) */
+       /* The events on this watch. */
        struct list_head list;
 
-       /* Watches we need to fire for (watches[0]->events == this). */
-       struct watch **watches;
-       unsigned int num_watches;
-
-       struct timeval timeout;
-
-       /* Name of node which changed. */
-       char *node;
-
-       /* For remove, we trigger on all the children of this node too. */
-       bool recurse;
+       /* Data to send (node\0token\0). */
+       unsigned int len;
+       char *data;
 };
 
 struct watch
 {
+       /* Watches on this connection */
        struct list_head list;
-       unsigned int priority;
 
        /* Current outstanding events applying to this watch. */
        struct list_head events;
 
        /* Is this relative to connnection's implicit path? */
-       bool relative;
+       const char *relative_path;
 
        char *token;
        char *node;
-       struct connection *conn;
 };
-static LIST_HEAD(watches);
-
-static struct watch_event *get_first_event(struct connection *conn)
-{
-       struct watch *watch;
-       struct watch_event *event;
-
-       /* Find first watch with an event. */
-       list_for_each_entry(watch, &watches, list) {
-               if (watch->conn != conn)
-                       continue;
-
-               event = list_top(&watch->events, struct watch_event, list);
-               if (event)
-                       return event;
-       }
-       return NULL;
-}
 
 /* Look through our watches: if any of them have an event, queue it. */
 void queue_next_event(struct connection *conn)
 {
        struct watch_event *event;
-       const char *node;
-       char *buffer;
-       unsigned int len;
+       struct watch *watch;
 
        /* We had a reply queued already?  Send it: other end will
         * discard watch. */
@@ -110,170 +77,83 @@
        if (conn->waiting_for_ack)
                return;
 
-       event = get_first_event(conn);
-       if (!event)
-               return;
-
-       /* If we decide to cancel, we will reset this. */
-       conn->waiting_for_ack = event->watches[0];
-
-       /* If we deleted /foo and they're watching /foo/bar, that's what we
-        * tell them has changed. */
-       if (!is_child(event->node, event->watches[0]->node)) {
-               assert(event->recurse);
-               node = event->watches[0]->node;
-       } else
-               node = event->node;
-
-       /* If watch placed using relative path, give them relative answer. */
-       if (event->watches[0]->relative) {
-               node += strlen(get_implicit_path(conn));
-               if (node[0] == '/') /* Could be "". */
+       list_for_each_entry(watch, &conn->watches, list) {
+               event = list_top(&watch->events, struct watch_event, list);
+               if (event) {
+                       conn->waiting_for_ack = watch;
+                       send_reply(conn,XS_WATCH_EVENT,event->data,event->len);
+                       break;
+               }
+       }
+}
+
+static int destroy_watch_event(void *_event)
+{
+       struct watch_event *event = _event;
+
+       trace_destroy(event, "watch_event");
+       return 0;
+}
+
+static void add_event(struct watch *watch, const char *node)
+{
+       struct watch_event *event;
+
+       if (watch->relative_path) {
+               node += strlen(watch->relative_path);
+               if (*node == '/') /* Could be "" */
                        node++;
        }
 
-       /* Create reply from path and token */
-       len = strlen(node) + 1 + strlen(event->watches[0]->token) + 1;
-       buffer = talloc_array(conn, char, len);
-       strcpy(buffer, node);
-       strcpy(buffer+strlen(node)+1, event->watches[0]->token);
-       send_reply(conn, XS_WATCH_EVENT, buffer, len);
-       talloc_free(buffer);
-}
-
-static struct watch **find_watches(const char *node, bool recurse,
-                                  unsigned int *num)
-{
-       struct watch *i;
-       struct watch **ret = NULL;
-
-       *num = 0;
-
-       /* We include children too if this is an rm. */
-       list_for_each_entry(i, &watches, list) {
-               if (is_child(node, i->node) ||
-                   (recurse && is_child(i->node, node))) {
-                       (*num)++;
-                       ret = talloc_realloc(node, ret, struct watch *, *num);
-                       ret[*num - 1] = i;
-               }
-       }
-       return ret;
+       event = talloc(watch, struct watch_event);
+       event->len = strlen(node) + 1 + strlen(watch->token) + 1;
+       event->data = talloc_array(event, char, event->len);
+       strcpy(event->data, node);
+       strcpy(event->data + strlen(node) + 1, watch->token);
+       talloc_set_destructor(event, destroy_watch_event);
+       list_add_tail(&event->list, &watch->events);
+       trace_create(event, "watch_event");
 }
 
 /* FIXME: we fail to fire on out of memory.  Should drop connections. */
-void fire_watches(struct transaction *trans, const char *node, bool recurse)
-{
-       struct watch **watches;
-       struct watch_event *event;
-       unsigned int num_watches;
+void fire_watches(struct connection *conn, const char *node, bool recurse)
+{
+       struct connection *i;
+       struct watch *watch;
 
        /* During transactions, don't fire watches. */
-       if (trans)
-               return;
-
-       watches = find_watches(node, recurse, &num_watches);
-       if (!watches)
-               return;
-
-       /* Create and fill in info about event. */
-       event = talloc(talloc_autofree_context(), struct watch_event);
-       event->node = talloc_strdup(event, node);
-
-       /* Tie event to this watch. */
-       event->watches = watches;
-       talloc_steal(event, watches);
-       event->num_watches = num_watches;
-       event->recurse = recurse;
-       list_add_tail(&event->list, &watches[0]->events);
-
-       /* Warn if not finished after thirty seconds. */
-       gettimeofday(&event->timeout, NULL);
-       event->timeout.tv_sec += 30;
-
-       /* If connection not doing anything, queue this. */
-       if (!watches[0]->conn->out)
-               queue_next_event(watches[0]->conn);
-}
-
-/* We're done with this event: see if anyone else wants it. */
-static void move_event_onwards(struct watch_event *event)
-{
-       list_del(&event->list);
-
-       event->num_watches--;
-       event->watches++;
-       if (!event->num_watches) {
-               talloc_free(event);
-               return;
-       }
-
-       list_add_tail(&event->list, &event->watches[0]->events);
-
-       /* If connection not doing anything, queue this. */
-       if (!event->watches[0]->conn->out)
-               queue_next_event(event->watches[0]->conn);
-}
-
-static void remove_watch_from_events(struct watch *dying_watch)
-{
-       struct watch *watch;
-       struct watch_event *event;
-       unsigned int i;
-
-       list_for_each_entry(watch, &watches, list) {
-               list_for_each_entry(event, &watch->events, list) {
-                       for (i = 0; i < event->num_watches; i++) {
-                               if (event->watches[i] != dying_watch)
-                                       continue;
-
-                               assert(i != 0);
-                               memmove(event->watches+i,
-                                       event->watches+i+1,
-                                       (event->num_watches - (i+1))
-                                       * sizeof(struct watch *));
-                               event->num_watches--;
-                       }
+       if (conn->transaction)
+               return;
+
+       /* Create an event for each watch.  Don't send to self. */
+       list_for_each_entry(i, &connections, list) {
+               if (i == conn)
+                       continue;
+
+               list_for_each_entry(watch, &i->watches, list) {
+                       if (is_child(node, watch->node))
+                               add_event(watch, node);
+                       else if (recurse && is_child(watch->node, node))
+                               add_event(watch, watch->node);
+                       else
+                               continue;
+                       /* If connection not doing anything, queue this. */
+                       if (!i->out)
+                               queue_next_event(i);
                }
        }
 }
 
 static int destroy_watch(void *_watch)
 {
-       struct watch *watch = _watch;
-       struct watch_event *event;
-
-       /* If we have pending events, pass them on to others. */
-       while ((event = list_top(&watch->events, struct watch_event, list)))
-               move_event_onwards(event);
-
-       /* Remove from global list. */
-       list_del(&watch->list);
-
-       /* Other events which match this watch must be cleared. */
-       remove_watch_from_events(watch);
-
-       trace_destroy(watch, "watch");
+       trace_destroy(_watch, "watch");
        return 0;
 }
 
-/* We keep watches in priority order. */
-static void insert_watch(struct watch *watch)
-{
-       struct watch *i;
-
-       list_for_each_entry(i, &watches, list) {
-               if (i->priority <= watch->priority) {
-                       list_add_tail(&watch->list, &i->list);
-                       return;
-               }
-       }
-
-       list_add_tail(&watch->list, &watches);
-}
-
 void shortest_watch_ack_timeout(struct timeval *tv)
 {
+       (void)tv;
+#if 0 /* FIXME */
        struct watch *watch;
 
        list_for_each_entry(watch, &watches, list) {
@@ -285,10 +165,12 @@
                                *tv = i->timeout;
                }
        }
+#endif
 }      
 
 void check_watch_ack_timeout(void)
 {
+#if 0
        struct watch *watch;
        struct timeval now;
 
@@ -307,82 +189,97 @@
                        }
                }
        }
-}
-
-bool do_watch(struct connection *conn, struct buffered_data *in)
-{
-       struct watch *watch;
-       char *vec[3];
+#endif
+}
+
+void do_watch(struct connection *conn, struct buffered_data *in)
+{
+       struct watch *watch;
+       char *vec[2];
        bool relative;
 
-       if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
-               return send_error(conn, EINVAL);
+       if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
+               send_error(conn, EINVAL);
+               return;
+       }
 
        relative = !strstarts(vec[0], "/");
        vec[0] = canonicalize(conn, vec[0]);
-       if (!check_node_perms(conn, vec[0], XS_PERM_READ))
-               return send_error(conn, errno);
+       if (!check_node_perms(conn, vec[0], XS_PERM_READ)) {
+               send_error(conn, errno);
+               return;
+       }
 
        watch = talloc(conn, struct watch);
        watch->node = talloc_strdup(watch, vec[0]);
        watch->token = talloc_strdup(watch, vec[1]);
-       watch->conn = conn;
-       watch->priority = strtoul(vec[2], NULL, 0);
-       watch->relative = relative;
+       if (relative)
+               watch->relative_path = get_implicit_path(conn);
+       else
+               watch->relative_path = NULL;
+
        INIT_LIST_HEAD(&watch->events);
 
-       insert_watch(watch);
+       list_add_tail(&watch->list, &conn->watches);
+       trace_create(watch, "watch");
        talloc_set_destructor(watch, destroy_watch);
-       trace_create(watch, "watch");
-       return send_ack(conn, XS_WATCH);
-}
-
-bool do_watch_ack(struct connection *conn, const char *token)
+       send_ack(conn, XS_WATCH);
+}
+
+void do_watch_ack(struct connection *conn, const char *token)
 {
        struct watch_event *event;
 
-       if (!token)
-               return send_error(conn, EINVAL);
-
-       if (!conn->waiting_for_ack)
-               return send_error(conn, ENOENT);
-
-       event = list_top(&conn->waiting_for_ack->events,
-                        struct watch_event, list);
-       assert(event->watches[0] == conn->waiting_for_ack);
+       if (!token) {
+               send_error(conn, EINVAL);
+               return;
+       }
+
+       if (!conn->waiting_for_ack) {
+               send_error(conn, ENOENT);
+               return;
+       }
+
        if (!streq(conn->waiting_for_ack->token, token)) {
                /* They're confused: this will cause us to send event again */
                conn->waiting_for_ack = NULL;
-               return send_error(conn, EINVAL);
-       }
-
-       move_event_onwards(event);
+               send_error(conn, EINVAL);
+               return;
+       }
+
+       /* Remove event: after ack sent, core will call queue_next_event */
+       event = list_top(&conn->waiting_for_ack->events, struct watch_event,
+                        list);
+       list_del(&event->list);
+       talloc_free(event);
+
        conn->waiting_for_ack = NULL;
-       return send_ack(conn, XS_WATCH_ACK);
-}
-
-bool do_unwatch(struct connection *conn, struct buffered_data *in)
+       send_ack(conn, XS_WATCH_ACK);
+}
+
+void do_unwatch(struct connection *conn, struct buffered_data *in)
 {
        struct watch *watch;
        char *node, *vec[2];
 
-       if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec))
-               return send_error(conn, EINVAL);
+       if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
+               send_error(conn, EINVAL);
+               return;
+       }
 
        /* We don't need to worry if we're waiting for an ack for the
         * watch we're deleting: conn->waiting_for_ack was reset by
         * this command in consider_message anyway. */
        node = canonicalize(conn, vec[0]);
-       list_for_each_entry(watch, &watches, list) {
-               if (watch->conn != conn)
-                       continue;
-
+       list_for_each_entry(watch, &conn->watches, list) {
                if (streq(watch->node, node) && streq(watch->token, vec[1])) {
+                       list_del(&watch->list);
                        talloc_free(watch);
-                       return send_ack(conn, XS_UNWATCH);
-               }
-       }
-       return send_error(conn, ENOENT);
+                       send_ack(conn, XS_UNWATCH);
+                       return;
+               }
+       }
+       send_error(conn, ENOENT);
 }
 
 #ifdef TESTING
@@ -391,15 +288,16 @@
        struct watch *watch;
        struct watch_event *event;
 
-       /* Find first watch with an event. */
-       list_for_each_entry(watch, &watches, list) {
-               if (watch->conn != conn)
-                       continue;
-
-               printf("    watch on %s token %s prio %i\n",
-                      watch->node, watch->token, watch->priority);
+       if (conn->waiting_for_ack)
+               printf("    waiting_for_ack for watch on %s token %s\n",
+                      conn->waiting_for_ack->node,
+                      conn->waiting_for_ack->token);
+
+       list_for_each_entry(watch, &conn->watches, list) {
+               printf("    watch on %s token %s\n",
+                      watch->node, watch->token);
                list_for_each_entry(event, &watch->events, list)
-                       printf("        event: %s\n", event->node);
+                       printf("        event: %s\n", event->data);
        }
 }
 #endif
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xenstored_watch.h
--- a/tools/xenstore/xenstored_watch.h  Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/xenstored_watch.h  Thu Aug  4 11:39:03 2005
@@ -22,9 +22,9 @@
 
 #include "xenstored_core.h"
 
-bool do_watch(struct connection *conn, struct buffered_data *in);
-bool do_watch_ack(struct connection *conn, const char *token);
-bool do_unwatch(struct connection *conn, struct buffered_data *in);
+void do_watch(struct connection *conn, struct buffered_data *in);
+void do_watch_ack(struct connection *conn, const char *token);
+void do_unwatch(struct connection *conn, struct buffered_data *in);
 
 /* Is this a watch event message for this connection? */
 bool is_watch_event(struct connection *conn, struct buffered_data *out);
@@ -32,8 +32,9 @@
 /* Look through our watches: if any of them have an event, queue it. */
 void queue_next_event(struct connection *conn);
 
-/* Fire all watches: recurse means all the children are effected (ie. rm) */
-void fire_watches(struct transaction *trans, const char *node, bool recurse);
+/* Fire all watches: recurse means all the children are effected (ie. rm).
+ */
+void fire_watches(struct connection *conn, const char *node, bool recurse);
 
 /* Find shortest timeout: if any, reduce tv (may already be set). */
 void shortest_watch_ack_timeout(struct timeval *tv);
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xs.c
--- a/tools/xenstore/xs.c       Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/xs.c       Thu Aug  4 11:39:03 2005
@@ -401,22 +401,16 @@
 /* Watch a node for changes (poll on fd to detect, or call read_watch()).
  * When the node (or any child) changes, fd will become readable.
  * Token is returned when watch is read, to allow matching.
- * Priority indicates order if multiple watchers: higher is first.
  * Returns false on failure.
  */
-bool xs_watch(struct xs_handle *h, const char *path, const char *token,
-             unsigned int priority)
-{
-       char prio[MAX_STRLEN(priority)];
-       struct iovec iov[3];
-
-       sprintf(prio, "%u", priority);
+bool xs_watch(struct xs_handle *h, const char *path, const char *token)
+{
+       struct iovec iov[2];
+
        iov[0].iov_base = (void *)path;
        iov[0].iov_len = strlen(path) + 1;
        iov[1].iov_base = (void *)token;
        iov[1].iov_len = strlen(token) + 1;
-       iov[2].iov_base = prio;
-       iov[2].iov_len = strlen(prio) + 1;
 
        return xs_bool(xs_talkv(h, XS_WATCH, iov, ARRAY_SIZE(iov), NULL));
 }
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xs.h
--- a/tools/xenstore/xs.h       Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/xs.h       Thu Aug  4 11:39:03 2005
@@ -82,11 +82,9 @@
 /* Watch a node for changes (poll on fd to detect, or call read_watch()).
  * When the node (or any child) changes, fd will become readable.
  * Token is returned when watch is read, to allow matching.
- * Priority indicates order if multiple watchers: higher is first.
  * Returns false on failure.
  */
-bool xs_watch(struct xs_handle *h, const char *path, const char *token,
-             unsigned int priority);
+bool xs_watch(struct xs_handle *h, const char *path, const char *token);
 
 /* Return the FD to poll on to see if a watch has fired. */
 int xs_fileno(struct xs_handle *h);
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xs_test.c
--- a/tools/xenstore/xs_test.c  Thu Aug  4 10:43:03 2005
+++ b/tools/xenstore/xs_test.c  Thu Aug  4 11:39:03 2005
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <signal.h>
@@ -33,6 +34,9 @@
 #define XSTEST
 
 static struct xs_handle *handles[10] = { NULL };
+
+static bool timeout = true;
+static bool readonly = false;
 
 struct ringbuf_head
 {
@@ -184,7 +188,7 @@
             "  getperm <path>\n"
             "  setperm <path> <id> <flags> ...\n"
             "  shutdown\n"
-            "  watch <path> <token> <prio>\n"
+            "  watch <path> <token>\n"
             "  waitwatch\n"
             "  ackwatch <token>\n"
             "  unwatch <path> <token>\n"
@@ -197,22 +201,34 @@
             "  dump\n");
 }
 
+static int argpos(const char *line, unsigned int num)
+{
+       unsigned int i, len = 0, off = 0;
+
+       for (i = 0; i <= num; i++) {
+               off += len;
+               off += strspn(line + off, " \t\n");
+               len = strcspn(line + off, " \t\n");
+               if (!len)
+                       return off;
+       }
+       return off;
+}
+
 static char *arg(char *line, unsigned int num)
 {
        static char *args[10];
-       unsigned int i, len = 0;
-
-       for (i = 0; i <= num; i++) {
-               line += len;
-               line += strspn(line, " \t\n");
-               len = strcspn(line, " \t\n");
-               if (!len)
-                       barf("Can't get arg %u", num);
-       }
+       unsigned int off, len;
+
+       off = argpos(line, num);
+       len = strcspn(line + off, " \t\n");
+
+       if (!len)
+               barf("Can't get arg %u", num);
 
        free(args[num]);
        args[num] = malloc(len + 1);
-       memcpy(args[num], line, len);
+       memcpy(args[num], line+off, len);
        args[num][len] = '\0';
        return args[num];
 }
@@ -371,10 +387,9 @@
                failed(handle);
 }
 
-static void do_watch(unsigned int handle, const char *node, const char *token,
-                    const char *pri)
-{
-       if (!xs_watch(handles[handle], node, token, atoi(pri)))
+static void do_watch(unsigned int handle, const char *node, const char *token)
+{
+       if (!xs_watch(handles[handle], node, token))
                failed(handle);
 }
 
@@ -544,23 +559,102 @@
        free(subdirs);
 }
 
+static int handle;
+
+static void alarmed(int sig __attribute__((unused)))
+{
+       if (handle) {
+               char handlename[10];
+               sprintf(handlename, "%u:", handle);
+               write(STDOUT_FILENO, handlename, strlen(handlename));
+       }
+       write(STDOUT_FILENO, command, strlen(command));
+       write(STDOUT_FILENO, " timeout\n", strlen(" timeout\n"));
+       exit(1);
+}
+
+static void do_command(unsigned int default_handle, char *line)
+{
+       char *endp;
+
+       if (strspn(line, " \n") == strlen(line))
+               return;
+       if (strstarts(line, "#"))
+               return;
+
+       handle = strtoul(line, &endp, 10);
+       if (endp != line)
+               memmove(line, endp+1, strlen(endp));
+       else
+               handle = default_handle;
+
+       if (!handles[handle]) {
+               if (readonly)
+                       handles[handle] = xs_daemon_open_readonly();
+               else
+                       handles[handle] = xs_daemon_open();
+               if (!handles[handle])
+                       barf_perror("Opening connection to daemon");
+       }
+       command = arg(line, 0);
+
+       if (timeout)
+               alarm(1);
+
+       if (streq(command, "dir"))
+               do_dir(handle, arg(line, 1));
+       else if (streq(command, "read"))
+               do_read(handle, arg(line, 1));
+       else if (streq(command, "write"))
+               do_write(handle,
+                        arg(line, 1), arg(line, 2), arg(line, 3));
+       else if (streq(command, "setid"))
+               do_setid(handle, arg(line, 1));
+       else if (streq(command, "mkdir"))
+               do_mkdir(handle, arg(line, 1));
+       else if (streq(command, "rm"))
+               do_rm(handle, arg(line, 1));
+       else if (streq(command, "getperm"))
+               do_getperm(handle, arg(line, 1));
+       else if (streq(command, "setperm"))
+               do_setperm(handle, arg(line, 1), line);
+       else if (streq(command, "shutdown"))
+               do_shutdown(handle);
+       else if (streq(command, "watch"))
+               do_watch(handle, arg(line, 1), arg(line, 2));
+       else if (streq(command, "waitwatch"))
+               do_waitwatch(handle);
+       else if (streq(command, "ackwatch"))
+               do_ackwatch(handle, arg(line, 1));
+       else if (streq(command, "unwatch"))
+               do_unwatch(handle, arg(line, 1), arg(line, 2));
+       else if (streq(command, "close")) {
+               xs_daemon_close(handles[handle]);
+               handles[handle] = NULL;
+       } else if (streq(command, "start"))
+               do_start(handle, arg(line, 1));
+       else if (streq(command, "commit"))
+               do_end(handle, false);
+       else if (streq(command, "abort"))
+               do_end(handle, true);
+       else if (streq(command, "introduce"))
+               do_introduce(handle, arg(line, 1), arg(line, 2),
+                            arg(line, 3), arg(line, 4));
+       else if (streq(command, "release"))
+               do_release(handle, arg(line, 1));
+       else if (streq(command, "dump"))
+               dump(handle);
+       else if (streq(command, "sleep"))
+               sleep(atoi(arg(line, 1)));
+       else
+               barf("Unknown command %s", command);
+       fflush(stdout);
+       alarm(0);
+}
+
 int main(int argc, char *argv[])
 {
        char line[1024];
-       bool readonly = false, timeout = true;
-       int handle;
-
-       static void alarmed(int sig __attribute__((unused)))
-       {
-               if (handle) {
-                       char handlename[10];
-                       sprintf(handlename, "%u:", handle);
-                       write(STDOUT_FILENO, handlename, strlen(handlename));
-               }
-               write(STDOUT_FILENO, command, strlen(command));
-               write(STDOUT_FILENO, " timeout\n", strlen(" timeout\n"));
-               exit(1);
-       }
 
        if (argc > 1 && streq(argv[1], "--readonly")) {
                readonly = true;
@@ -568,7 +662,7 @@
                argv++;
        }
 
-       if (argc > 1 && streq(argv[1], "--notimeout")) {
+       if (argc > 1 && streq(argv[1], "--no-timeout")) {
                timeout = false;
                argc--;
                argv++;
@@ -581,81 +675,8 @@
        ringbuf_datasize = getpagesize() / 2 - sizeof(struct ringbuf_head);
 
        signal(SIGALRM, alarmed);
-       while (fgets(line, sizeof(line), stdin)) {
-               char *endp;
-
-               if (strspn(line, " \n") == strlen(line))
-                       continue;
-               if (strstarts(line, "#"))
-                       continue;
-
-               handle = strtoul(line, &endp, 10);
-               if (endp != line)
-                       memmove(line, endp+1, strlen(endp));
-               else
-                       handle = 0;
-
-               if (!handles[handle]) {
-                       if (readonly)
-                               handles[handle] = xs_daemon_open_readonly();
-                       else
-                               handles[handle] = xs_daemon_open();
-                       if (!handles[handle])
-                               barf_perror("Opening connection to daemon");
-               }
-               command = arg(line, 0);
-
-               if (timeout)
-                       alarm(5);
-               if (streq(command, "dir"))
-                       do_dir(handle, arg(line, 1));
-               else if (streq(command, "read"))
-                       do_read(handle, arg(line, 1));
-               else if (streq(command, "write"))
-                       do_write(handle,
-                                arg(line, 1), arg(line, 2), arg(line, 3));
-               else if (streq(command, "setid"))
-                       do_setid(handle, arg(line, 1));
-               else if (streq(command, "mkdir"))
-                       do_mkdir(handle, arg(line, 1));
-               else if (streq(command, "rm"))
-                       do_rm(handle, arg(line, 1));
-               else if (streq(command, "getperm"))
-                       do_getperm(handle, arg(line, 1));
-               else if (streq(command, "setperm"))
-                       do_setperm(handle, arg(line, 1), line);
-               else if (streq(command, "shutdown"))
-                       do_shutdown(handle);
-               else if (streq(command, "watch"))
-                       do_watch(handle, arg(line, 1), arg(line, 2), arg(line, 
3));
-               else if (streq(command, "waitwatch"))
-                       do_waitwatch(handle);
-               else if (streq(command, "ackwatch"))
-                       do_ackwatch(handle, arg(line, 1));
-               else if (streq(command, "unwatch"))
-                       do_unwatch(handle, arg(line, 1), arg(line, 2));
-               else if (streq(command, "close")) {
-                       xs_daemon_close(handles[handle]);
-                       handles[handle] = NULL;
-               } else if (streq(command, "start"))
-                       do_start(handle, arg(line, 1));
-               else if (streq(command, "commit"))
-                       do_end(handle, false);
-               else if (streq(command, "abort"))
-                       do_end(handle, true);
-               else if (streq(command, "introduce"))
-                       do_introduce(handle, arg(line, 1), arg(line, 2),
-                                    arg(line, 3), arg(line, 4));
-               else if (streq(command, "release"))
-                       do_release(handle, arg(line, 1));
-               else if (streq(command, "dump"))
-                       dump(handle);
-               else if (streq(command, "sleep"))
-                       sleep(atoi(arg(line, 1)));
-               else
-                       barf("Unknown command %s", command);
-               fflush(stdout);
-               alarm(0);
-       }
+       while (fgets(line, sizeof(line), stdin))
+               do_command(0, line);
+
        return 0;
 }
diff -r ba5d5bd28edf -r b0de1894df67 tools/xenstore/xs_watch_stress.c
--- a/tools/xenstore/xs_watch_stress.c  Thu Aug  4 10:43:03 2005
+++ /dev/null   Thu Aug  4 11:39:03 2005
@@ -1,120 +0,0 @@
-/* Stress test for watch code: two processes communicating by watches */
-#include "xs.h"
-#include "utils.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-int main(int argc __attribute__((unused)), char *argv[])
-{
-       int childpid, status, fds[2];
-       bool parent;
-       unsigned int i, acks = 0;
-       struct xs_handle *h;
-       char *data;
-       unsigned int len;
-       const char *path, *otherpath;
-
-       pipe(fds);
-       childpid = fork();
-       if (childpid == -1)
-               barf_perror("Failed fork");
-       parent = (childpid != 0);
-
-       h = xs_daemon_open();
-       if (!h)
-               barf_perror("Could not connect to daemon");
-
-       if (!xs_watch(h, "/", "token", 0))
-               barf_perror("Could not set watch");
-
-       if (parent) {
-               char c;
-
-               if (read(fds[0], &c, 1) != 1)
-                       barf("Child exited");
-
-               path = "/parent";
-               otherpath = "/child";
-               /* Create initial node. */
-               if (!xs_write(h, path, "0", 2, O_CREAT))
-                       barf_perror("Write to %s failed", path);
-       } else {
-               path = "/child";
-               otherpath = "/parent";
-
-               if (write(fds[1], "", 1) != 1)
-                       barf_perror("Write to parent failed");
-       }
-
-       for (i = 0; i < (argv[1] ? (unsigned)atoi(argv[1]) : 100);) {
-               char **vec;
-
-               vec = xs_read_watch(h);
-               if (!vec)
-                       barf_perror("Read watch failed");
-
-               if (!streq(vec[1], "token"))
-                       barf("Watch token %s bad", vec[1]);
-               if (streq(vec[0], otherpath)) {
-                       char number[32];
-
-                       data = xs_read(h, otherpath, &len);
-                       if (!data)
-                               barf_perror("reading %s", otherpath);
-                       sprintf(number, "%i", atoi(data) + 1);
-                       free(data);
-                       if (!xs_write(h, path, number, strlen(number) + 1,
-                                     O_CREAT))
-                               barf_perror("writing %s", path);
-                       i++;
-               } else if (!streq(vec[0], path))
-                       barf_perror("Watch fired on unknown path %s", vec[0]);
-               xs_acknowledge_watch(h, vec[1]);
-               acks++;
-               free(vec);
-       }
-
-       if (!parent) {
-               while (acks != 2 * i - 1) {
-                       char **vec;
-                       vec = xs_read_watch(h);
-                       if (!vec)
-                               barf_perror("Watch failed");
-                       if (!streq(vec[0], path))
-                               barf_perror("Watch fired path %s", vec[0]);
-                       if (!streq(vec[1], "token"))
-                               barf("Watch token %s bad", vec[1]);
-                       free(vec);
-
-                       printf("Expect %i events, only got %i\n",
-                              2 * i - 1, acks);
-                       acks++;
-               }
-               exit(0);
-       }
-
-       if (acks != 2 * i)
-               barf("Parent got %i watch events\n", acks);
-
-       printf("Waiting for %i\n", childpid);
-       if (waitpid(childpid, &status, 0) != childpid)
-               barf_perror("Child wait failed");
-       if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
-               barf_perror("Child status %i", status);
-
-       data = xs_read(h, path, &len);
-       if (atoi(data) != 2 * (int)i)
-               barf("%s count is %s\n", path, data);
-       free(data);
-       data = xs_read(h, otherpath, &len);
-       if (atoi(data) != 2 * (int)i - 1)
-               barf("%s count is %s\n", otherpath, data);
-       free(data);
-       printf("Success!\n");
-       exit(0);
-}


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [PATCH 6/11] Xenstore watch rework, Rusty Russell <=