blob: 1d735bcc55493fdcb68e2ee4ce34be5d6810825f [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
//
//
#include "ring.h"
#include <assert.h>
//
// A barebones ring
//
void
spinel_ring_init(struct spinel_ring * ring, uint32_t size)
{
assert(size >= 1);
ring->size = size;
ring->head = 0;
ring->tail = 0;
ring->rem = size;
}
bool
spinel_ring_is_empty(struct spinel_ring const * ring)
{
return ring->rem == 0;
}
bool
spinel_ring_is_full(struct spinel_ring const * ring)
{
return ring->rem == ring->size;
}
uint32_t
spinel_ring_dropped(struct spinel_ring const * ring)
{
return ring->size - ring->rem;
}
uint32_t
spinel_ring_head_nowrap(struct spinel_ring const * ring)
{
uint32_t const nowrap = ring->size - ring->head;
return (ring->rem <= nowrap) ? ring->rem : nowrap;
}
uint32_t
spinel_ring_tail_nowrap(struct spinel_ring const * ring)
{
uint32_t const nowrap = ring->size - ring->tail;
uint32_t const dropped = spinel_ring_dropped(ring);
return (dropped <= nowrap) ? dropped : nowrap;
}
uint32_t
spinel_ring_acquire_1(struct spinel_ring * ring)
{
assert(ring->rem >= 1);
//
// CAUTION: this is unguarded so always test before acquiring
//
ring->rem -= 1;
uint32_t const head = ring->head;
uint32_t const new_head = head + 1;
ring->head = (new_head < ring->size) ? new_head : 0;
return head;
}
void
spinel_ring_drop_1(struct spinel_ring * ring)
{
assert(ring->rem >= 1);
//
// CAUTION: this is unguarded so always test before acquiring
//
ring->rem -= 1;
uint32_t const head = ring->head;
uint32_t const new_head = head + 1;
ring->head = (new_head < ring->size) ? new_head : 0;
}
void
spinel_ring_drop_n(struct spinel_ring * ring, uint32_t n)
{
assert(ring->rem >= n);
//
// CAUTION: this is unguarded so always test before acquiring
//
ring->rem -= n;
uint32_t const head = ring->head;
uint32_t const new_head = head + n;
ring->head = (new_head < ring->size) ? new_head : new_head - ring->size;
}
void
spinel_ring_release_n(struct spinel_ring * ring, uint32_t n)
{
assert(ring->rem + n <= ring->size);
//
// CAUTION: assumes conservation so no need to test before release
//
ring->rem += n;
uint32_t const tail = ring->tail + n;
ring->tail = (tail < ring->size) ? tail : tail - ring->size;
}
//
// A subsidiary ring for when space is known to be implicitly
// available.
//
void
spinel_next_init(struct spinel_next * next, uint32_t size)
{
next->size = size;
next->head = 0;
}
uint32_t
spinel_next_acquire_1(struct spinel_next * next)
{
uint32_t const head = next->head;
uint32_t const new_head = head + 1;
next->head = (new_head < next->size) ? new_head : 0;
return head;
}
uint32_t
spinel_next_acquire_2(struct spinel_next * next, uint32_t * span)
{
uint32_t const head = next->head;
if (head + 1 < next->size)
{
uint32_t const new_head = head + 2;
next->head = (new_head < next->size) ? new_head : 0;
*span = 2;
return head;
}
else // we need two contiguous slots
{
next->head = 2;
*span = 3;
return 0;
}
}
void
spinel_next_drop_n(struct spinel_next * next, uint32_t n)
{
uint32_t const head = next->head;
uint32_t const new_head = head + n;
next->head = (new_head < next->size) ? new_head : new_head - next->size;
}
//
//
//