* 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.
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;
}