Last active
December 19, 2018 05:01
-
-
Save buttercutter/3efaf801c14e2bc0d64aa1225841077c to your computer and use it in GitHub Desktop.
Modified https://github.com/KastnerRG/riffa/blob/master/driver/linux/circ_queue.c using kernel built-in circ_buf struct
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Filename: circ_buf.c | |
* Version: 1.0 | |
* Description: A circular buffer using API from | |
* https://github.com/torvalds/linux/blob/master/Documentation/core-api/circular-buffers.rst | |
*/ | |
#include <linux/slab.h> | |
#include <linux/circ_buf.h> | |
#include "circ_buf.h" | |
#define DEBUG 1 | |
#ifdef DEBUG | |
#define DEBUG_MSG(...) printk(__VA_ARGS__) | |
#else | |
#define DEBUG_MSG(...) | |
#endif | |
typedef struct item { | |
unsigned int val1; // event number | |
unsigned int val2; // relevant value tied to the event number | |
} item; | |
struct circ_buf * init_circ_queue(int len) | |
{ | |
struct circ_buf * q; | |
//spinlock_t head_tail_lock; | |
q = kzalloc(sizeof(struct circ_buf), GFP_KERNEL); | |
if (q == NULL) { | |
DEBUG_MSG(KERN_ERR "Not enough memory to allocate circ_queue"); | |
return NULL; | |
} | |
//spin_lock(&head_tail_lock); | |
q->head = 0; | |
q->tail = 0; | |
//spin_unlock(&head_tail_lock); | |
// creates an array of length 'len' where each array location can store a struct * item | |
q->buf = (char *) kzalloc(len*sizeof(struct item)*sizeof(unsigned int), GFP_KERNEL); | |
if (q->buf == NULL) { | |
DEBUG_MSG(KERN_ERR "Not enough memory to allocate circ_queue array"); | |
return NULL; | |
} | |
return q; | |
} | |
inline int push_circ_queue(struct circ_buf * buffer, unsigned int val1, unsigned int val2) | |
{ | |
unsigned int head; | |
unsigned int tail; | |
//spinlock_t producer_lock; | |
// just to make sure that val1 and val2 in struct item have some initial values | |
item item = {0, 0}; | |
//spin_lock(&producer_lock); | |
head = buffer->head; | |
/* The spin_unlock() and next spin_lock() provide needed ordering. */ | |
tail = READ_ONCE(buffer->tail); | |
DEBUG_MSG(KERN_INFO "Before push, head = %u , tail = %u\n", head, tail); | |
if (CIRC_SPACE(head, tail, CIRC_BUFF_SIZE) >= 1) | |
{ | |
/* insert one item into the buffer */ | |
item.val1 = val1; | |
item.val2 = val2; | |
memcpy(&buffer[head], &item, sizeof(struct item)); | |
DEBUG_MSG(KERN_INFO "item.val1 = %u , item.val2 = %u\n", item.val1, item.val2); | |
smp_store_release(&buffer->head, (head + 1) & (CIRC_BUFF_SIZE - 1)); | |
DEBUG_MSG(KERN_INFO "After push, head = %u , tail = %u\n", buffer->head, buffer->tail); | |
/* wake_up() will make sure that the head is committed before | |
* waking anyone up */ | |
//wake_up(consumer); | |
//spin_unlock(&producer_lock); | |
return 0; | |
} | |
else | |
{ | |
//spin_unlock(&producer_lock); // still need to unlock even unused | |
return 1; // not enough buffer space | |
} | |
} | |
inline int pop_circ_queue(struct circ_buf * buffer, unsigned int * val1, unsigned int * val2) | |
{ | |
struct item *item; | |
unsigned int head; | |
unsigned int tail; | |
//spinlock_t consumer_lock; | |
//spin_lock(&consumer_lock); | |
/* Read index before reading contents at that index. */ | |
head = smp_load_acquire(&buffer->head); | |
tail = buffer->tail; | |
DEBUG_MSG(KERN_INFO "Before pop, head = %u , tail = %u\n", head, tail); | |
if (CIRC_CNT(head, tail, CIRC_BUFF_SIZE) >= 1) | |
{ | |
/* extract one item from the buffer */ | |
memcpy(&item, &buffer[tail], sizeof(struct item)); | |
val1 = &item->val1; | |
val2 = &item->val2; | |
DEBUG_MSG(KERN_INFO "val1 = %u , val2 = %u\n", *val1, *val2); | |
/* Finish reading descriptor before incrementing tail. */ | |
smp_store_release(&buffer->tail, (tail + 1) & (CIRC_BUFF_SIZE - 1)); | |
DEBUG_MSG(KERN_INFO "After pop, head = %u , tail = %u\n", buffer->head, buffer->tail); | |
//spin_unlock(&consumer_lock); | |
return 0; | |
} | |
else | |
{ | |
//spin_unlock(&consumer_lock); // still need to unlock even unused | |
return 1; // not enough buffer space | |
} | |
} | |
void free_circ_queue(struct circ_buf * q) | |
{ | |
if (q == NULL) | |
return; | |
kfree(q->buf); | |
kfree(q); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment