* [PATCH v2 0/3] python: Add non-blocking Xenstore watch bindings
@ 2017-09-21 16:47 Euan Harris
2017-09-21 16:47 ` [PATCH v2 1/3] python: Add binding for xs_fileno() Euan Harris
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Euan Harris @ 2017-09-21 16:47 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] 7+ messages in thread* [PATCH v2 1/3] python: Add binding for xs_fileno() 2017-09-21 16:47 [PATCH v2 0/3] python: Add non-blocking Xenstore watch bindings Euan Harris @ 2017-09-21 16:47 ` Euan Harris 2017-09-21 18:04 ` Marek Marczykowski-Górecki 2017-09-21 16:47 ` [PATCH v2 2/3] python: Extract registered watch search logic from xspy_read_watch() Euan Harris 2017-09-21 16:47 ` [PATCH v2 3/3] python: Add binding for non-blocking xs_check_watch() Euan Harris 2 siblings, 1 reply; 7+ messages in thread From: Euan Harris @ 2017-09-21 16:47 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> --- 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..9f1b916 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 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. */ }, }; -- 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] 7+ messages in thread
* Re: [PATCH v2 1/3] python: Add binding for xs_fileno() 2017-09-21 16:47 ` [PATCH v2 1/3] python: Add binding for xs_fileno() Euan Harris @ 2017-09-21 18:04 ` Marek Marczykowski-Górecki 0 siblings, 0 replies; 7+ messages in thread From: Marek Marczykowski-Górecki @ 2017-09-21 18:04 UTC (permalink / raw) To: Euan Harris; +Cc: xen-devel [-- Attachment #1.1: Type: text/plain, Size: 2051 bytes --] On Thu, Sep 21, 2017 at 05:47:06PM +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> > --- > 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..9f1b916 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 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. > +} > + > + > #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] 7+ messages in thread
* [PATCH v2 2/3] python: Extract registered watch search logic from xspy_read_watch() 2017-09-21 16:47 [PATCH v2 0/3] python: Add non-blocking Xenstore watch bindings Euan Harris 2017-09-21 16:47 ` [PATCH v2 1/3] python: Add binding for xs_fileno() Euan Harris @ 2017-09-21 16:47 ` Euan Harris 2017-09-21 18:07 ` Marek Marczykowski-Górecki 2017-09-21 16:47 ` [PATCH v2 3/3] python: Add binding for non-blocking xs_check_watch() Euan Harris 2 siblings, 1 reply; 7+ messages in thread From: Euan Harris @ 2017-09-21 16:47 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> --- 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 9f1b916..2af5e07 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] 7+ messages in thread
* Re: [PATCH v2 2/3] python: Extract registered watch search logic from xspy_read_watch() 2017-09-21 16:47 ` [PATCH v2 2/3] python: Extract registered watch search logic from xspy_read_watch() Euan Harris @ 2017-09-21 18:07 ` Marek Marczykowski-Górecki 0 siblings, 0 replies; 7+ messages in thread From: Marek Marczykowski-Górecki @ 2017-09-21 18:07 UTC (permalink / raw) To: Euan Harris; +Cc: xen-devel [-- Attachment #1.1: Type: text/plain, Size: 4013 bytes --] On Thu, Sep 21, 2017 at 05:47:07PM +0100, Euan Harris wrote: > 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 9f1b916..2af5e07 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) { -- 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] 7+ messages in thread
* [PATCH v2 3/3] python: Add binding for non-blocking xs_check_watch() 2017-09-21 16:47 [PATCH v2 0/3] python: Add non-blocking Xenstore watch bindings Euan Harris 2017-09-21 16:47 ` [PATCH v2 1/3] python: Add binding for xs_fileno() Euan Harris 2017-09-21 16:47 ` [PATCH v2 2/3] python: Extract registered watch search logic from xspy_read_watch() Euan Harris @ 2017-09-21 16:47 ` Euan Harris 2017-09-21 18:09 ` Marek Marczykowski-Górecki 2 siblings, 1 reply; 7+ messages in thread From: Euan Harris @ 2017-09-21 16:47 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> --- 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 2af5e07..4710002 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] 7+ messages in thread
* Re: [PATCH v2 3/3] python: Add binding for non-blocking xs_check_watch() 2017-09-21 16:47 ` [PATCH v2 3/3] python: Add binding for non-blocking xs_check_watch() Euan Harris @ 2017-09-21 18:09 ` Marek Marczykowski-Górecki 0 siblings, 0 replies; 7+ messages in thread From: Marek Marczykowski-Górecki @ 2017-09-21 18:09 UTC (permalink / raw) To: Euan Harris; +Cc: xen-devel [-- Attachment #1.1: Type: text/plain, Size: 2308 bytes --] On Thu, Sep 21, 2017 at 05:47:08PM +0100, Euan Harris wrote: > 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 2af5e07..4710002 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), -- 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] 7+ messages in thread
end of thread, other threads:[~2017-09-21 18:09 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-09-21 16:47 [PATCH v2 0/3] python: Add non-blocking Xenstore watch bindings Euan Harris 2017-09-21 16:47 ` [PATCH v2 1/3] python: Add binding for xs_fileno() Euan Harris 2017-09-21 18:04 ` Marek Marczykowski-Górecki 2017-09-21 16:47 ` [PATCH v2 2/3] python: Extract registered watch search logic from xspy_read_watch() Euan Harris 2017-09-21 18:07 ` Marek Marczykowski-Górecki 2017-09-21 16:47 ` [PATCH v2 3/3] python: Add binding for non-blocking xs_check_watch() Euan Harris 2017-09-21 18:09 ` Marek Marczykowski-Górecki
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.