| 302 | } |
| 303 | |
| 304 | static __inline void * |
| 305 | buf_ring_peek_clear_sc(struct buf_ring *br) |
| 306 | { |
| 307 | #ifdef DEBUG_BUFRING |
| 308 | void *ret; |
| 309 | |
| 310 | if (!mtx_owned(br->br_lock)) |
| 311 | panic("lock not held on single consumer dequeue"); |
| 312 | #endif |
| 313 | |
| 314 | if (br->br_cons_head == br->br_prod_tail) |
| 315 | return (NULL); |
| 316 | |
| 317 | #if defined(__arm__) || defined(__aarch64__) |
| 318 | /* |
| 319 | * The barrier is required there on ARM and ARM64 to ensure, that |
| 320 | * br->br_ring[br->br_cons_head] will not be fetched before the above |
| 321 | * condition is checked. |
| 322 | * Without the barrier, it is possible, that buffer will be fetched |
| 323 | * before the enqueue will put mbuf into br, then, in the meantime, the |
| 324 | * enqueue will update the array and the br_prod_tail, and the |
| 325 | * conditional check will be true, so we will return previously fetched |
| 326 | * (and invalid) buffer. |
| 327 | */ |
| 328 | atomic_thread_fence_acq(); |
| 329 | #endif |
| 330 | |
| 331 | #ifdef DEBUG_BUFRING |
| 332 | /* |
| 333 | * Single consumer, i.e. cons_head will not move while we are |
| 334 | * running, so atomic_swap_ptr() is not necessary here. |
| 335 | */ |
| 336 | ret = br->br_ring[br->br_cons_head]; |
| 337 | br->br_ring[br->br_cons_head] = NULL; |
| 338 | return (ret); |
| 339 | #else |
| 340 | return (br->br_ring[br->br_cons_head]); |
| 341 | #endif |
| 342 | } |
| 343 | |
| 344 | static __inline int |
| 345 | buf_ring_full(struct buf_ring *br) |
no test coverage detected