DPDK_RING 剝離(sc)
dpdk中的ring結構的原理在官方的doc中有。詳細的介紹了單線程和多線程下的ring的結構的實現。其中線程安全的ring的出入隊中沒有用到鎖,這個結構是比較巧妙的。
此外,和一般的ring設計相比,dpdk的ring中減少了比較的次數和減法的次數。考慮了很多性能方面的東西。
目前就剝離了單線程版的。
代碼如下:
- daq_ring.h
#ifndef DAQ_RING_H
#define DAQ_RING_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <pthread.h>
typedef struct _daq_ring{
// pthread_mutex_t mutex;
int size;
int mask;
int cons_head;
int cons_tail;
int prod_head;
int prod_tail;
void * ring[0];
};
typedef struct _daq_ring daq_ring;
//create a ring which can contain size's objects.
daq_ring * daq_ring_create(int num);
//fre a ring.
int daq_ring_free(daq_ring * r);
//see whether a ring is empty.
int daq_ring_isEmpty(daq_ring * r);
//see whether a ring is full.
int daq_ring_isFull(daq_ring * r);
//see the number of objects in ring now.
int daq_ring_count(daq_ring * r);
//see the size of a ring.
int daq_ring_getSize(daq_ring *r);
//see the number of objects can be inputed into the ring now.
int daq_ring_freeCount(daq_ring * r);
//enqueue objects into a ring.
int daq_ring_enqueue(daq_ring * r, void * const *obj_table, int num,int mc);
//dequeue objects from a ring.
int daq_ring_dequeue(daq_ring * r, void **obj_table, int num,int mc);
#endif
//end of daq_ring.h
-daq_ring.c
#include "daq_ring.h"
/*typedef struct _daq_ring{
pthread_mutex_t mutex;
unsigned int size;
void * head;
void * tail;
void * memhead;
}daq_ring;*/
daq_ring * daq_ring_create(int num){
daq_ring * r = NULL;
if(num <=0)return NULL;
r = (daq_ring *)malloc(sizeof(daq_ring) + num*sizeof(void*));
if(r == NULL){
return NULL;
}
r->size = num;
r->mask = num-1;
r->prod_head = r->prod_tail = r->cons_head = r->cons_tail = 0;
// pthread_mutex_init(&r->mutex,NULL);
return r;
}
//fre a ring.
int daq_ring_free(daq_ring * r){
free(r);
}
//see whether a ring is empty.
int daq_ring_isEmpty(daq_ring * r){
return r->cons_tail == r->prod_tail;
}
//see whether a ring is full.
int daq_ring_isFull(daq_ring * r){
return (((r->cons_tail - r->prod_tail -1)&r->mask)==0);
}
//see the number of objects in ring now.
int daq_ring_count(daq_ring * r){
return ((r->prod_tail - r->cons_tail)&r->mask);
}
//see the size of a ring.
int daq_ring_getSize(daq_ring *r){
return r->size;
}
//see the number of objects can be inputed into the ring now.
int daq_ring_freeCount(daq_ring * r){
return ((r->cons_tail - r->prod_tail - 1) & r->mask);
}
//enqueue objects into a ring.
int daq_ring_enqueue(daq_ring * r, void * const *obj_table, int num,int mc){
int prod_head = r->prod_head;
int cons_tail = r->cons_tail;
int prod_next = prod_head +1;
int mask = r->mask;
int i ;
int free = mask + cons_tail -prod_head;
if(num >free){
if(free == 0)return 0;
num = free;
}
prod_next = prod_head +num;
r->prod_head = prod_next;
{
const int size = r->size;
int idx = prod_head & mask;
if(idx + num < size){
for (i = 0; i < (num & ((~(unsigned)0x3))); i+=4, idx+=4) {
r->ring[idx] = obj_table[i];
r->ring[idx+1] = obj_table[i+1];
r->ring[idx+2] = obj_table[i+2];
r->ring[idx+3] = obj_table[i+3];
}
switch (num & 0x3) {
case 3: r->ring[idx++] = obj_table[i++];
case 2: r->ring[idx++] = obj_table[i++];
case 1: r->ring[idx++] = obj_table[i++];
}
}else{
for (i =0;idx<size;++i,++idx)
r->ring[idx] = obj_table[i];
for(idx = 0;i<num;++i,++idx)
r->ring[idx] = obj_table[i];
}
}
r->prod_tail = prod_next;
return num;
}
//dequeue objects from a ring.
int daq_ring_dequeue(daq_ring * r, void **obj_table, int num,int mc){
int cons_head,prod_tail;
int cons_next,entries;
int i;
int mask = r->mask;
cons_head = r->cons_head;
prod_tail = r->prod_tail;
entries = prod_tail - cons_head;
if(num > entries){
if(entries == 0)return 0;
num = entries;
}
cons_next = cons_head + num;
r -> cons_head = cons_next;
{
int idx = cons_head & mask;
int size = r-> size;
if (idx + num < size) {
for (i = 0; i < (num & (~(unsigned)0x3)); i+=4, idx+=4) {
obj_table[i] = r->ring[idx];
obj_table[i+1] = r->ring[idx+1];
obj_table[i+2] = r->ring[idx+2];
obj_table[i+3] = r->ring[idx+3];
}
switch (num & 0x3) {
case 3: obj_table[i++] = r->ring[idx++];
case 2: obj_table[i++] = r->ring[idx++];
case 1: obj_table[i++] = r->ring[idx++];
}
} else {
for (i = 0; idx < size; i++, idx++)
obj_table[i] = r->ring[idx];
for (idx = 0; i < num; i++, idx++)
obj_table[i] = r->ring[idx];
}
}
r->cons_tail = cons_next;
return num;
}
void daq_ring_stat(daq_ring * r){
printf("***********************************************\n");
printf("Daq_ring's size is %d\n",daq_ring_getSize(r));
printf("Daq_ring's objects now is %d.\n",daq_ring_count(r));
printf("Daq_ring's free space is %d\n",daq_ring_freeCount(r));
printf("Daq_ring is %s now.\n",daq_ring_isEmpty(r)?"empty":"not empty");
printf("Daq_ring is %s now.\n",daq_ring_isFull(r)?"full":"not full");
printf("***********************************************\n");
}
void print_ptr(daq_ring *r){
printf("r->cons:%p %p\n", r->cons_head, r->cons_tail);
printf("r->prod:%p %p\n",r->prod_head,r->prod_tail);
printf("r->ring[0]:%p\n",&r->ring[0]);
}
int test1(){
char * str[] = {
"t1","t2","t3","t4","t5","t6","t7","t8","t9","t10","t11","t12","t13"
};
void * ctx[12];
int i;
for(i =0;i<10;++i)
printf("%s\n",str[i]);
daq_ring * r = daq_ring_create(9);
daq_ring_stat(r);
print_ptr(r);
daq_ring_enqueue(r,str,8,1);
daq_ring_stat(r);
print_ptr(r);
daq_ring_dequeue(r,ctx,8,1);
for(int i =0;i<8;++i)
printf("%s\n",(char *)ctx[i]);
daq_ring_stat(r);
print_ptr(r);
daq_ring_enqueue(r,str,8,1);
daq_ring_stat(r);
print_ptr(r);
daq_ring_dequeue(r,ctx,8,1);
for(i =0;i<10;++i)
printf("%s\n",(char *)ctx[i]);
return 0;
}
int test2(){
int i;
char * str[] = {
"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10", "t11", "t12", "t13", "t14", "t15", "t16", "t17"
};
void * ctx[18];
daq_ring * r = daq_ring_create(16);
daq_ring_enqueue(r,str,14,1);
daq_ring_stat(r);
print_ptr(r);
daq_ring_dequeue(r,ctx,4,1);
for(i =0;i<4;++i)
printf("%s\n",(char *)ctx[i]);
daq_ring_stat(r);
print_ptr(r);
daq_ring_enqueue(r,&str[5],5,1);
daq_ring_stat(r);
print_ptr(r);
daq_ring_dequeue(r,ctx,15,1);
for(i =0;i<15;++i)
printf("%s\n",(char *)ctx[i]);
daq_ring_stat(r);
print_ptr(r);
}
int main(){
test2();
return 0;
}