首 页文章中心

Linux学习网

您的位置Linux学习网 > Linux综合 > 文章内容

内核循环缓冲区数据结构在用户态的使用

作者:佚名  来源:不详  发布时间:2007-12-21 16:37:00
忘记了之前是有个什么事情一时想起好像需要用个cycler buffer,手头一时又没有,懒得自己实现。就向同学要了个。后来好像也没有用到,倒是一直记得好像老早以前看到ldd上提到双向链表的时候有提到个kfifo,只是一直没有用到这个,所以一直没看。倒是无聊的时候想起过printk是否用的就是这个数据结构。

  昨天临下班的时候想到kfifo这个东东,今天就抽点时间看看。

  刚开始是把双向链表拎出来编一下看看,结果让我大吃一惊。居然没有list.h,看来fc从4以后开始倒退倒是有点佐证了。好在机器上还有linux-libc-headers的包,解包覆盖一下应该就ok了吧。不要高兴,还是不行。打开list.h一看,居然里面只包含了另一个文件,只扔给我一个#error,超ft。没办法,只好上内核源码里去拷了,于是把include/*都copy到了/usr/include。再编,靠,居然还是不过。nnd,再看list.h,居然还有个宏定义才能使用里面的inline函数,要不就extern reference了,郁闷。只好在源文件中加了:4KVLinux联盟

#ifdef CONFIG_DEBUG_LIST4KVLinux联盟
#undef CONFIG_DEBUG_LIST4KVLinux联盟
#endif

  然后再包含上linux/autoconf.h,这才一切ok。汗......

  有了上面的折腾,在开始搞kfifo之前就先看看kfifo.h和他的实现吧。结果一看kfifo.h和kfifo.c,头文件里面extern了好几个kfifo.c里面实现的东东不说,还用了spinlock,看来直接用是没有指望了,还是dirty hack到user space算了。于是只能把文件copy出来dirty hack了。吭哧吭哧搞了一气,搞了个可用的东东开列如下:4KVLinux联盟
  kfifo.c:4KVLinux联盟

#include "kfifo.h"4KVLinux联盟
#include 4KVLinux联盟
#include 4KVLinux联盟
#include 4KVLinux联盟
#include 4KVLinux联盟
struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size)4KVLinux联盟
{4KVLinux联盟
    struct kfifo *fifo;4KVLinux联盟
4KVLinux联盟
    fifo = malloc(sizeof(struct kfifo));4KVLinux联盟
    if (!fifo)4KVLinux联盟
        return (void*)(-ENOMEM);4KVLinux联盟
4KVLinux联盟
    fifo->buffer = buffer;4KVLinux联盟
    fifo->size = size;4KVLinux联盟
    fifo->in = fifo->out = 0;4KVLinux联盟
4KVLinux联盟
    return fifo;4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
struct kfifo *kfifo_alloc(unsigned int size)4KVLinux联盟
{4KVLinux联盟
    unsigned char *buffer;4KVLinux联盟
    struct kfifo *ret;4KVLinux联盟
    if (size & (size - 1)) {4KVLinux联盟
        fprintf(stderr,"size > 0x80000000\n");4KVLinux联盟
        size = roundup_pow_of_two(size);4KVLinux联盟
    }4KVLinux联盟
4KVLinux联盟
    buffer = malloc(size);4KVLinux联盟
    if (!buffer)4KVLinux联盟
        return (void *)(-ENOMEM);4KVLinux联盟
4KVLinux联盟
    ret = kfifo_init(buffer, size);4KVLinux联盟
4KVLinux联盟
    if ((unsigned long)ret<=0)4KVLinux联盟
    {4KVLinux联盟
        free(buffer);4KVLinux联盟
    }4KVLinux联盟
4KVLinux联盟
    return ret;4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
void kfifo_free(struct kfifo *fifo)4KVLinux联盟
{4KVLinux联盟
    free(fifo->buffer);4KVLinux联盟
    free(fifo);4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
unsigned int __kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len)4KVLinux联盟
{4KVLinux联盟
    unsigned int l;4KVLinux联盟
4KVLinux联盟
    len = min(len, fifo->size - fifo->in + fifo->out);4KVLinux联盟
4KVLinux联盟
        l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));4KVLinux联盟
    memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);4KVLinux联盟
    memcpy(fifo->buffer, buffer + l, len - l);4KVLinux联盟
4KVLinux联盟
    fifo->in += len;4KVLinux联盟
4KVLinux联盟
    return len;4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
unsigned int __kfifo_get(struct kfifo *fifo,4KVLinux联盟
             unsigned char *buffer, unsigned int len)4KVLinux联盟
{4KVLinux联盟
    unsigned int l;4KVLinux联盟
4KVLinux联盟
    len = min(len, fifo->in - fifo->out);4KVLinux联盟
4KVLinux联盟
    l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));4KVLinux联盟
    memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);4KVLinux联盟
4KVLinux联盟
    fifo->out += len;4KVLinux联盟
    return len;4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
  kfifo.h:4KVLinux联盟
#ifndef _LINUX_KFIFO_H4KVLinux联盟
#define _LINUX_KFIFO_H4KVLinux联盟
4KVLinux联盟
#define __u32 unsigned long4KVLinux联盟
#define __u64 unsigned long long4KVLinux联盟
4KVLinux联盟
#define min(x,y) ({ \4KVLinux联盟
        typeof(x) _x = (x);     \4KVLinux联盟
        typeof(y) _y = (y);     \4KVLinux联盟
        (void) (&_x == &_y);            \4KVLinux联盟
        _x < _y ? _x : _y; })4KVLinux联盟
4KVLinux联盟
#define max(x,y) ({ \4KVLinux联盟
        typeof(x) _x = (x);     \4KVLinux联盟
        typeof(y) _y = (y);     \4KVLinux联盟
        (void) (&_x == &_y);            \4KVLinux联盟
        _x > _y ? _x : _y; })4KVLinux联盟
4KVLinux联盟
static inline int fls(int x)4KVLinux联盟
{4KVLinux联盟
    int r;4KVLinux联盟
4KVLinux联盟
    __asm__("bsrl %1,%0\n\t"4KVLinux联盟
            "jnz 1f\n\t"4KVLinux联盟
            "movl $-1,%0\n"4KVLinux联盟
            "1:" : "=r" (r) : "rm" (x));4KVLinux联盟
    return r+1;4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
static inline int fls64(__u64 x)4KVLinux联盟
{4KVLinux联盟
    __u32 h = x >> 32;4KVLinux联盟
    if (h)4KVLinux联盟
        return fls(h) + 32;4KVLinux联盟
    return fls(x);4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
static inline unsigned fls_long(unsigned long l)4KVLinux联盟
{4KVLinux联盟
    if (sizeof(l) == 4)4KVLinux联盟
        return fls(l);4KVLinux联盟
    return fls64(l);4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
static inline unsigned long roundup_pow_of_two(unsigned long x)4KVLinux联盟
{4KVLinux联盟
    return 1UL << fls_long(x - 1);4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
struct kfifo {4KVLinux联盟
    unsigned char *buffer;    /* the buffer holding the data */4KVLinux联盟
    unsigned int size;    /* the size of the allocated buffer */4KVLinux联盟
    unsigned int in;    /* data is added at offset (in % size) */4KVLinux联盟
    unsigned int out;    /* data is extracted from off. (out % size) */4KVLinux联盟
};4KVLinux联盟
4KVLinux联盟
struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size);4KVLinux联盟
struct kfifo *kfifo_alloc(unsigned int size);4KVLinux联盟
void kfifo_free(struct kfifo *fifo);4KVLinux联盟
unsigned int __kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len);4KVLinux联盟
unsigned int __kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len);4KVLinux联盟
4KVLinux联盟
static inline void __kfifo_reset(struct kfifo *fifo)4KVLinux联盟
{4KVLinux联盟
    fifo->in = fifo->out = 0;4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
static inline void kfifo_reset(struct kfifo *fifo)4KVLinux联盟
{4KVLinux联盟
4KVLinux联盟
    __kfifo_reset(fifo);4KVLinux联盟
4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
static inline unsigned int kfifo_put(struct kfifo *fifo,4KVLinux联盟
                     unsigned char *buffer, unsigned int len)4KVLinux联盟
{4KVLinux联盟
    unsigned int ret;4KVLinux联盟
4KVLinux联盟
    ret = __kfifo_put(fifo, buffer, len);4KVLinux联盟
4KVLinux联盟
    return ret;4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
static inline unsigned int kfifo_get(struct kfifo *fifo,4KVLinux联盟
                     unsigned char *buffer, unsigned int len)4KVLinux联盟
{4KVLinux联盟
    unsigned int ret;4KVLinux联盟
4KVLinux联盟
    ret = __kfifo_get(fifo, buffer, len);4KVLinux联盟
4KVLinux联盟
    if (fifo->in == fifo->out)4KVLinux联盟
        fifo->in = fifo->out = 0;4KVLinux联盟
4KVLinux联盟
4KVLinux联盟
    return ret;4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
static inline unsigned int __kfifo_len(struct kfifo *fifo)4KVLinux联盟
{4KVLinux联盟
    return fifo->in - fifo->out;4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
static inline unsigned int kfifo_len(struct kfifo *fifo)4KVLinux联盟
{4KVLinux联盟
    unsigned int ret;4KVLinux联盟
4KVLinux联盟
    ret = __kfifo_len(fifo);4KVLinux联盟
4KVLinux联盟
    return ret;4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
#endif

   4KVLinux联盟
  用起来还是不错的,初步测试了一下效果还行,在去掉了spinlock的保护之后还揣测了一段时间是不是把spinlock改成sem用来sync,不过看到代码的实现又觉得这个spinlock不是对fifo的index进行保护的,也就是说这个实现是免锁的。在kernel中的代码也不过是在smp的情况下加了mb而已。

  贴一下测试的代码如下:

#define FIFO_LENGTH 40964KVLinux联盟
4KVLinux联盟
struct ll_param4KVLinux联盟
{4KVLinux联盟
    struct kfifo * fifo;4KVLinux联盟
    int msg_len;4KVLinux联盟
};4KVLinux联盟
4KVLinux联盟
static struct ll_param fifo;4KVLinux联盟
4KVLinux联盟
void thread_reader(void * param)4KVLinux联盟
{4KVLinux联盟
    int read_len=0;4KVLinux联盟
    unsigned int counter=0;4KVLinux联盟
    unsigned char buffer[FIFO_LENGTH]={0};4KVLinux联盟
    struct ll_param * p=(struct ll_param *)param;4KVLinux联盟
    4KVLinux联盟
    for(;;)4KVLinux联盟
    {4KVLinux联盟
        bzero(buffer,FIFO_LENGTH);4KVLinux联盟
        read_len=kfifo_get(p->fifo,buffer,FIFO_LENGTH);4KVLinux联盟
        if(read_len!=0)4KVLinux联盟
        {4KVLinux联盟
            printf("Read len:%d,buffer is:%s\n",read_len,buffer);4KVLinux联盟
        }4KVLinux联盟
        else4KVLinux联盟
        {4KVLinux联盟
            counter++;4KVLinux联盟
        }4KVLinux联盟
        if(counter>20)4KVLinux联盟
        {4KVLinux联盟
            break;4KVLinux联盟
        }4KVLinux联盟
        usleep(50000);4KVLinux联盟
    }4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
void thread_writer(void * param)4KVLinux联盟
{4KVLinux联盟
    unsigned int write_len=0;4KVLinux联盟
    unsigned int counter=0;4KVLinux联盟
    unsigned char buffer[32]={0};4KVLinux联盟
    struct ll_param * p=(struct ll_param *)param;4KVLinux联盟
    4KVLinux联盟
    for(counter=0;counter<1000;counter++)4KVLinux联盟
    {4KVLinux联盟
        bzero(buffer,32);4KVLinux联盟
        sprintf((char *)buffer,"This is %d message.\n",counter);4KVLinux联盟
        write_len=kfifo_put(p->fifo,buffer,strlen((char *)buffer));4KVLinux联盟
        usleep(100);4KVLinux联盟
    }4KVLinux联盟
}4KVLinux联盟
4KVLinux联盟
4KVLinux联盟
int main(void)4KVLinux联盟
{4KVLinux联盟
    pthread_t pidr;4KVLinux联盟
    pthread_t pidw;4KVLinux联盟
4KVLinux联盟
    fifo.msg_len=10;4KVLinux联盟
    fifo.fifo=kfifo_alloc(FIFO_LENGTH);4KVLinux联盟
4KVLinux联盟
    pthread_create(&pidw,NULL,(void *)thread_writer,&fifo);4KVLinux联盟
    pthread_create(&pidr,NULL,(void *)thread_reader,&fifo);4KVLinux联盟
4KVLinux联盟
    pthread_join(pidr,NULL);4KVLinux联盟
    pthread_join(pidw,NULL);4KVLinux联盟
4KVLinux联盟
    kfifo_free(fifo.fifo);4KVLinux联盟
    printf("\nGoodbye!\n");4KVLinux联盟
    return 0;4KVLinux联盟
}4KVLinux联盟

4KVLinux联盟
  要说明的是,初步测了一下,似乎reader中用来get的buffer大小对受writer和reader之间不一致的速率的影响较大。比如如果reader里面定义的buffer长度设置为小于fifo长度,在writer和reader个子usleep不同时间时表现会不同。以后再慢慢找吧(boss刚刚来电话又要搞个恶心的任务。所以心情大坏)。

  先这样。

收藏本页到: 365Key | del.icio.us | | 添加到雅虎收藏+
  • 网站帮助 - 广告合作 - 网站地图