python: Add non-blocking Xenstore watch bindings
v2 cover python: Add non-blocking Xenstore watch bindings
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(-)
Signature · 7 lines
1.8.3.1 _______________________________________________ Xen-devel mailing list [email protected] https://lists.xen.org/xen-devel
PATCH v2 1/3 python: Add binding for xs_fileno()
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.
--- tools/python/xen/lowlevel/xs/xs.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
tools/python/xen/lowlevel/xs/xs.c +20 -0
@@ -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 PyInt_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. */ }, };
Signature · 7 lines
1.8.3.1 _______________________________________________ Xen-devel mailing list [email protected] https://lists.xen.org/xen-devel
Re: [PATCH v2 1/3] python: Add binding for xs_fileno()
Quoted 25 lines · Euan Harris
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 <[email protected]>Reviewed-by Konrad Rzeszutek Wilk <[email protected]>Reviewed-by Wei Liu <[email protected]>--- tools/python/xen/lowlevel/xs/xs.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)tools/python/xen/lowlevel/xs/xs.c +6
-0@@ -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)
tools/python/xen/lowlevel/xs/xs.c static PyObject *xspy_watch(XsHandle *self, PyObject *args) · line 471
Quoted 10 lines
tools/python/xen/lowlevel/xs/xs.c +10
-0+{ +struct xs_handle *xh =xshandle (self); +int fd; + +if (!xh) +return NULL ; + + fd =xs_fileno (xh); + +return PyInt_FromLong (fd);
Use PyLong_FromLong. There is no PyInt_* in py3k. But for convenience we have #define PyLong_FromLong -> PyInt_FromLong for python 2.
Quoted 14 lines
tools/python/xen/lowlevel/xs/xs.c +4
-0+} + +#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. */ }, };
Signature · 5 lines
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?
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
PATCH v2 2/3 python: Extract registered watch search logic from xspy_read_watch()
In reply to Euan HarrisWhen 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.
---
Changed since v1:
* Remove stray newline
* Fix indentation
tools/python/xen/lowlevel/xs/xs.c | 60 ++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 23 deletions(-)
tools/python/xen/lowlevel/xs/xs.c +37 -23
@@ -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) {
Signature · 7 lines
1.8.3.1 _______________________________________________ Xen-devel mailing list [email protected] https://lists.xen.org/xen-devel
Re: [PATCH v2 2/3] python: Extract registered watch search logic from xspy_read_watch()
Quoted 8 lines · Euan Harris
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 forxs_check_watch()
needs to do the same, so this patch extracts the search code into a separate function.Signed-off-by Euan Harris <[email protected]>Reviewed-by Wei Liu <[email protected]>
Quoted 102 lines
---
Changed since v1:
* Remove stray newline
* Fix indentationtools/python/xen/lowlevel/xs/xs.c | 60 ++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 23 deletions(-)tools/python/xen/lowlevel/xs/xs.c +37
-23@@ -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) {
Signature · 5 lines
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?
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel
PATCH v2 3/3 python: Add binding for non-blocking xs_check_watch()
In reply to Euan Harrisxs_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.
--- tools/python/xen/lowlevel/xs/xs.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
tools/python/xen/lowlevel/xs/xs.c +28 -0
@@ -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),
Signature · 7 lines
1.8.3.1 _______________________________________________ Xen-devel mailing list [email protected] https://lists.xen.org/xen-devel
Re: [PATCH v2 3/3] python: Add binding for non-blocking xs_check_watch()
Quoted 6 lines · Euan Harris
xs_check_watch()checks for watch notifications without blocking. Together with the binding forxs_fileno(), this makes it possible to write event-driven clients in Python.Signed-off-by Euan Harris <[email protected]>Reviewed-by Wei Liu <[email protected]>
Quoted 50 lines
--- tools/python/xen/lowlevel/xs/xs.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)tools/python/xen/lowlevel/xs/xs.c +28
-0@@ -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),
Signature · 5 lines
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?
_______________________________________________
Xen-devel mailing list
[email protected]
https://lists.xen.org/xen-devel