diff mbox series

[v2,01/25] fifo32: add peek function

Message ID 20241008011852.1439154-2-tavip@google.com (mailing list archive)
State New, archived
Headers show
Series NXP i.MX RT595 | expand

Commit Message

Octavian Purdila Oct. 8, 2024, 1:18 a.m. UTC
Add fifo32_peek() that returns the first element from the queue
without popping it.

Signed-off-by: Octavian Purdila <tavip@google.com>
---
 include/qemu/fifo32.h | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

Comments

Mark Cave-Ayland Oct. 8, 2024, 11:27 a.m. UTC | #1
On 08/10/2024 02:18, Octavian Purdila wrote:

> Add fifo32_peek() that returns the first element from the queue
> without popping it.
> 
> Signed-off-by: Octavian Purdila <tavip@google.com>
> ---
>   include/qemu/fifo32.h | 28 ++++++++++++++++++++++++++++
>   1 file changed, 28 insertions(+)
> 
> diff --git a/include/qemu/fifo32.h b/include/qemu/fifo32.h
> index 4e9fd1b5ef..9de1807375 100644
> --- a/include/qemu/fifo32.h
> +++ b/include/qemu/fifo32.h
> @@ -140,6 +140,34 @@ static inline uint32_t fifo32_pop(Fifo32 *fifo)
>       return ret;
>   }
>   
> +/**
> + * fifo32_peek:
> + * @fifo: fifo to peek at
> + *
> + * Returns the value from the FIFO's head without poping it. Behaviour
> + * is undefined if the FIFO is empty. Clients are responsible for
> + * checking for emptiness using fifo32_is_empty().
> + *
> + * Returns: the value from the FIFO's head
> + */
> +
> +static inline uint32_t fifo32_peek(Fifo32 *fifo)
> +{
> +    uint32_t ret = 0, num;
> +    const uint8_t *buf;
> +
> +    buf = fifo8_peek_bufptr(&fifo->fifo, 4, &num);

Are you sure that you want to use fifo8_peek_bufptr() as opposed to fifo8_peek_buf() 
here? The reason for using the latter function (and why fifo8_*_bufptr() functions 
are not generally recommended) is that they will correctly handle the FIFO wraparound 
caused by the drifting head pointer which can occur if you don't empty the entire 
FIFO contents in a single *_pop() or *_pop_buf() operation.

> +    if (num != 4) {
> +        return ret;
> +    }
> +
> +    for (int i = 0; i < sizeof(uint32_t); i++) {
> +        ret |= buf[i] << (i * 8);
> +    }
> +
> +    return ret;
> +}
> +
>   /**
>    * There is no fifo32_pop_buf() because the data is not stored in the buffer
>    * as a set of native-order words.


ATB,

Mark.
Octavian Purdila Oct. 8, 2024, 5:25 p.m. UTC | #2
On Tue, Oct 8, 2024 at 4:27 AM Mark Cave-Ayland
<mark.cave-ayland@ilande.co.uk> wrote:
>
> On 08/10/2024 02:18, Octavian Purdila wrote:
>
> > Add fifo32_peek() that returns the first element from the queue
> > without popping it.
> >
> > Signed-off-by: Octavian Purdila <tavip@google.com>
> > ---
> >   include/qemu/fifo32.h | 28 ++++++++++++++++++++++++++++
> >   1 file changed, 28 insertions(+)
> >
> > diff --git a/include/qemu/fifo32.h b/include/qemu/fifo32.h
> > index 4e9fd1b5ef..9de1807375 100644
> > --- a/include/qemu/fifo32.h
> > +++ b/include/qemu/fifo32.h
> > @@ -140,6 +140,34 @@ static inline uint32_t fifo32_pop(Fifo32 *fifo)
> >       return ret;
> >   }
> >
> > +/**
> > + * fifo32_peek:
> > + * @fifo: fifo to peek at
> > + *
> > + * Returns the value from the FIFO's head without poping it. Behaviour
> > + * is undefined if the FIFO is empty. Clients are responsible for
> > + * checking for emptiness using fifo32_is_empty().
> > + *
> > + * Returns: the value from the FIFO's head
> > + */
> > +
> > +static inline uint32_t fifo32_peek(Fifo32 *fifo)
> > +{
> > +    uint32_t ret = 0, num;
> > +    const uint8_t *buf;
> > +
> > +    buf = fifo8_peek_bufptr(&fifo->fifo, 4, &num);
>
> Are you sure that you want to use fifo8_peek_bufptr() as opposed to fifo8_peek_buf()
> here? The reason for using the latter function (and why fifo8_*_bufptr() functions
> are not generally recommended) is that they will correctly handle the FIFO wraparound
> caused by the drifting head pointer which can occur if you don't empty the entire
> FIFO contents in a single *_pop() or *_pop_buf() operation.
>

I don't think that it matters in this case because the size of the
FIFO is always going to be a multiple of 4 and all push and pop
operations happen with 4 bytes as well. Am I missing something?

In any case, if it makes things more clear / consistent I can switch
to fifo8_peek_buf.

> > +    if (num != 4) {
> > +        return ret;
> > +    }
> > +
> > +    for (int i = 0; i < sizeof(uint32_t); i++) {
> > +        ret |= buf[i] << (i * 8);
> > +    }
> > +
> > +    return ret;
> > +}
> > +
> >   /**
> >    * There is no fifo32_pop_buf() because the data is not stored in the buffer
> >    * as a set of native-order words.
>
>
> ATB,
>
> Mark.
>
Mark Cave-Ayland Oct. 9, 2024, 8:41 a.m. UTC | #3
On 08/10/2024 18:25, Octavian Purdila wrote:

> On Tue, Oct 8, 2024 at 4:27 AM Mark Cave-Ayland
> <mark.cave-ayland@ilande.co.uk> wrote:
>>
>> On 08/10/2024 02:18, Octavian Purdila wrote:
>>
>>> Add fifo32_peek() that returns the first element from the queue
>>> without popping it.
>>>
>>> Signed-off-by: Octavian Purdila <tavip@google.com>
>>> ---
>>>    include/qemu/fifo32.h | 28 ++++++++++++++++++++++++++++
>>>    1 file changed, 28 insertions(+)
>>>
>>> diff --git a/include/qemu/fifo32.h b/include/qemu/fifo32.h
>>> index 4e9fd1b5ef..9de1807375 100644
>>> --- a/include/qemu/fifo32.h
>>> +++ b/include/qemu/fifo32.h
>>> @@ -140,6 +140,34 @@ static inline uint32_t fifo32_pop(Fifo32 *fifo)
>>>        return ret;
>>>    }
>>>
>>> +/**
>>> + * fifo32_peek:
>>> + * @fifo: fifo to peek at
>>> + *
>>> + * Returns the value from the FIFO's head without poping it. Behaviour
>>> + * is undefined if the FIFO is empty. Clients are responsible for
>>> + * checking for emptiness using fifo32_is_empty().
>>> + *
>>> + * Returns: the value from the FIFO's head
>>> + */
>>> +
>>> +static inline uint32_t fifo32_peek(Fifo32 *fifo)
>>> +{
>>> +    uint32_t ret = 0, num;
>>> +    const uint8_t *buf;
>>> +
>>> +    buf = fifo8_peek_bufptr(&fifo->fifo, 4, &num);
>>
>> Are you sure that you want to use fifo8_peek_bufptr() as opposed to fifo8_peek_buf()
>> here? The reason for using the latter function (and why fifo8_*_bufptr() functions
>> are not generally recommended) is that they will correctly handle the FIFO wraparound
>> caused by the drifting head pointer which can occur if you don't empty the entire
>> FIFO contents in a single *_pop() or *_pop_buf() operation.
>>
> 
> I don't think that it matters in this case because the size of the
> FIFO is always going to be a multiple of 4 and all push and pop
> operations happen with 4 bytes as well. Am I missing something?
> 
> In any case, if it makes things more clear / consistent I can switch
> to fifo8_peek_buf.

I'm guess I'm just a little bit wary of the Fifo32 API since it appears that 
fifo32_num_used(), fifo32_num_free() and fifo32_is_full() are written in a way that 
suggests unaligned accesses can occur.

Given that fifo8_push() and fifo8_pop() should assert() upon failure I don't think 
that's possible for Fifo32, but then all my test cases use Fifo8.

If you're confident from your tests that this can't happen then we can leave it as-is.


ATB,

Mark.
diff mbox series

Patch

diff --git a/include/qemu/fifo32.h b/include/qemu/fifo32.h
index 4e9fd1b5ef..9de1807375 100644
--- a/include/qemu/fifo32.h
+++ b/include/qemu/fifo32.h
@@ -140,6 +140,34 @@  static inline uint32_t fifo32_pop(Fifo32 *fifo)
     return ret;
 }
 
+/**
+ * fifo32_peek:
+ * @fifo: fifo to peek at
+ *
+ * Returns the value from the FIFO's head without poping it. Behaviour
+ * is undefined if the FIFO is empty. Clients are responsible for
+ * checking for emptiness using fifo32_is_empty().
+ *
+ * Returns: the value from the FIFO's head
+ */
+
+static inline uint32_t fifo32_peek(Fifo32 *fifo)
+{
+    uint32_t ret = 0, num;
+    const uint8_t *buf;
+
+    buf = fifo8_peek_bufptr(&fifo->fifo, 4, &num);
+    if (num != 4) {
+        return ret;
+    }
+
+    for (int i = 0; i < sizeof(uint32_t); i++) {
+        ret |= buf[i] << (i * 8);
+    }
+
+    return ret;
+}
+
 /**
  * There is no fifo32_pop_buf() because the data is not stored in the buffer
  * as a set of native-order words.