0
votes

I have a question regarding using the circular buffer macros in the linux kernel.

I'm trying to use the circular buffer macros from include/linux/circ_buf.h.

The ACCESS_ONCE() macro is used to ensure that the compiler will read from memory the value, and not try to optimize the access.

In the documentation of circular buffer the following code is given as an example for the producer:

        spin_lock(&producer_lock);

        unsigned long head = buffer->head;
        /* The spin_unlock() and next spin_lock() provide needed ordering. */
        unsigned long tail = ACCESS_ONCE(buffer->tail);

        if (CIRC_SPACE(head, tail, buffer->size) >= 1) {
            /* insert one item into the buffer */
            struct item *item = buffer[head];

            produce_item(item);

            smp_store_release(buffer->head,
                      (head + 1) & (buffer->size - 1));

            /* wake_up() will make sure that the head is committed before
             * waking anyone up */
            wake_up(consumer);
        }

        spin_unlock(&producer_lock);

I have 3 questions:

  1. What I'm not sure is, if I need to use ACCESS_ONCE when reading the value of buffer->tail, since in my function I need to read buffer->tail only once. I read the value at the start of the function and then use that value throughout the function. I assume that this example code was written with the idea that it runs in a loop and the new tail value must be read from memory in every iteration.

  2. I thought if you have a single producer and a single consumer you don't need to use spinlocks. Why are spin locks used here?

  3. Also there is this comment here:

    /* wake_up() will make sure that the head is committed before * waking anyone up */

    If I don't use wake_up in my code, do I need to use a memory barrier? Isn't smp_store_release() already issuing a memory barrier?

1
1. Your assumption is probably correct. 2. For single producer/consumer, you are correct in that you don't need spinlocks, but having them makes it easier in the future.Drew McGowen
1. So I don't need ACCESS_ONCE, if I read the value only once? Do you know If I need a memory barrier if I don't use wake_up, but are using smp_store_release()?user711495
To your first question, I'd imagine so. As for the memory barrier, I'm not too familiar with SMP LinuxDrew McGowen

1 Answers

0
votes
  1. Without ACCESS_ONCE, the compiler would be allowed to optimize the code so that it reads the variable multiple times.

  2. You need spinlocks when the producer and consumer can run concurrently, and when the shared variables must be updated atomically.

  3. Whatever mechanism you use for waking up the consumer must ensure that the previous writes and the wakeup are ordered.