mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
tools/libs/store: add support to use watches with a depth parameter
Add a new xs_watch_depth() function to libxenstore allowing to limit the scope of a Xenstore watch. It can be used only in case Xenstore is supporting the XENSTORE_SERVER_FEATURE_WATCHDEPTH feature. For convenience add a xs_watch_try_depth() wrapper, which will call xs_watch_depth() if supported and xs_watch() otherwise. Cache the supported features of Xenstore in order not having to get them from Xenstore for each call of one of the new functions. While touching xs.c fix a whitespace issue there. Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Jason Andryuk <jason.andryuk@amd.com>
This commit is contained in:
1 parent
cb8972017c
commit
27d908e74e
5 files changed
+116
-12
No files matched your search
@@ -740,6 +740,12 @@ Xenstore is capable to reconnect to a guest.
|
||||
Xenstore will present an error value in case it disconnects due to an error
|
||||
condition.
|
||||
|
||||
=item B<0x00000004>
|
||||
|
||||
Xenstore supports to set watches with a limited depth (depth 0 matches
|
||||
only the watched node, depth 1 matches the node and its direct children,
|
||||
etc.).
|
||||
|
||||
=back
|
||||
|
||||
The features supported by the running Xenstore instance can be retrieved
|
||||
|
||||
@@ -177,6 +177,22 @@ bool xs_set_permissions(struct xs_handle *h, xs_transaction_t t,
|
||||
*/
|
||||
bool xs_watch(struct xs_handle *h, const char *path, const char *token);
|
||||
|
||||
/* Same as xs_watch(), but with limiting the matching for modified
|
||||
* children to a specified depth (depth 0 only matches the node itself,
|
||||
* depth 1 will additionally match direct children of the node, etc.).
|
||||
* Only supported if the XENSTORE_SERVER_FEATURE_WATCHDEPTH (4) is set
|
||||
* in the returned features of xs_get_features_supported().
|
||||
*/
|
||||
bool xs_watch_depth(struct xs_handle *h, const char *path, const char *token,
|
||||
unsigned int depth);
|
||||
|
||||
/* If supported, same as xs_watch_depth(), use xs_watch() otherwise.
|
||||
* As a result watches might trigger for nodes below the watched path, too.
|
||||
* Not to be used for special watches!
|
||||
*/
|
||||
bool xs_watch_try_depth(struct xs_handle *h, const char *path,
|
||||
const char *token, unsigned int depth);
|
||||
|
||||
/* Return the FD to poll on to see if a watch has fired. */
|
||||
int xs_fileno(struct xs_handle *h);
|
||||
|
||||
|
||||
@@ -52,4 +52,6 @@ VERS_4.2 {
|
||||
xs_set_global_quota;
|
||||
xs_get_domain_quota;
|
||||
xs_set_domain_quota;
|
||||
xs_watch_depth;
|
||||
xs_watch_try_depth;
|
||||
} VERS_4.1;
|
||||
+90
-12
@@ -984,16 +984,8 @@ bool xs_restrict(struct xs_handle *h, unsigned domid)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
* Returns false on failure.
|
||||
*/
|
||||
bool xs_watch(struct xs_handle *h, const char *path, const char *token)
|
||||
static bool xs_watch_helper(struct xs_handle *h)
|
||||
{
|
||||
struct xsd_sockmsg msg = { .type = XS_WATCH };
|
||||
struct iovec iov[3];
|
||||
|
||||
#ifdef USE_PTHREAD
|
||||
#define DEFAULT_THREAD_STACKSIZE (16 * 1024)
|
||||
/* NetBSD doesn't have PTHREAD_STACK_MIN. */
|
||||
@@ -1001,8 +993,8 @@ bool xs_watch(struct xs_handle *h, const char *path, const char *token)
|
||||
# define PTHREAD_STACK_MIN 0
|
||||
#endif
|
||||
|
||||
#define READ_THREAD_STACKSIZE \
|
||||
((DEFAULT_THREAD_STACKSIZE < PTHREAD_STACK_MIN) ? \
|
||||
#define READ_THREAD_STACKSIZE \
|
||||
((DEFAULT_THREAD_STACKSIZE < PTHREAD_STACK_MIN) ? \
|
||||
PTHREAD_STACK_MIN : DEFAULT_THREAD_STACKSIZE)
|
||||
|
||||
/* We dynamically create a reader thread on demand. */
|
||||
@@ -1050,6 +1042,22 @@ bool xs_watch(struct xs_handle *h, const char *path, const char *token)
|
||||
mutex_unlock(&h->request_mutex);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
* Returns false on failure.
|
||||
*/
|
||||
bool xs_watch(struct xs_handle *h, const char *path, const char *token)
|
||||
{
|
||||
struct xsd_sockmsg msg = { .type = XS_WATCH };
|
||||
struct iovec iov[3];
|
||||
|
||||
if (!xs_watch_helper(h))
|
||||
return false;
|
||||
|
||||
iov[0].iov_base = &msg;
|
||||
iov[0].iov_len = sizeof(msg);
|
||||
iov[1].iov_base = (void *)path;
|
||||
@@ -1060,6 +1068,63 @@ bool xs_watch(struct xs_handle *h, const char *path, const char *token)
|
||||
return xs_bool(xs_talkv(h, iov, ARRAY_SIZE(iov), NULL));
|
||||
}
|
||||
|
||||
/* Same as xs_watch(), but with limiting the matching for modified
|
||||
* children to a specified depth (depth 0 only matches the node itself,
|
||||
* depth 1 will additionally match direct children of the node, etc.).
|
||||
* Only supported if the XENSTORE_SERVER_FEATURE_WATCHDEPTH (4) is set
|
||||
* in the returned features of xs_get_features_supported().
|
||||
*/
|
||||
bool xs_watch_depth(struct xs_handle *h, const char *path, const char *token,
|
||||
unsigned int depth)
|
||||
{
|
||||
struct xsd_sockmsg msg = { .type = XS_WATCH };
|
||||
struct iovec iov[4];
|
||||
char depthstr[MAX_STRLEN(depth)];
|
||||
static bool depth_supported;
|
||||
|
||||
if (!xs_watch_helper(h))
|
||||
return false;
|
||||
|
||||
if (!depth_supported) {
|
||||
unsigned int features;
|
||||
|
||||
if (!xs_get_features_supported(h, &features))
|
||||
return false;
|
||||
if (!(features & XENSTORE_SERVER_FEATURE_WATCHDEPTH))
|
||||
return false;
|
||||
depth_supported = true;
|
||||
}
|
||||
|
||||
snprintf(depthstr, sizeof(depthstr), "%u", depth);
|
||||
|
||||
iov[0].iov_base = &msg;
|
||||
iov[0].iov_len = sizeof(msg);
|
||||
iov[1].iov_base = (void *)path;
|
||||
iov[1].iov_len = strlen(path) + 1;
|
||||
iov[2].iov_base = (void *)token;
|
||||
iov[2].iov_len = strlen(token) + 1;
|
||||
iov[3].iov_base = depthstr;
|
||||
iov[3].iov_len = strlen(depthstr) + 1;
|
||||
|
||||
return xs_bool(xs_talkv(h, iov, ARRAY_SIZE(iov), NULL));
|
||||
}
|
||||
|
||||
/* If supported, same as xs_watch_depth(), use xs_watch() otherwise.
|
||||
* As a result watches might trigger for nodes below the watched path, too.
|
||||
* Not to be used for special watches!
|
||||
*/
|
||||
bool xs_watch_try_depth(struct xs_handle *h, const char *path,
|
||||
const char *token, unsigned int depth)
|
||||
{
|
||||
unsigned int features;
|
||||
|
||||
if (xs_get_features_supported(h, &features) &&
|
||||
(features & XENSTORE_SERVER_FEATURE_WATCHDEPTH) &&
|
||||
xs_watch_depth(h, path, token, depth))
|
||||
return true;
|
||||
|
||||
return xs_watch(h, path, token);
|
||||
}
|
||||
|
||||
/* Clear the pipe token if there are no more pending watchs.
|
||||
* We suppose the watch_mutex is already taken.
|
||||
@@ -1420,13 +1485,26 @@ static bool xs_uint(char *reply, unsigned int *uintval)
|
||||
|
||||
bool xs_get_features_supported(struct xs_handle *h, unsigned int *features)
|
||||
{
|
||||
static unsigned int own_features = 0;
|
||||
static bool features_valid = false;
|
||||
struct xsd_sockmsg msg = { .type = XS_GET_FEATURE };
|
||||
struct iovec iov[1];
|
||||
|
||||
if (features_valid) {
|
||||
*features = own_features;
|
||||
return true;
|
||||
}
|
||||
|
||||
iov[0].iov_base = &msg;
|
||||
iov[0].iov_len = sizeof(msg);
|
||||
|
||||
return xs_uint(xs_talkv(h, iov, ARRAY_SIZE(iov), NULL), features);
|
||||
if (!xs_uint(xs_talkv(h, iov, ARRAY_SIZE(iov), NULL), &own_features))
|
||||
return false;
|
||||
|
||||
features_valid = true;
|
||||
*features = own_features;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xs_get_features_domain(struct xs_handle *h, unsigned int domid,
|
||||
|
||||
@@ -124,6 +124,8 @@ struct xenstore_domain_interface {
|
||||
#define XENSTORE_SERVER_FEATURE_RECONNECTION 1
|
||||
/* The presence of the "error" field in the ring page */
|
||||
#define XENSTORE_SERVER_FEATURE_ERROR 2
|
||||
/* The XS_WATCH command can be used with a <depth> parameter */
|
||||
#define XENSTORE_SERVER_FEATURE_WATCHDEPTH 4
|
||||
|
||||
/* Valid values for the connection field */
|
||||
#define XENSTORE_CONNECTED 0 /* the steady-state */
|
||||
|
||||