Linux circular buffer

linux内核中实现了环形buffer,它也能和内存屏障配合实现允许同时写、清空的buffer。

https://www.kernel.org/doc/html/latest/core-api/circular-buffers.html

struct circ_buf {
    char *buf;
    int head;
    int tail;
};

/* 使用空间 */
#define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size)-1))

/* 剩余空间 */
#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size))

/* 立即可读的连续空间  */
#define CIRC_CNT_TO_END(head,tail,size) \
    ({int end = (size) - (tail); \
      int n = ((head) + end) & ((size)-1); \
      n < end ? n : end;})

/* 立即可写的连续空间  */
#define CIRC_SPACE_TO_END(head,tail,size) \
    ({int end = (size) - 1 - (head); \
      int n = (end + (tail)) & ((size)-1); \
      n <= end ? n : end+1;})

提供的设施还是比较原始的,用法参考了下,acpi_dbg.c

#include <linux/circ_buf.h>

#define circ_count(circ) \
    (CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
#define circ_count_to_end(circ) \
    (CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
#define circ_space(circ) \
    (CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
#define circ_space_to_end(circ) \
    (CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))

// 初始化
int __init acpi_aml_init(void) 
{
    acpi_aml_io.in_crc.buf = acpi_aml_io.in_buf;
}
static int acpi_aml_open(/* ... */) 
{
    /* ... */    
    acpi_aml_io.in_crc.head = acpi_aml_io.in_crc.tail = 0;
    /* ... */
}

// 生产者
static int acpi_aml_write_user(const char __user *buf, int len)
{
    int ret;
    struct circ_buf *crc = &acpi_aml_io.in_crc;        // <----实例
    int n;
    char *p;

    ret = acpi_aml_lock_write(crc, ACPI_AML_IN_USER);  // <----上锁
    if (ret < 0)
        return ret;
    /* sync tail before inserting cmds */
    smp_mb();
    p = &crc->buf[crc->head];                          // <----获取头部
    n = min(len, circ_space_to_end(crc));              // <----填充长度
    if (copy_from_user(p, buf, n)) {
        ret = -EFAULT;
        goto out;
    }
    /* sync head after inserting cmds */
    smp_wmb();
    crc->head = (crc->head + n) & (ACPI_AML_BUF_SIZE - 1); // <----计算新的head,与上mask(2^n-1就是掩码)
    ret = n;
out:
    acpi_aml_unlock_fifo(ACPI_AML_IN_USER, ret >= 0);
    return n;
}

// 消费者(每次只消耗1byte)
static int acpi_aml_readb_kern(void)
{
    int ret;
    struct circ_buf *crc = &acpi_aml_io.in_crc;        // <----实例
    char *p;

    ret = acpi_aml_lock_read(crc, ACPI_AML_IN_KERN);   // <----上锁
    if (ret < 0)
        return ret;
    /* sync head before removing cmds */
    smp_rmb();
    p = &crc->buf[crc->tail];                          // <----获取尾部
    ret = (int)*p;
    /* sync tail before inserting cmds */
    smp_mb();
    crc->tail = (crc->tail + 1) & (ACPI_AML_BUF_SIZE - 1); // <----计算新的tail,与上mask(2^n-1就是掩码)
    acpi_aml_unlock_fifo(ACPI_AML_IN_KERN, true);      // <----解锁
    return ret;
}