按照linux内核对kfifo的实现,修改成用户空间的kfifo,kfifo是一个循环存储队列,队列是一个大块内存,通过in和out指针管理进和出队列。比较适合大小固定的数据存储。这里的实现没有加锁机制!内核kfifo原理,参考http://blog.csdn.net/linyt/article/details/5764312
kfifo头文件。
#ifndef _Linux_KFIFO_H
#define _Linux_KFIFO_H
#define __u32 unsigned long
#define __u64 unsigned long long
#define min(x,y) ((x) < (y) ? (x) : (y) )
#define max(x,y) ((x) > (y) ? (x) : (y) )
/*
static inline int fls(int x)
{
int r;
__asm__("bsrl %1,%0nt"
"jnz 1fnt"
"movl $-1,%0n"
"1:" : "=r" (r) : "rm" (x));
return r+1;
}
*/
static inline int fls(int x)
{
int r = 32;
if (!x)
return 0;
if (!(x & 0xffff0000u)) {
x <<= 16;
r -= 16;
}
if (!(x & 0xff000000u)) {
x <<= 8;
r -= 8;
}
if (!(x & 0xf0000000u)) {
x <<= 4;
r -= 4;
}
if (!(x & 0xc0000000u)) {
x <<= 2;
r -= 2;
}
if (!(x & 0x80000000u)) {
x <<= 1;
r -= 1;
}
return r;
}
static inline int fls64(__u64 x)
{
__u32 h = x >> 32;
if (h)
return fls(h) + 32;
return fls(x);
}
static inline unsigned fls_long(unsigned long l)
{
if (sizeof(l) == 4)
return fls(l);
return fls64(l);
}
static inline unsigned long roundup_pow_of_two(unsigned long x)
{
return 1UL << fls_long(x - 1);
}
struct kfifo {
unsigned char *buffer; /* the buffer holding the data */
unsigned int size; /* the size of the allocated buffer */
unsigned int in; /* data is added at offset (in % size) */
unsigned int out; /* data is extracted from off. (out % size) */
};
struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size);
struct kfifo *kfifo_alloc(unsigned int size);
void kfifo_free(struct kfifo *fifo);
unsigned int __kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len);
unsigned int __kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len);
static inline void __kfifo_reset(struct kfifo *fifo)
{
fifo->in = fifo->out = 0;
}
static inline void kfifo_reset(struct kfifo *fifo)
{
__kfifo_reset(fifo);
}
static inline unsigned int kfifo_put(struct kfifo *fifo,
unsigned char *buffer, unsigned int len)
{
unsigned int ret;
ret = __kfifo_put(fifo, buffer, len);
return ret;
}
static inline unsigned int kfifo_get(struct kfifo *fifo,
unsigned char *buffer, unsigned int len)
{
unsigned int ret;
ret = __kfifo_get(fifo, buffer, len);
if (fifo->in == fifo->out)
fifo->in = fifo->out = 0;
return ret;
}
static inline unsigned int __kfifo_len(struct kfifo *fifo)
{
return fifo->in - fifo->out;
}
static inline unsigned int kfifo_len(struct kfifo *fifo)
{
unsigned int ret;
ret = __kfifo_len(fifo);
return ret;
}
#endif
kfifo实现
#include "kfifo.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size)
{
struct kfifo *fifo;
fifo = (struct kfifo *)malloc(sizeof(struct kfifo));
if (!fifo)
return NULL;
fifo->buffer = buffer;
fifo->size = size;
fifo->in = fifo->out = 0;
return fifo;
}
struct kfifo *kfifo_alloc(unsigned int size)
{
unsigned char *buffer;
struct kfifo *ret;
if (size & (size - 1)) {
fprintf(stderr,"size > 0x80000000n");
size = roundup_pow_of_two(size);
}
buffer = (unsigned char *)malloc(size);
if (!buffer)
return NULL;
ret = kfifo_init(buffer, size);
if ((unsigned long)ret <= 0)
{
free(buffer);
}
return ret;
}
void kfifo_free(struct kfifo *fifo)
{
free(fifo->buffer);
free(fifo);
}
unsigned int __kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len)
{
unsigned int l;
len = min(len, fifo->size - fifo->in + fifo->out);
l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
memcpy(fifo->buffer, buffer + l, len - l);
fifo->in += len;
return len;
}
unsigned int __kfifo_get(struct kfifo *fifo,
unsigned char *buffer, unsigned int len)
{
unsigned int l;
len = min(len, fifo->in - fifo->out);
l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
fifo->out += len;
return len;
}
kfifo测试(来自网友的代码)
#define FIFO_LENGTH 4096
#include <stdio.h>
#include <pthread.h>
#include <strings.h>
#include <string.h>
#include "kfifo.h"
struct ll_param
{
struct kfifo * fifo;
int msg_len;
};
static struct ll_param fifo;
void thread_reader(void * param)
{
int read_len=0;
unsigned int counter=0;
unsigned char buffer[FIFO_LENGTH];
struct ll_param * p=(struct ll_param *)param;
printf("nnn = %d\n", roundup_pow_of_two(5));
for(;;)
{
bzero(buffer, FIFO_LENGTH);
read_len=kfifo_get(p->fifo, buffer, 25);
if(read_len !=0 )
{
printf("Read len:%d, buffer is :< %s >n\n", read_len, buffer);
}
else
{
counter++;
}
if(counter > 20)
{
break;
}
usleep(50000);
}
}
void thread_writer(void * param)
{
unsigned int write_len = 0;
unsigned int counter = 0;
unsigned char buffer[32];
struct ll_param * p = (struct ll_param *)param;
for(counter = 0; counter < 100; counter++)
{
bzero(buffer,32);
sprintf((char *)buffer, "This is %d message.n", counter);
write_len=kfifo_put(p->fifo, buffer, 25); //strlen((char *)buffer)
usleep(100);
}
}
int main(void)
{
pthread_t pidr;
pthread_t pidw;
fifo.msg_len = 10;
fifo.fifo = kfifo_alloc(FIFO_LENGTH);
pthread_create(&pidw, NULL, (void *)thread_writer, &fifo);
pthread_create(&pidr, NULL, (void *)thread_reader, &fifo);
pthread_join(pidr, NULL);
pthread_join(pidw, NULL);
kfifo_free(fifo.fifo);
printf("nGoodbye!n\n");
return 0;
}
Makefile
CFLAGS = -O2 -Wall
INCLUDE = -I /
CC = gcc
test:test.o kfifo.o
${CC} ${CFLAGS} test.o kfifo.o -o $@ ${INCLUDE} -pthread
test.o:
$(CC) -c test.c ${INCLUDE} -pthread
kfifo.o:
$(CC) -c kfifo.c ${INCLUDE}
clean:
rm -rf *.o test