Move the visited list to the abandoned list.
| 1109 | |
| 1110 | // Move the visited list to the abandoned list. |
| 1111 | static bool mi_abandoned_visited_revisit(void) |
| 1112 | { |
| 1113 | // quick check if the visited list is empty |
| 1114 | if (mi_atomic_load_ptr_relaxed(mi_segment_t, &abandoned_visited) == NULL) return false; |
| 1115 | |
| 1116 | // grab the whole visited list |
| 1117 | mi_segment_t* first = mi_atomic_exchange_ptr_acq_rel(mi_segment_t, &abandoned_visited, NULL); |
| 1118 | if (first == NULL) return false; |
| 1119 | |
| 1120 | // first try to swap directly if the abandoned list happens to be NULL |
| 1121 | mi_tagged_segment_t afirst; |
| 1122 | mi_tagged_segment_t ts = mi_atomic_load_relaxed(&abandoned); |
| 1123 | if (mi_tagged_segment_ptr(ts)==NULL) { |
| 1124 | size_t count = mi_atomic_load_relaxed(&abandoned_visited_count); |
| 1125 | afirst = mi_tagged_segment(first, ts); |
| 1126 | if (mi_atomic_cas_strong_acq_rel(&abandoned, &ts, afirst)) { |
| 1127 | mi_atomic_add_relaxed(&abandoned_count, count); |
| 1128 | mi_atomic_sub_relaxed(&abandoned_visited_count, count); |
| 1129 | return true; |
| 1130 | } |
| 1131 | } |
| 1132 | |
| 1133 | // find the last element of the visited list: O(n) |
| 1134 | mi_segment_t* last = first; |
| 1135 | mi_segment_t* next; |
| 1136 | while ((next = mi_atomic_load_ptr_relaxed(mi_segment_t, &last->abandoned_next)) != NULL) { |
| 1137 | last = next; |
| 1138 | } |
| 1139 | |
| 1140 | // and atomically prepend to the abandoned list |
| 1141 | // (no need to increase the readers as we don't access the abandoned segments) |
| 1142 | mi_tagged_segment_t anext = mi_atomic_load_relaxed(&abandoned); |
| 1143 | size_t count; |
| 1144 | do { |
| 1145 | count = mi_atomic_load_relaxed(&abandoned_visited_count); |
| 1146 | mi_atomic_store_ptr_release(mi_segment_t, &last->abandoned_next, mi_tagged_segment_ptr(anext)); |
| 1147 | afirst = mi_tagged_segment(first, anext); |
| 1148 | } while (!mi_atomic_cas_weak_release(&abandoned, &anext, afirst)); |
| 1149 | mi_atomic_add_relaxed(&abandoned_count, count); |
| 1150 | mi_atomic_sub_relaxed(&abandoned_visited_count, count); |
| 1151 | return true; |
| 1152 | } |
| 1153 | |
| 1154 | // Push on the abandoned list. |
| 1155 | static void mi_abandoned_push(mi_segment_t* segment) { |
no test coverage detected