X-Git-Url: https://git.liburcu.org/?p=urcu.git;a=blobdiff_plain;f=urcu%2Fwfcqueue.h;h=ec86032dd4e091155c64b8d80a0525874d90269a;hp=4ce8fe962296406b7b69eb75992ea9d910ef6f08;hb=4d0d7cbccec1c35f544f6fee24b762e398a2f0b9;hpb=ffa11a1830c532f3b052146eb9f0dd450cb2a0f2 diff --git a/urcu/wfcqueue.h b/urcu/wfcqueue.h index 4ce8fe9..ec86032 100644 --- a/urcu/wfcqueue.h +++ b/urcu/wfcqueue.h @@ -43,7 +43,7 @@ extern "C" { * McKenney. */ -#define CDS_WFCQ_WOULDBLOCK ((void *) -1UL) +#define CDS_WFCQ_WOULDBLOCK ((struct cds_wfcq_node *) -1UL) enum cds_wfcq_ret { CDS_WFCQ_RET_WOULDBLOCK = -1, @@ -52,6 +52,10 @@ enum cds_wfcq_ret { CDS_WFCQ_RET_SRC_EMPTY = 2, }; +enum cds_wfcq_state { + CDS_WFCQ_STATE_LAST = (1U << 0), +}; + struct cds_wfcq_node { struct cds_wfcq_node *next; }; @@ -61,11 +65,65 @@ struct cds_wfcq_node { * enqueue/dequeue are expected from many CPUs. This eliminates * false-sharing between enqueue and dequeue. */ +struct __cds_wfcq_head { + struct cds_wfcq_node node; +}; + struct cds_wfcq_head { struct cds_wfcq_node node; pthread_mutex_t lock; }; +#ifndef __cplusplus +/* + * The transparent union allows calling functions that work on both + * struct cds_wfcq_head and struct __cds_wfcq_head on any of those two + * types. + */ +typedef union { + struct __cds_wfcq_head *_h; + struct cds_wfcq_head *h; +} __attribute__((__transparent_union__)) cds_wfcq_head_ptr_t; + +/* + * This static inline is only present for compatibility with C++. It is + * effect-less in C. + */ +static inline struct __cds_wfcq_head *__cds_wfcq_head_cast(struct __cds_wfcq_head *head) +{ + return head; +} + +/* + * This static inline is only present for compatibility with C++. It is + * effect-less in C. + */ +static inline struct cds_wfcq_head *cds_wfcq_head_cast(struct cds_wfcq_head *head) +{ + return head; +} +#else /* #ifndef __cplusplus */ + +/* C++ ignores transparent union. */ +typedef union { + struct __cds_wfcq_head *_h; + struct cds_wfcq_head *h; +} cds_wfcq_head_ptr_t; + +/* C++ ignores transparent union. Requires an explicit conversion. */ +static inline cds_wfcq_head_ptr_t __cds_wfcq_head_cast(struct __cds_wfcq_head *head) +{ + cds_wfcq_head_ptr_t ret = { ._h = head }; + return ret; +} +/* C++ ignores transparent union. Requires an explicit conversion. */ +static inline cds_wfcq_head_ptr_t cds_wfcq_head_cast(struct cds_wfcq_head *head) +{ + cds_wfcq_head_ptr_t ret = { .h = head }; + return ret; +} +#endif /* #else #ifndef __cplusplus */ + struct cds_wfcq_tail { struct cds_wfcq_node *p; }; @@ -85,12 +143,16 @@ struct cds_wfcq_tail { /* Locking performed within cds_wfcq calls. */ #define cds_wfcq_dequeue_blocking _cds_wfcq_dequeue_blocking +#define cds_wfcq_dequeue_with_state_blocking \ + _cds_wfcq_dequeue_with_state_blocking #define cds_wfcq_splice_blocking _cds_wfcq_splice_blocking #define cds_wfcq_first_blocking _cds_wfcq_first_blocking #define cds_wfcq_next_blocking _cds_wfcq_next_blocking /* Locking ensured by caller by holding cds_wfcq_dequeue_lock() */ #define __cds_wfcq_dequeue_blocking ___cds_wfcq_dequeue_blocking +#define __cds_wfcq_dequeue_with_state_blocking \ + ___cds_wfcq_dequeue_with_state_blocking #define __cds_wfcq_splice_blocking ___cds_wfcq_splice_blocking #define __cds_wfcq_first_blocking ___cds_wfcq_first_blocking #define __cds_wfcq_next_blocking ___cds_wfcq_next_blocking @@ -101,6 +163,8 @@ struct cds_wfcq_tail { * need to block. splice returns nonzero if it needs to block. */ #define __cds_wfcq_dequeue_nonblocking ___cds_wfcq_dequeue_nonblocking +#define __cds_wfcq_dequeue_with_state_nonblocking \ + ___cds_wfcq_dequeue_with_state_nonblocking #define __cds_wfcq_splice_nonblocking ___cds_wfcq_splice_nonblocking #define __cds_wfcq_first_nonblocking ___cds_wfcq_first_nonblocking #define __cds_wfcq_next_nonblocking ___cds_wfcq_next_nonblocking @@ -153,12 +217,18 @@ extern void cds_wfcq_node_init(struct cds_wfcq_node *node); extern void cds_wfcq_init(struct cds_wfcq_head *head, struct cds_wfcq_tail *tail); +/* + * __cds_wfcq_init: initialize wait-free queue. + */ +extern void __cds_wfcq_init(struct __cds_wfcq_head *head, + struct cds_wfcq_tail *tail); + /* * cds_wfcq_empty: return whether wait-free queue is empty. * * No memory barrier is issued. No mutual exclusion is required. */ -extern bool cds_wfcq_empty(struct cds_wfcq_head *head, +extern bool cds_wfcq_empty(cds_wfcq_head_ptr_t head, struct cds_wfcq_tail *tail); /* @@ -182,7 +252,7 @@ extern void cds_wfcq_dequeue_unlock(struct cds_wfcq_head *head, * Returns false if the queue was empty prior to adding the node. * Returns true otherwise. */ -extern bool cds_wfcq_enqueue(struct cds_wfcq_head *head, +extern bool cds_wfcq_enqueue(cds_wfcq_head_ptr_t head, struct cds_wfcq_tail *tail, struct cds_wfcq_node *node); @@ -199,6 +269,17 @@ extern struct cds_wfcq_node *cds_wfcq_dequeue_blocking( struct cds_wfcq_head *head, struct cds_wfcq_tail *tail); +/* + * cds_wfcq_dequeue_with_state_blocking: dequeue with state. + * + * Same as cds_wfcq_dequeue_blocking, but saves whether dequeueing the + * last node of the queue into state (CDS_WFCQ_STATE_LAST). + */ +extern struct cds_wfcq_node *cds_wfcq_dequeue_with_state_blocking( + struct cds_wfcq_head *head, + struct cds_wfcq_tail *tail, + int *state); + /* * cds_wfcq_splice_blocking: enqueue all src_q nodes at the end of dest_q. * @@ -210,7 +291,7 @@ extern struct cds_wfcq_node *cds_wfcq_dequeue_blocking( * ensured. * * Returns enum cds_wfcq_ret which indicates the state of the src or - * dest queue. Cannot block. + * dest queue. */ extern enum cds_wfcq_ret cds_wfcq_splice_blocking( struct cds_wfcq_head *dest_q_head, @@ -228,9 +309,20 @@ extern enum cds_wfcq_ret cds_wfcq_splice_blocking( * caller. */ extern struct cds_wfcq_node *__cds_wfcq_dequeue_blocking( - struct cds_wfcq_head *head, + cds_wfcq_head_ptr_t head, struct cds_wfcq_tail *tail); +/* + * __cds_wfcq_dequeue_with_state_blocking: dequeue with state. + * + * Same as __cds_wfcq_dequeue_blocking, but saves whether dequeueing the + * last node of the queue into state (CDS_WFCQ_STATE_LAST). + */ +extern struct cds_wfcq_node *__cds_wfcq_dequeue_with_state_blocking( + cds_wfcq_head_ptr_t head, + struct cds_wfcq_tail *tail, + int *state); + /* * __cds_wfcq_dequeue_nonblocking: dequeue a node from a wait-free queue. * @@ -238,9 +330,20 @@ extern struct cds_wfcq_node *__cds_wfcq_dequeue_blocking( * if it needs to block. */ extern struct cds_wfcq_node *__cds_wfcq_dequeue_nonblocking( - struct cds_wfcq_head *head, + cds_wfcq_head_ptr_t head, struct cds_wfcq_tail *tail); +/* + * __cds_wfcq_dequeue_with_state_blocking: dequeue with state. + * + * Same as __cds_wfcq_dequeue_nonblocking, but saves whether dequeueing + * the last node of the queue into state (CDS_WFCQ_STATE_LAST). + */ +extern struct cds_wfcq_node *__cds_wfcq_dequeue_with_state_nonblocking( + cds_wfcq_head_ptr_t head, + struct cds_wfcq_tail *tail, + int *state); + /* * __cds_wfcq_splice_blocking: enqueue all src_q nodes at the end of dest_q. * @@ -252,9 +355,9 @@ extern struct cds_wfcq_node *__cds_wfcq_dequeue_nonblocking( * dest queue. Never returns CDS_WFCQ_RET_WOULDBLOCK. */ extern enum cds_wfcq_ret __cds_wfcq_splice_blocking( - struct cds_wfcq_head *dest_q_head, + cds_wfcq_head_ptr_t dest_q_head, struct cds_wfcq_tail *dest_q_tail, - struct cds_wfcq_head *src_q_head, + cds_wfcq_head_ptr_t src_q_head, struct cds_wfcq_tail *src_q_tail); /* @@ -264,9 +367,9 @@ extern enum cds_wfcq_ret __cds_wfcq_splice_blocking( * CDS_WFCQ_RET_WOULDBLOCK if it needs to block. */ extern enum cds_wfcq_ret __cds_wfcq_splice_nonblocking( - struct cds_wfcq_head *dest_q_head, + cds_wfcq_head_ptr_t dest_q_head, struct cds_wfcq_tail *dest_q_tail, - struct cds_wfcq_head *src_q_head, + cds_wfcq_head_ptr_t src_q_head, struct cds_wfcq_tail *src_q_tail); /* @@ -284,7 +387,7 @@ extern enum cds_wfcq_ret __cds_wfcq_splice_nonblocking( * Returns NULL if queue is empty, first node otherwise. */ extern struct cds_wfcq_node *__cds_wfcq_first_blocking( - struct cds_wfcq_head *head, + cds_wfcq_head_ptr_t head, struct cds_wfcq_tail *tail); /* @@ -294,7 +397,7 @@ extern struct cds_wfcq_node *__cds_wfcq_first_blocking( * it needs to block. */ extern struct cds_wfcq_node *__cds_wfcq_first_nonblocking( - struct cds_wfcq_head *head, + cds_wfcq_head_ptr_t head, struct cds_wfcq_tail *tail); /* @@ -313,7 +416,7 @@ extern struct cds_wfcq_node *__cds_wfcq_first_nonblocking( * otherwise. */ extern struct cds_wfcq_node *__cds_wfcq_next_blocking( - struct cds_wfcq_head *head, + cds_wfcq_head_ptr_t head, struct cds_wfcq_tail *tail, struct cds_wfcq_node *node); @@ -324,7 +427,7 @@ extern struct cds_wfcq_node *__cds_wfcq_next_blocking( * it needs to block. */ extern struct cds_wfcq_node *__cds_wfcq_next_nonblocking( - struct cds_wfcq_head *head, + cds_wfcq_head_ptr_t head, struct cds_wfcq_tail *tail, struct cds_wfcq_node *node); @@ -333,7 +436,7 @@ extern struct cds_wfcq_node *__cds_wfcq_next_nonblocking( /* * __cds_wfcq_for_each_blocking: Iterate over all nodes in a queue, * without dequeuing them. - * @head: head of the queue (struct cds_wfcq_head pointer). + * @head: head of the queue (struct cds_wfcq_head or __cds_wfcq_head pointer). * @tail: tail of the queue (struct cds_wfcq_tail pointer). * @node: iterator on the queue (struct cds_wfcq_node pointer). * @@ -350,7 +453,7 @@ extern struct cds_wfcq_node *__cds_wfcq_next_nonblocking( /* * __cds_wfcq_for_each_blocking_safe: Iterate over all nodes in a queue, * without dequeuing them. Safe against deletion. - * @head: head of the queue (struct cds_wfcq_head pointer). + * @head: head of the queue (struct cds_wfcq_head or __cds_wfcq_head pointer). * @tail: tail of the queue (struct cds_wfcq_tail pointer). * @node: iterator on the queue (struct cds_wfcq_node pointer). * @n: struct cds_wfcq_node pointer holding the next pointer (used