All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/3] python: Add non-blocking Xenstore watch bindings
@ 2017-09-22 16:21 Euan Harris
  2017-09-22 16:21 ` [PATCH v3 1/3] python: Add binding for xs_fileno() Euan Harris
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Euan Harris @ 2017-09-22 16:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Euan Harris, marmarek

Expose xs_fileno() and xs_check_watch() to Python.   These functions
make it posible to write event-driven Xenstore clients in Python:

  #!/usr/bin/env python
  
  import xen.lowlevel.xs
  
  import sys
  import errno
  from select import select
  import time
  
  # Connect to XenStore and set watch
  xsh = xen.lowlevel.xs.xs()
  xsh.watch("/foo", "footoken")
  xsh.watch("/bar", "bartoken")
  
  # Start polling loop
  xsfd = xsh.fileno()
  while True:
     readable, writable, exceptional = select([xsfd], [], [xsfd], 1.0)
     print "%d tick" % time.time()
  
     if readable:
         while True:
             watch = xsh.check_watch()
             if not watch:
                 break
             path, token = watch
             print "%d watch fired: path=%s, token=%s" % (time.time(), 
                                                          path, token)
             value = xsh.read("", path)
             print "%d read %s = %s" % (time.time(), path, value)
  
     if exceptional:
         print "select error"
  
The polling loop can be simplified further by wrapping the call to
xsh.check_watch() in a generator, but this is easier to do in Python
than in the C bindings.


Euan Harris (3):
  python: Add binding for xs_fileno()
  python: Extract registered watch search logic from  xspy_read_watch()
  python: Add binding for non-blocking xs_check_watch()

 tools/python/xen/lowlevel/xs/xs.c | 108 ++++++++++++++++++++++++++++++--------
 1 file changed, 85 insertions(+), 23 deletions(-)

-- 
1.8.3.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v3 1/3] python: Add binding for xs_fileno()
  2017-09-22 16:21 [PATCH v3 0/3] python: Add non-blocking Xenstore watch bindings Euan Harris
@ 2017-09-22 16:21 ` Euan Harris
  2017-09-22 17:50   ` Marek Marczykowski-Górecki
  2017-09-22 16:21 ` [PATCH v3 2/3] python: Extract registered watch search logic from xspy_read_watch() Euan Harris
  2017-09-22 16:21 ` [PATCH v3 3/3] python: Add binding for non-blocking xs_check_watch() Euan Harris
  2 siblings, 1 reply; 6+ messages in thread
From: Euan Harris @ 2017-09-22 16:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Euan Harris, marmarek

xs_fileno() returns a file descriptor which receives events when Xenstore
watches fire.   Exposing this in the Python bindings is a prerequisite
for writing event-driven clients in Python.

Signed-off-by: Euan Harris <euan.harris@citrix.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Wei Liu <wei.liu2@citrix.com>
---
Changed since v2:
 * Use PyLong_FromLong instead of PyInt_FromLong
---
 tools/python/xen/lowlevel/xs/xs.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/tools/python/xen/lowlevel/xs/xs.c b/tools/python/xen/lowlevel/xs/xs.c
index aba5a20..3a827b0 100644
--- a/tools/python/xen/lowlevel/xs/xs.c
+++ b/tools/python/xen/lowlevel/xs/xs.c
@@ -453,6 +453,25 @@ static PyObject *xspy_watch(XsHandle *self, PyObject *args)
 }
 
 
+#define xspy_fileno_doc "\n"                              \
+	"Return the FD to poll for notifications when watches fire.\n"   \
+	"Returns: [int] file descriptor.\n"                \
+	"\n"
+
+static PyObject *xspy_fileno(XsHandle *self)
+{
+    struct xs_handle *xh = xshandle(self);
+    int fd;
+
+    if (!xh)
+        return NULL;
+
+    fd = xs_fileno(xh);
+
+    return PyLong_FromLong(fd);
+}
+
+
 #define xspy_read_watch_doc "\n"				\
 	"Read a watch notification.\n"				\
 	"\n"							\
@@ -887,6 +906,7 @@ static PyMethodDef xshandle_methods[] = {
     XSPY_METH(release_domain,    METH_VARARGS),
     XSPY_METH(close,             METH_NOARGS),
     XSPY_METH(get_domain_path,   METH_VARARGS),
+    XSPY_METH(fileno,            METH_NOARGS),
     { NULL /* Sentinel. */ },
 };
 
-- 
1.8.3.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v3 2/3] python: Extract registered watch search logic from xspy_read_watch()
  2017-09-22 16:21 [PATCH v3 0/3] python: Add non-blocking Xenstore watch bindings Euan Harris
  2017-09-22 16:21 ` [PATCH v3 1/3] python: Add binding for xs_fileno() Euan Harris
@ 2017-09-22 16:21 ` Euan Harris
  2017-09-22 16:21 ` [PATCH v3 3/3] python: Add binding for non-blocking xs_check_watch() Euan Harris
  2 siblings, 0 replies; 6+ messages in thread
From: Euan Harris @ 2017-09-22 16:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Euan Harris, marmarek

When a watch fires, xspy_read_watch() checks whether the client has
registered interest in the path which changed and, if so, returns the
path and a client-supplied token.   The binding for xs_check_watch()
needs to do the same, so this patch extracts the search code into a
separate function.

Signed-off-by: Euan Harris <euan.harris@citrix.com>
Reviewed-by: Wei Liu <wei.liu2@citrix.com>
Acked-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
---
Changed since v1:
 * Remove stray newline
 * Fix indentation
---
 tools/python/xen/lowlevel/xs/xs.c | 60 ++++++++++++++++++++++++---------------
 1 file changed, 37 insertions(+), 23 deletions(-)

diff --git a/tools/python/xen/lowlevel/xs/xs.c b/tools/python/xen/lowlevel/xs/xs.c
index 3a827b0..e7c3bd0 100644
--- a/tools/python/xen/lowlevel/xs/xs.c
+++ b/tools/python/xen/lowlevel/xs/xs.c
@@ -77,6 +77,8 @@ static inline struct xs_handle *xshandle(XsHandle *self)
 
 static void remove_watch(XsHandle *xsh, PyObject *token);
 
+static PyObject *match_watch_by_token(XsHandle *self, char **xsval);
+
 static PyObject *none(bool result);
 
 static int parse_transaction_path(XsHandle *self, PyObject *args,
@@ -484,8 +486,6 @@ static PyObject *xspy_read_watch(XsHandle *self, PyObject *args)
     struct xs_handle *xh = xshandle(self);
     PyObject *val = NULL;
     char **xsval;
-    PyObject *token;
-    int i;
     unsigned int num;
 
     if (!xh)
@@ -497,29 +497,16 @@ again:
     Py_END_ALLOW_THREADS
     if (!xsval) {
         PyErr_SetFromErrno(xs_error);
-        goto exit;
-    }
-    if (sscanf(xsval[XS_WATCH_TOKEN], "%li", (unsigned long *)&token) != 1) {
-	xs_set_error(EINVAL);
-        goto exit;
-    }
-    for (i = 0; i < PyList_Size(self->watches); i++) {
-        if (token == PyList_GetItem(self->watches, i))
-            break;
-    }
-    if (i == PyList_Size(self->watches)) {
-      /* We do not have a registered watch for the one that has just fired.
-         Ignore this -- a watch that has been recently deregistered can still
-         have watches in transit.  This is a blocking method, so go back to
-         read again.
-      */
-      free(xsval);
-      goto again;
+        return val;
     }
-    /* Create tuple (path, token). */
-    val = Py_BuildValue("(sO)", xsval[XS_WATCH_PATH], token);
- exit:
+
+    val = match_watch_by_token(self, xsval);
     free(xsval);
+
+    if (!val && errno == EAGAIN) {
+        goto again;
+    }
+
     return val;
 }
 
@@ -868,6 +855,33 @@ static int parse_transaction_path(XsHandle *self, PyObject *args,
 }
 
 
+static PyObject *match_watch_by_token(XsHandle *self, char **xsval)
+{
+    PyObject *token;
+    int i;
+
+    if (sscanf(xsval[XS_WATCH_TOKEN], "%li", (unsigned long *)&token) != 1) {
+        xs_set_error(EINVAL);
+        return NULL;
+    }
+    for (i = 0; i < PyList_Size(self->watches); i++) {
+        if (token == PyList_GetItem(self->watches, i))
+            break;
+    }
+    if (i == PyList_Size(self->watches)) {
+        /* We do not have a registered watch for the one that has just fired.
+           Ignore this -- a watch that has been recently deregistered can still
+           have watches in transit.
+        */
+        xs_set_error(EAGAIN);
+        return NULL;
+    }
+
+    /* Create tuple (path, token). */
+    return Py_BuildValue("(sO)", xsval[XS_WATCH_PATH], token);
+}
+
+
 static PyObject *none(bool result)
 {
     if (result) {
-- 
1.8.3.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v3 3/3] python: Add binding for non-blocking xs_check_watch()
  2017-09-22 16:21 [PATCH v3 0/3] python: Add non-blocking Xenstore watch bindings Euan Harris
  2017-09-22 16:21 ` [PATCH v3 1/3] python: Add binding for xs_fileno() Euan Harris
  2017-09-22 16:21 ` [PATCH v3 2/3] python: Extract registered watch search logic from xspy_read_watch() Euan Harris
@ 2017-09-22 16:21 ` Euan Harris
  2 siblings, 0 replies; 6+ messages in thread
From: Euan Harris @ 2017-09-22 16:21 UTC (permalink / raw)
  To: xen-devel; +Cc: Euan Harris, marmarek

xs_check_watch() checks for watch notifications without blocking.
Together with the binding for xs_fileno(), this makes it possible
to write event-driven clients in Python.

Signed-off-by: Euan Harris <euan.harris@citrix.com>
Reviewed-by: Wei Liu <wei.liu2@citrix.com>
Acked-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
---
 tools/python/xen/lowlevel/xs/xs.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/tools/python/xen/lowlevel/xs/xs.c b/tools/python/xen/lowlevel/xs/xs.c
index e7c3bd0..9a0acfc 100644
--- a/tools/python/xen/lowlevel/xs/xs.c
+++ b/tools/python/xen/lowlevel/xs/xs.c
@@ -474,6 +474,33 @@ static PyObject *xspy_fileno(XsHandle *self)
 }
 
 
+#define xspy_check_watch_doc "\n"				\
+	"Check for watch notifications without blocking.\n"	\
+	"\n"							\
+	"Returns: [tuple] (path, token).\n"			\
+	"         None if no watches have fired.\n"             \
+	"Raises xen.lowlevel.xs.Error on error.\n"	        \
+	"\n"
+
+static PyObject *xspy_check_watch(XsHandle *self, PyObject *args)
+{
+    struct xs_handle *xh = xshandle(self);
+    PyObject *val = NULL;
+    char **xsval;
+
+    if (!xh)
+        return NULL;
+
+    xsval = xs_check_watch(xh);
+    if (!xsval) {
+        return none(errno == EAGAIN);
+    }
+
+    val = match_watch_by_token(self, xsval);
+    free(xsval);
+    return val;
+}
+
 #define xspy_read_watch_doc "\n"				\
 	"Read a watch notification.\n"				\
 	"\n"							\
@@ -911,6 +938,7 @@ static PyMethodDef xshandle_methods[] = {
     XSPY_METH(set_permissions,   METH_VARARGS),
     XSPY_METH(watch,             METH_VARARGS),
     XSPY_METH(read_watch,        METH_NOARGS),
+    XSPY_METH(check_watch,       METH_NOARGS),
     XSPY_METH(unwatch,           METH_VARARGS),
     XSPY_METH(transaction_start, METH_NOARGS),
     XSPY_METH(transaction_end,   METH_VARARGS | METH_KEYWORDS),
-- 
1.8.3.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 1/3] python: Add binding for xs_fileno()
  2017-09-22 16:21 ` [PATCH v3 1/3] python: Add binding for xs_fileno() Euan Harris
@ 2017-09-22 17:50   ` Marek Marczykowski-Górecki
  2017-09-25  8:40     ` Wei Liu
  0 siblings, 1 reply; 6+ messages in thread
From: Marek Marczykowski-Górecki @ 2017-09-22 17:50 UTC (permalink / raw)
  To: Euan Harris; +Cc: xen-devel


[-- Attachment #1.1: Type: text/plain, Size: 2069 bytes --]

On Fri, Sep 22, 2017 at 05:21:12PM +0100, Euan Harris wrote:
> xs_fileno() returns a file descriptor which receives events when Xenstore
> watches fire.   Exposing this in the Python bindings is a prerequisite
> for writing event-driven clients in Python.
> 
> Signed-off-by: Euan Harris <euan.harris@citrix.com>
> Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
> Reviewed-by: Wei Liu <wei.liu2@citrix.com>

Acked-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>

> ---
> Changed since v2:
>  * Use PyLong_FromLong instead of PyInt_FromLong
> ---
>  tools/python/xen/lowlevel/xs/xs.c | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
> 
> diff --git a/tools/python/xen/lowlevel/xs/xs.c b/tools/python/xen/lowlevel/xs/xs.c
> index aba5a20..3a827b0 100644
> --- a/tools/python/xen/lowlevel/xs/xs.c
> +++ b/tools/python/xen/lowlevel/xs/xs.c
> @@ -453,6 +453,25 @@ static PyObject *xspy_watch(XsHandle *self, PyObject *args)
>  }
>  
>  
> +#define xspy_fileno_doc "\n"                              \
> +	"Return the FD to poll for notifications when watches fire.\n"   \
> +	"Returns: [int] file descriptor.\n"                \
> +	"\n"
> +
> +static PyObject *xspy_fileno(XsHandle *self)
> +{
> +    struct xs_handle *xh = xshandle(self);
> +    int fd;
> +
> +    if (!xh)
> +        return NULL;
> +
> +    fd = xs_fileno(xh);
> +
> +    return PyLong_FromLong(fd);
> +}
> +
> +
>  #define xspy_read_watch_doc "\n"				\
>  	"Read a watch notification.\n"				\
>  	"\n"							\
> @@ -887,6 +906,7 @@ static PyMethodDef xshandle_methods[] = {
>      XSPY_METH(release_domain,    METH_VARARGS),
>      XSPY_METH(close,             METH_NOARGS),
>      XSPY_METH(get_domain_path,   METH_VARARGS),
> +    XSPY_METH(fileno,            METH_NOARGS),
>      { NULL /* Sentinel. */ },
>  };
>  

-- 
Best Regards,
Marek Marczykowski-Górecki
Invisible Things Lab
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

[-- Attachment #2: Type: text/plain, Size: 127 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3 1/3] python: Add binding for xs_fileno()
  2017-09-22 17:50   ` Marek Marczykowski-Górecki
@ 2017-09-25  8:40     ` Wei Liu
  0 siblings, 0 replies; 6+ messages in thread
From: Wei Liu @ 2017-09-25  8:40 UTC (permalink / raw)
  To: Marek Marczykowski-Górecki; +Cc: xen-devel, Euan Harris, Wei Liu

On Fri, Sep 22, 2017 at 07:50:04PM +0200, Marek Marczykowski-Górecki wrote:
> On Fri, Sep 22, 2017 at 05:21:12PM +0100, Euan Harris wrote:
> > xs_fileno() returns a file descriptor which receives events when Xenstore
> > watches fire.   Exposing this in the Python bindings is a prerequisite
> > for writing event-driven clients in Python.
> > 
> > Signed-off-by: Euan Harris <euan.harris@citrix.com>
> > Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
> > Reviewed-by: Wei Liu <wei.liu2@citrix.com>
> 
> Acked-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>

Thanks for the quick turnaround.

I've queued this series up for applying for 4.10.

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-09-25  8:40 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-22 16:21 [PATCH v3 0/3] python: Add non-blocking Xenstore watch bindings Euan Harris
2017-09-22 16:21 ` [PATCH v3 1/3] python: Add binding for xs_fileno() Euan Harris
2017-09-22 17:50   ` Marek Marczykowski-Górecki
2017-09-25  8:40     ` Wei Liu
2017-09-22 16:21 ` [PATCH v3 2/3] python: Extract registered watch search logic from xspy_read_watch() Euan Harris
2017-09-22 16:21 ` [PATCH v3 3/3] python: Add binding for non-blocking xs_check_watch() Euan Harris

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.