[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 02/15] libxenstore: Provide xs_check_watch



On Mon, 2011-12-05 at 18:10 +0000, Ian Jackson wrote:
> Event-driven programs want to wait until the xs_fileno triggers for
> reading, and then repeatedly call xs_check_watch.
> 
> Also xs_read_watch exposes a useless "num" out parameter, which should
> always (if things aren't going hideously wrong) be at least 2 and
> which the caller shouldn't be interested in.  So xs_check_watch
> doesn't have one of those.
> 
> Signed-off-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>

Are we supposed to do something to the SONAME with this kind of change?
If not then:

Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx>

---
>  tools/xenstore/xs.c |   89 
> ++++++++++++++++++++++++++++++++++++++++++++-------
>  tools/xenstore/xs.h |   16 +++++++++
>  2 files changed, 93 insertions(+), 12 deletions(-)
> 
> diff --git a/tools/xenstore/xs.c b/tools/xenstore/xs.c
> index df270f7..8e54fe0 100644
> --- a/tools/xenstore/xs.c
> +++ b/tools/xenstore/xs.c
> @@ -132,7 +132,23 @@ struct xs_handle {
>  
>  #endif
>  
> -static int read_message(struct xs_handle *h);
> +static int read_message(struct xs_handle *h, int nonblocking);
> +
> +static void setnonblock(int fd, int nonblock) {
> +     int esave = errno;
> +     int flags = fcntl(fd, F_GETFL);
> +     if (flags == -1)
> +             goto out;
> +
> +     if (nonblock)
> +             flags |= O_NONBLOCK;
> +     else
> +             flags &= ~O_NONBLOCK;
> +
> +     fcntl(fd, F_SETFL, flags);
> +out:
> +     errno = esave;
> +}
>  
>  int xs_fileno(struct xs_handle *h)
>  {
> @@ -325,8 +341,16 @@ void xs_close(struct xs_handle* xsh)
>               xs_daemon_close(xsh);
>  }
>  
> -static bool read_all(int fd, void *data, unsigned int len)
> +static bool read_all(int fd, void *data, unsigned int len, int nonblocking)
> +     /* With nonblocking, either reads either everything requested,
> +      * or nothing. */
>  {
> +     if (!len)
> +             return true;
> +
> +     if (nonblocking)
> +             setnonblock(fd, 1);
> +
>       while (len) {
>               int done;
>  
> @@ -334,18 +358,28 @@ static bool read_all(int fd, void *data, unsigned int 
> len)
>               if (done < 0) {
>                       if (errno == EINTR)
>                               continue;
> -                     return false;
> +                     goto out_false;
>               }
>               if (done == 0) {
>                       /* It closed fd on us?  EBADF is appropriate. */
>                       errno = EBADF;
> -                     return false;
> +                     goto out_false;
>               }
>               data += done;
>               len -= done;
> +
> +             if (nonblocking) {
> +                     setnonblock(fd, 0);
> +                     nonblocking = 0;
> +             }
>       }
>  
>       return true;
> +
> +out_false:
> +     if (nonblocking)
> +             setnonblock(fd, 0);
> +     return false;
>  }
>  
>  #ifdef XSTEST
> @@ -374,7 +408,7 @@ static void *read_reply(
>       read_from_thread = read_thread_exists(h);
>  
>       /* Read from comms channel ourselves if there is no reader thread. */
> -     if (!read_from_thread && (read_message(h) == -1))
> +     if (!read_from_thread && (read_message(h, 0) == -1))
>               return NULL;
>  
>       mutex_lock(&h->reply_mutex);
> @@ -693,7 +727,8 @@ bool xs_watch(struct xs_handle *h, const char *path, 
> const char *token)
>   * Returns array of two pointers: path and token, or NULL.
>   * Call free() after use.
>   */
> -char **xs_read_watch(struct xs_handle *h, unsigned int *num)
> +static char **read_watch_internal(struct xs_handle *h, unsigned int *num,
> +                               int nonblocking)
>  {
>       struct xs_stored_msg *msg;
>       char **ret, *strings, c = 0;
> @@ -707,14 +742,20 @@ char **xs_read_watch(struct xs_handle *h, unsigned int 
> *num)
>        * we haven't called xs_watch.  Presumably the application
>        * will do so later; in the meantime we just block.
>        */
> -     while (list_empty(&h->watch_list) && h->fd != -1)
> +     while (list_empty(&h->watch_list) && h->fd != -1) {
> +             if (nonblocking) {
> +                     mutex_unlock(&h->watch_mutex);
> +                     errno = EAGAIN;
> +                     return 0;
> +             }
>               condvar_wait(&h->watch_condvar, &h->watch_mutex);
> +     }
>  #else /* !defined(USE_PTHREAD) */
>       /* Read from comms channel ourselves if there are no threads
>        * and therefore no reader thread. */
>  
>       assert(!read_thread_exists(h)); /* not threadsafe but worth a check */
> -     if ((read_message(h) == -1))
> +     if ((read_message(h, nonblocking) == -1))
>               return NULL;
>  
>  #endif /* !defined(USE_PTHREAD) */
> @@ -760,6 +801,24 @@ char **xs_read_watch(struct xs_handle *h, unsigned int 
> *num)
>       return ret;
>  }
>  
> +char **xs_check_watch(struct xs_handle *h)
> +{
> +     unsigned int num;
> +     char **ret;
> +     ret = read_watch_internal(h, &num, 1);
> +     if (ret) assert(num >= 2);
> +     return ret;
> +}
> +
> +/* Find out what node change was on (will block if nothing pending).
> + * Returns array of two pointers: path and token, or NULL.
> + * Call free() after use.
> + */
> +char **xs_read_watch(struct xs_handle *h, unsigned int *num)
> +{
> +     return read_watch_internal(h, num, 0);
> +}
> +
>  /* Remove a watch on a node.
>   * Returns false on failure (no watch on that node).
>   */
> @@ -940,11 +999,17 @@ char *xs_debug_command(struct xs_handle *h, const char 
> *cmd,
>                       ARRAY_SIZE(iov), NULL);
>  }
>  
> -static int read_message(struct xs_handle *h)
> +static int read_message(struct xs_handle *h, int nonblocking)
>  {
>       /* IMPORTANT: It is forbidden to call this function without
>        * acquiring the request lock and checking that h->read_thr_exists
>        * is false.  See "Lock discipline" in struct xs_handle, above. */
> +
> +     /* If nonblocking==1, this function will always read either
> +      * nothing, returning -1 and setting errno==EAGAIN, or we read
> +      * whole amount requested.  Ie as soon as we have the start of
> +      * the message we block until we get all of it.
> +      */
>           
>       struct xs_stored_msg *msg = NULL;
>       char *body = NULL;
> @@ -956,7 +1021,7 @@ static int read_message(struct xs_handle *h)
>       if (msg == NULL)
>               goto error;
>       cleanup_push(free, msg);
> -     if (!read_all(h->fd, &msg->hdr, sizeof(msg->hdr))) { /* Cancellation 
> point */
> +     if (!read_all(h->fd, &msg->hdr, sizeof(msg->hdr), nonblocking)) { /* 
> Cancellation point */
>               saved_errno = errno;
>               goto error_freemsg;
>       }
> @@ -966,7 +1031,7 @@ static int read_message(struct xs_handle *h)
>       if (body == NULL)
>               goto error_freemsg;
>       cleanup_push(free, body);
> -     if (!read_all(h->fd, body, msg->hdr.len)) { /* Cancellation point */
> +     if (!read_all(h->fd, body, msg->hdr.len, 0)) { /* Cancellation point */
>               saved_errno = errno;
>               goto error_freebody;
>       }
> @@ -1021,7 +1086,7 @@ static void *read_thread(void *arg)
>       struct xs_handle *h = arg;
>       int fd;
>  
> -     while (read_message(h) != -1)
> +     while (read_message(h, 0) != -1)
>               continue;
>  
>       /* An error return from read_message leaves the socket in an undefined
> diff --git a/tools/xenstore/xs.h b/tools/xenstore/xs.h
> index 1cbe255..63f535d 100644
> --- a/tools/xenstore/xs.h
> +++ b/tools/xenstore/xs.h
> @@ -135,6 +135,22 @@ 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);
>  
> +/* Check for node changes.  On success, returns a non-NULL pointer ret
> + * such that ret[0] and ret[1] are valid C strings, namely the
> + * triggering path (see docs/misc/xenstore.txt) and the token (from
> + * xs_watch).  On error return value is NULL setting errno.
> + * 
> + * Callers should, after xs_fileno has become readable, repeatedly
> + * call xs_check_watch until it returns NULL and sets errno to EAGAIN.
> + * (If the fd became readable, xs_check_watch is allowed to make it no
> + * longer show up as readable even if future calls to xs_check_watch
> + * will return more watch events.)
> + *
> + * After the caller is finished with the returned information it
> + * should be freed all in one go with free(ret).
> + */
> +char **xs_check_watch(struct xs_handle *h);
> +
>  /* Find out what node change was on (will block if nothing pending).
>   * Returns array containing the path and token. Use XS_WATCH_* to access 
> these
>   * elements. Call free() after use.



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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.