+ } while (0);
+
+#define MONO_LLS_FOREACH(list, type, elem) \
+ MONO_LLS_FOREACH_FILTERED ((list), type, elem, mono_lls_filter_accept_all)
+
+/*
+ * These macros can be used while other threads are potentially modifying the
+ * list, but they only provide a snapshot of the list as a result.
+ *
+ * NOTE: Do NOT break out of the loop through any other means than a break
+ * statement, as other ways of breaking the loop will skip past important
+ * cleanup work.
+ */
+
+#define MONO_LLS_FOREACH_FILTERED_SAFE(list, type, elem, filter) \
+ do { \
+ /* NOTE: Keep this macro's code in sync with the mono_lls_find () logic. */ \
+ MonoLinkedListSet *list__ = (list); \
+ MonoThreadHazardPointers *hp__ = mono_hazard_pointer_get (); \
+ gboolean progress__ = FALSE; \
+ uintptr_t hkey__; \
+ gboolean restart__; \
+ do { \
+ restart__ = FALSE; \
+ MonoLinkedListSetNode **prev__ = &list__->head; \
+ mono_hazard_pointer_set (hp__, 2, prev__); \
+ MonoLinkedListSetNode *cur__ = (MonoLinkedListSetNode *) mono_lls_get_hazardous_pointer_with_mask ((gpointer *) prev__, hp__, 1); \
+ while (1) { \
+ if (!cur__) { \
+ break; \
+ } \
+ MonoLinkedListSetNode *next__ = (MonoLinkedListSetNode *) mono_lls_get_hazardous_pointer_with_mask ((gpointer *) &cur__->next, hp__, 0); \
+ uintptr_t ckey__ = cur__->key; \
+ mono_memory_read_barrier (); \
+ if (*prev__ != cur__) { \
+ restart__ = TRUE; \
+ break; \
+ } \
+ if (!mono_lls_pointer_get_mark (next__)) { \
+ if (!progress__ || ckey__ > hkey__) { \
+ progress__ = TRUE; \
+ hkey__ = ckey__; \
+ type *elem = (type *) cur__; \
+ if (filter (elem)) { \
+ gboolean broke__ = TRUE; \
+ gboolean done__ = FALSE; \
+ do { \
+ if (done__) { \
+ broke__ = FALSE; \
+ break; \
+ } \
+ done__ = TRUE;
+
+#define MONO_LLS_FOREACH_SAFE_END \
+ broke__ = FALSE; \
+ break; \
+ } while (1); \
+ if (broke__) { \
+ break; \
+ } \
+ } \
+ } \
+ prev__ = &cur__->next; \
+ mono_hazard_pointer_set (hp__, 2, cur__); \
+ } else { \
+ next__ = (MonoLinkedListSetNode *) mono_lls_pointer_unmask (next__); \
+ if (InterlockedCompareExchangePointer ((volatile gpointer *) prev__, next__, cur__) == cur__) { \
+ mono_memory_write_barrier (); \
+ mono_hazard_pointer_clear (hp__, 1); \
+ if (list__->free_node_func) { \
+ mono_thread_hazardous_queue_free (cur__, list__->free_node_func); \
+ } \
+ } else { \
+ restart__ = TRUE; \
+ break; \
+ } \
+ } \
+ cur__ = (MonoLinkedListSetNode *) mono_lls_pointer_unmask (next__); \
+ mono_hazard_pointer_set (hp__, 1, cur__); \
+ } \
+ } while (restart__); \
+ mono_hazard_pointer_clear (hp__, 0); \
+ mono_hazard_pointer_clear (hp__, 1); \
+ mono_hazard_pointer_clear (hp__, 2); \
+ } while (0);
+
+#define MONO_LLS_FOREACH_SAFE(list, type, elem) \
+ MONO_LLS_FOREACH_FILTERED_SAFE ((list), type, elem, mono_lls_filter_accept_all)