[lttng-dev] [PATCH urcu] wfstack: implement nonblocking pop and next

Mathieu Desnoyers mathieu.desnoyers at efficios.com
Thu Dec 6 16:06:20 EST 2012


* Mathieu Desnoyers (mathieu.desnoyers at efficios.com) wrote:
> Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers at efficios.com>

I'll merge this patch into master, let me know if anything seems broken
and I'll do the appropriate follow-up.

Thanks,

Mathieu

> ---
> diff --git a/urcu/static/wfstack.h b/urcu/static/wfstack.h
> index 018a121..9bc9519 100644
> --- a/urcu/static/wfstack.h
> +++ b/urcu/static/wfstack.h
> @@ -137,7 +137,7 @@ int _cds_wfs_push(struct cds_wfs_stack *s, struct cds_wfs_node *node)
>   * Waiting for push to complete enqueue and return the next node.
>   */
>  static inline struct cds_wfs_node *
> -___cds_wfs_node_sync_next(struct cds_wfs_node *node)
> +___cds_wfs_node_sync_next(struct cds_wfs_node *node, int blocking)
>  {
>  	struct cds_wfs_node *next;
>  	int attempt = 0;
> @@ -146,6 +146,8 @@ ___cds_wfs_node_sync_next(struct cds_wfs_node *node)
>  	 * Adaptative busy-looping waiting for push to complete.
>  	 */
>  	while ((next = CMM_LOAD_SHARED(node->next)) == NULL) {
> +		if (!blocking)
> +			return CDS_WFS_WOULDBLOCK;
>  		if (++attempt >= CDS_WFS_ADAPT_ATTEMPTS) {
>  			poll(NULL, 0, CDS_WFS_WAIT);	/* Wait for 10ms */
>  			attempt = 0;
> @@ -157,6 +159,29 @@ ___cds_wfs_node_sync_next(struct cds_wfs_node *node)
>  	return next;
>  }
>  
> +static inline
> +struct cds_wfs_node *
> +___cds_wfs_pop(struct cds_wfs_stack *s, int blocking)
> +{
> +	struct cds_wfs_head *head, *new_head;
> +	struct cds_wfs_node *next;
> +
> +	for (;;) {
> +		head = CMM_LOAD_SHARED(s->head);
> +		if (___cds_wfs_end(head))
> +			return NULL;
> +		next = ___cds_wfs_node_sync_next(&head->node, blocking);
> +		if (!blocking && next == CDS_WFS_WOULDBLOCK)
> +			return CDS_WFS_WOULDBLOCK;
> +		new_head = caa_container_of(next, struct cds_wfs_head, node);
> +		if (uatomic_cmpxchg(&s->head, head, new_head) == head)
> +			return &head->node;
> +		if (!blocking)
> +			return CDS_WFS_WOULDBLOCK;
> +		/* busy-loop if head changed under us */
> +	}
> +}
> +
>  /*
>   * __cds_wfs_pop_blocking: pop a node from the stack.
>   *
> @@ -177,19 +202,20 @@ static inline
>  struct cds_wfs_node *
>  ___cds_wfs_pop_blocking(struct cds_wfs_stack *s)
>  {
> -	struct cds_wfs_head *head, *new_head;
> -	struct cds_wfs_node *next;
> +	return ___cds_wfs_pop(s, 1);
> +}
>  
> -	for (;;) {
> -		head = CMM_LOAD_SHARED(s->head);
> -		if (___cds_wfs_end(head))
> -			return NULL;
> -		next = ___cds_wfs_node_sync_next(&head->node);
> -		new_head = caa_container_of(next, struct cds_wfs_head, node);
> -		if (uatomic_cmpxchg(&s->head, head, new_head) == head)
> -			return &head->node;
> -		/* busy-loop if head changed under us */
> -	}
> +/*
> + * __cds_wfs_pop_nonblocking: pop a node from the stack.
> + *
> + * Same as __cds_wfs_pop_blocking, but returns CDS_WFS_WOULDBLOCK if
> + * it needs to block.
> + */
> +static inline
> +struct cds_wfs_node *
> +___cds_wfs_pop_nonblocking(struct cds_wfs_stack *s)
> +{
> +	return ___cds_wfs_pop(s, 0);
>  }
>  
>  /*
> @@ -303,6 +329,22 @@ _cds_wfs_first(struct cds_wfs_head *head)
>  	return &head->node;
>  }
>  
> +static inline struct cds_wfs_node *
> +___cds_wfs_next(struct cds_wfs_node *node, int blocking)
> +{
> +	struct cds_wfs_node *next;
> +
> +	next = ___cds_wfs_node_sync_next(node, blocking);
> +	/*
> +	 * CDS_WFS_WOULDBLOCK != CSD_WFS_END, so we can check for end
> +	 * even if ___cds_wfs_node_sync_next returns CDS_WFS_WOULDBLOCK,
> +	 * and still return CDS_WFS_WOULDBLOCK.
> +	 */
> +	if (___cds_wfs_end(next))
> +		return NULL;
> +	return next;
> +}
> +
>  /*
>   * cds_wfs_next_blocking: get next node of a popped stack.
>   *
> @@ -319,12 +361,20 @@ _cds_wfs_first(struct cds_wfs_head *head)
>  static inline struct cds_wfs_node *
>  _cds_wfs_next_blocking(struct cds_wfs_node *node)
>  {
> -	struct cds_wfs_node *next;
> +	return ___cds_wfs_next(node, 1);
> +}
>  
> -	next = ___cds_wfs_node_sync_next(node);
> -	if (___cds_wfs_end(next))
> -		return NULL;
> -	return next;
> +
> +/*
> + * cds_wfs_next_nonblocking: get next node of a popped stack.
> + *
> + * Same as cds_wfs_next_blocking, but returns CDS_WFS_WOULDBLOCK if it
> + * needs to block.
> + */
> +static inline struct cds_wfs_node *
> +_cds_wfs_next_nonblocking(struct cds_wfs_node *node)
> +{
> +	return ___cds_wfs_next(node, 0);
>  }
>  
>  #ifdef __cplusplus
> diff --git a/urcu/wfstack.h b/urcu/wfstack.h
> index 0e435ba..03fee8f 100644
> --- a/urcu/wfstack.h
> +++ b/urcu/wfstack.h
> @@ -58,6 +58,8 @@ extern "C" {
>   * synchronization.
>   */
>  
> +#define CDS_WFS_WOULDBLOCK	((void *) -1UL)
> +
>  /*
>   * struct cds_wfs_node is returned by __cds_wfs_pop, and also used as
>   * iterator on stack. It is not safe to dereference the node next
> @@ -184,6 +186,14 @@ extern struct cds_wfs_node *cds_wfs_first(struct cds_wfs_head *head);
>  extern struct cds_wfs_node *cds_wfs_next_blocking(struct cds_wfs_node *node);
>  
>  /*
> + * cds_wfs_next_nonblocking: get next node of a popped stack.
> + *
> + * Same as cds_wfs_next_blocking, but returns CDS_WFS_WOULDBLOCK if it
> + * needs to block.
> + */
> +extern struct cds_wfs_node *cds_wfs_next_nonblocking(struct cds_wfs_node *node);
> +
> +/*
>   * cds_wfs_pop_lock: lock stack pop-protection mutex.
>   */
>  extern void cds_wfs_pop_lock(struct cds_wfs_stack *s);
> @@ -212,6 +222,14 @@ extern void cds_wfs_pop_unlock(struct cds_wfs_stack *s);
>  extern struct cds_wfs_node *__cds_wfs_pop_blocking(struct cds_wfs_stack *s);
>  
>  /*
> + * __cds_wfs_pop_nonblocking: pop a node from the stack.
> + *
> + * Same as __cds_wfs_pop_blocking, but returns CDS_WFS_WOULDBLOCK if
> + * it needs to block.
> + */
> +extern struct cds_wfs_node *__cds_wfs_pop_nonblocking(struct cds_wfs_stack *s);
> +
> +/*
>   * __cds_wfs_pop_all: pop all nodes from a stack.
>   *
>   * __cds_wfs_pop_all does not require any synchronization with other
> diff --git a/wfstack.c b/wfstack.c
> index f0bae57..4ccb6b9 100644
> --- a/wfstack.c
> +++ b/wfstack.c
> @@ -68,6 +68,11 @@ struct cds_wfs_node *cds_wfs_next_blocking(struct cds_wfs_node *node)
>  	return _cds_wfs_next_blocking(node);
>  }
>  
> +struct cds_wfs_node *cds_wfs_next_nonblocking(struct cds_wfs_node *node)
> +{
> +	return _cds_wfs_next_nonblocking(node);
> +}
> +
>  void cds_wfs_pop_lock(struct cds_wfs_stack *s)
>  {
>  	_cds_wfs_pop_lock(s);
> @@ -83,6 +88,11 @@ struct cds_wfs_node *__cds_wfs_pop_blocking(struct cds_wfs_stack *s)
>  	return ___cds_wfs_pop_blocking(s);
>  }
>  
> +struct cds_wfs_node *__cds_wfs_pop_nonblocking(struct cds_wfs_stack *s)
> +{
> +	return ___cds_wfs_pop_nonblocking(s);
> +}
> +
>  struct cds_wfs_head *__cds_wfs_pop_all(struct cds_wfs_stack *s)
>  {
>  	return ___cds_wfs_pop_all(s);
> 
> -- 
> Mathieu Desnoyers
> Operating System Efficiency R&D Consultant
> EfficiOS Inc.
> http://www.efficios.com
> 
> _______________________________________________
> lttng-dev mailing list
> lttng-dev at lists.lttng.org
> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev

-- 
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com



More information about the lttng-dev mailing list