* To be RCU-friendly, the struct rculist instances must be freed via
* ovsrcu_postpone().
*
- * The API is almost the same as for struct list, with the following exeptions:
+ * The API is almost the same as for struct ovs_list, with the following
+ * exeptions:
*
* - The 'prev' pointer may not be accessed by the user.
* - The 'next' pointer should be accessed via rculist_next() by readers, and
* - rculist_front() returns a const pointer to accommodate for an RCU reader.
* - rculist_splice_hidden(): Spliced elements may not have been visible to
* RCU readers before the operation.
- * - rculist_poison(): Immediately poisons the 'prev' pointer, and schedules
- * ovsrcu_postpone() to poison the 'next' pointer. This issues a memory
- * write operation to the list element, hopefully crashing the program if
- * the list node was freed or re-used too early.
+ * - rculist_poison(): Only poisons the 'prev' pointer.
*
- * The following functions are variations of the struct list functions with
+ * The following functions are variations of the struct ovs_list functions with
* similar names, but are now restricted to the writer use:
*
* - rculist_back_protected()
/* A non-existing mutex to make it more difficult for an user to accidentally
* keep using the 'prev' pointer. This may be helpful when porting code from
- * struct list to rculist. */
+ * struct ovs_list to rculist. */
extern struct ovs_mutex rculist_fake_mutex;
/* Doubly linked list head or element. */
static inline struct rculist *rculist_next_protected(const struct rculist *);
/* List initialization. */
-#define RCULIST_INITIALIZER(LIST) { LIST, OVSRCU_INITIALIZER(LIST) }
+#define RCUOVS_LIST_INITIALIZER(LIST) { LIST, OVSRCU_INITIALIZER(LIST) }
static inline void rculist_init(struct rculist *list);
static inline void rculist_poison(struct rculist *elem);
#define RCULIST_POISON (struct rculist *)(UINTPTR_MAX / 0xf * 0xc)
-void rculist_poison__(struct rculist *list);
-
/* Initializes 'list' with pointers that will (probably) cause segfaults if
* dereferenced and, better yet, show up clearly in a debugger. */
static inline void
OVS_NO_THREAD_SAFETY_ANALYSIS
{
list->prev = RCULIST_POISON;
- ovsrcu_postpone(rculist_poison__, list);
+}
+
+/* Initializes 'list' with pointers that will (probably) cause segfaults if
+ * dereferenced and, better yet, show up clearly in a debugger.
+ *
+ * This variant poisons also the next pointer, so this may not be called if
+ * this list element is still visible to RCU readers. */
+static inline void
+rculist_poison__(struct rculist *list)
+ OVS_NO_THREAD_SAFETY_ANALYSIS
+{
+ rculist_poison(list);
+ ovsrcu_set_hidden(&list->next, RCULIST_POISON);
}
/* rculist insertion. */
position_next->prev = element;
element->prev = position->prev;
ovsrcu_set(&element->prev->next, element);
-
-#ifndef NDEBUG
- rculist_poison(position); /* XXX: Some overhead due to ovsrcu_postpone() */
-#endif
+ rculist_poison(position);
}
/* Initializes 'dst' with the contents of 'src', compensating for moving it
} else {
rculist_init(dst);
}
-
-#ifndef NDEBUG
- rculist_poison(src); /* XXX: Some overhead due to ovsrcu_postpone() */
-#endif
+ rculist_poison(src);
}
/* Removes 'elem' from its list and returns the element that followed it.
- * Undefined behavior if 'elem' is not in a list.
+ * Has no effect when 'elem' is initialized, but not in a list.
+ * Undefined behavior if 'elem' is not initialized.
*
* Afterward, 'elem' is not linked to from the list any more, but still links
* to the nodes in the list, and may still be referenced by other threads until
elem_next->prev = elem->prev;
ovsrcu_set(&elem->prev->next, elem_next);
-
-#ifndef NDEBUG
- rculist_poison(elem); /* XXX: Some overhead due to ovsrcu_postpone() */
-#endif
+ rculist_poison(elem);
return elem_next;
}
}
/* Returns the back element in 'list_'.
- * Undefined behavior if 'list_' is empty. */
+ * Returns the 'list_' itself, if 'list_' is empty. */
static inline struct rculist *
-rculist_back_protected(const struct rculist *list_)
+rculist_back_protected(const struct rculist *list)
OVS_NO_THREAD_SAFETY_ANALYSIS
{
- struct rculist *list = CONST_CAST(struct rculist *, list_);
-
- ovs_assert(!rculist_is_empty(list));
-
- return list->prev;
+ return CONST_CAST(struct rculist *, list)->prev;
}
/* Returns the number of elements in 'list'.