* Caller passes in a state, with a guarantee that there is work to do and that * all items up to the pidx_tail in the state are visible. */
| 167 | * all items up to the pidx_tail in the state are visible. |
| 168 | */ |
| 169 | static void |
| 170 | drain_ring_lockless(struct ifmp_ring *r, union ring_state os, uint16_t prev, int budget) |
| 171 | { |
| 172 | union ring_state ns; |
| 173 | int n, pending, total; |
| 174 | uint16_t cidx = os.cidx; |
| 175 | uint16_t pidx = os.pidx_tail; |
| 176 | |
| 177 | MPASS(os.flags == BUSY); |
| 178 | MPASS(cidx != pidx); |
| 179 | |
| 180 | if (prev == IDLE) |
| 181 | counter_u64_add(r->starts, 1); |
| 182 | pending = 0; |
| 183 | total = 0; |
| 184 | |
| 185 | while (cidx != pidx) { |
| 186 | /* Items from cidx to pidx are available for consumption. */ |
| 187 | n = r->drain(r, cidx, pidx); |
| 188 | if (n == 0) { |
| 189 | critical_enter(); |
| 190 | os.state = r->state; |
| 191 | do { |
| 192 | ns.state = os.state; |
| 193 | ns.cidx = cidx; |
| 194 | ns.flags = STALLED; |
| 195 | } while (atomic_fcmpset_64(&r->state, &os.state, |
| 196 | ns.state) == 0); |
| 197 | critical_exit(); |
| 198 | if (prev != STALLED) |
| 199 | counter_u64_add(r->stalls, 1); |
| 200 | else if (total > 0) { |
| 201 | counter_u64_add(r->restarts, 1); |
| 202 | counter_u64_add(r->stalls, 1); |
| 203 | } |
| 204 | break; |
| 205 | } |
| 206 | cidx = increment_idx(r, cidx, n); |
| 207 | pending += n; |
| 208 | total += n; |
| 209 | |
| 210 | /* |
| 211 | * We update the cidx only if we've caught up with the pidx, the |
| 212 | * real cidx is getting too far ahead of the one visible to |
| 213 | * everyone else, or we have exceeded our budget. |
| 214 | */ |
| 215 | if (cidx != pidx && pending < 64 && total < budget) |
| 216 | continue; |
| 217 | critical_enter(); |
| 218 | os.state = r->state; |
| 219 | do { |
| 220 | ns.state = os.state; |
| 221 | ns.cidx = cidx; |
| 222 | ns.flags = state_to_flags(ns, total >= budget); |
| 223 | } while (atomic_fcmpset_acq_64(&r->state, &os.state, |
| 224 | ns.state) == 0); |
| 225 | critical_exit(); |
| 226 |
no test coverage detected