kfifo简单使用

kfifo简单应用.  从linux内核源码中获取并修改得到.并在应用层使用之. 备忘

kfifo.c

/*
 * A simple kernel FIFO implementation.
 *
 * Copyright (C) 2004 Stelian Pop <stelian@popies.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

//#include <linux/kernel.h>
//#include <linux/module.h>
//#include <linux/slab.h>
//#include <linux/err.h>
//#include <linux/kfifo.h>
//#include <linux/log2.h>

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kfifo.h"


static inline int is_power_of_2(unsigned long n)
{
    return (n != 0 && ((n & (n - 1)) == 0));
}

#define roundup_pow_of_two(size)    1       //????????????????????????????????????????????????

#define MAX_ERRNO   4095
#define unlikely(x) __builtin_expect(!!(x), 0)
#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)

#define BUG()       printf("BUG at %s:%d!\n", __FILE__, __LINE__)
#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while(0)

#define min(x, y) ({                        \
            typeof(x) _min1 = (x);          \
            typeof(y) _min2 = (y);          \
            (void) (&_min1 == &_min2);      \
            _min1 < _min2 ? _min1 : _min2; })


static inline void *ERR_PTR(long error)
{
        return (void *) error;
}

static inline long PTR_ERR(const void *ptr)
{
        return (long) ptr;
}

static inline long IS_ERR(const void *ptr)
{
        return IS_ERR_VALUE((unsigned long)ptr);
}


/**
 * kfifo_init - allocates a new FIFO using a preallocated buffer
 * @buffer: the preallocated buffer to be used.
 * @size: the size of the internal buffer, this have to be a power of 2.
 * @gfp_mask: get_free_pages mask, passed to kmalloc()
 * @lock: the lock to be used to protect the fifo buffer
 *
 * Do NOT pass the kfifo to kfifo_free() after use! Simply free the
 * &struct kfifo with kfree().
 */
struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
             gfp_t gfp_mask, spinlock_t *lock)
{
    struct kfifo *fifo;

    /* size must be a power of 2 */
    BUG_ON(!is_power_of_2(size));

    //fifo = kmalloc(sizeof(struct kfifo), gfp_mask);
    fifo = malloc(sizeof(struct kfifo));
    if (!fifo)
        return ERR_PTR(-ENOMEM);

    fifo->buffer = buffer;
    fifo->size = size;
    fifo->in = fifo->out = 0;
    fifo->lock = lock;

    return fifo;
}
//EXPORT_SYMBOL(kfifo_init);

/**
 * kfifo_alloc - allocates a new FIFO and its internal buffer
 * @size: the size of the internal buffer to be allocated.
 * @gfp_mask: get_free_pages mask, passed to kmalloc()
 * @lock: the lock to be used to protect the fifo buffer
 *
 * The size will be rounded-up to a power of 2.
 */
struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock)
{
    unsigned char *buffer;
    struct kfifo *ret;

    /*
     * round up to the next power of 2, since our 'let the indices
     * wrap' technique works only in this case.
     */
    if (!is_power_of_2(size)) {
        BUG_ON(size > 0x80000000);
#if 1
        size = roundup_pow_of_two(size);
#endif
    }
    //buffer = kmalloc(size, gfp_mask);
    buffer = malloc(size);
    if (!buffer)
        return ERR_PTR(-ENOMEM);

    ret = kfifo_init(buffer, size, gfp_mask, lock);

    if (IS_ERR(ret))
        free(buffer);
        //kfree(buffer);

    return ret;
}
//EXPORT_SYMBOL(kfifo_alloc);

/**
 * kfifo_free - frees the FIFO
 * @fifo: the fifo to be freed.
 */
void kfifo_free(struct kfifo *fifo)
{
    free(fifo->buffer);
    free(fifo);
    //kfree(fifo->buffer);
    //kfree(fifo);
}
//EXPORT_SYMBOL(kfifo_free);

/**
 * __kfifo_put - puts some data into the FIFO, no locking version
 * @fifo: the fifo to be used.
 * @buffer: the data to be added.
 * @len: the length of the data to be added.
 *
 * This function copies at most @len bytes from the @buffer into
 * the FIFO depending on the free space, and returns the number of
 * bytes copied.
 *
 * Note that with only one concurrent reader and one concurrent
 * writer, you don't need extra locking to use these functions.
 */
unsigned int __kfifo_put(struct kfifo *fifo,
            const unsigned char *buffer, unsigned int len)
{
    unsigned int l;

    len = min(len, fifo->size - fifo->in + fifo->out);

    /*
     * Ensure that we sample the fifo->out index -before- we
     * start putting bytes into the kfifo.
     */

    //smp_mb();

    /* first put the data starting from fifo->in to buffer end */
    l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
    memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);

    /* then put the rest (if any) at the beginning of the buffer */
    memcpy(fifo->buffer, buffer + l, len - l);

    /*
     * Ensure that we add the bytes to the kfifo -before-
     * we update the fifo->in index.
     */

    //smp_wmb();

    fifo->in += len;

    return len;
}
//EXPORT_SYMBOL(__kfifo_put);

/**
 * __kfifo_get - gets some data from the FIFO, no locking version
 * @fifo: the fifo to be used.
 * @buffer: where the data must be copied.
 * @len: the size of the destination buffer.
 *
 * This function copies at most @len bytes from the FIFO into the
 * @buffer and returns the number of copied bytes.
 *
 * Note that with only one concurrent reader and one concurrent
 * writer, you don't need extra locking to use these functions.
 */
unsigned int __kfifo_get(struct kfifo *fifo,
             unsigned char *buffer, unsigned int len)
{
    unsigned int l;

    len = min(len, fifo->in - fifo->out);

    /*
     * Ensure that we sample the fifo->in index -before- we
     * start removing bytes from the kfifo.
     */

    //smp_rmb();

    /* first get the data from fifo->out until the end of the buffer */
    l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
    memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);

    /* then get the rest (if any) from the beginning of the buffer */
    memcpy(buffer + l, fifo->buffer, len - l);

    /*
     * Ensure that we remove the bytes from the kfifo -before-
     * we update the fifo->out index.
     */

    //smp_mb();

    fifo->out += len;

    return len;
}
//EXPORT_SYMBOL(__kfifo_get);

kfifo.h

/*
 * A simple kernel FIFO implementation.
 *
 * Copyright (C) 2004 Stelian Pop <stelian@popies.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */
#ifndef _LINUX_KFIFO_H
#define _LINUX_KFIFO_H

//#include <linux/kernel.h>
//#include <linux/spinlock.h>

#ifndef spinlock_t
#define spinlock_t  int
#endif

#ifndef gfp_t 
#define gfp_t   int
#endif


#ifndef spin_lock_init
#define spin_lock_init(x)
#endif

#ifndef spin_lock_irqsave
#define spin_lock_irqsave(x, y)
#endif

#ifndef spin_unlock_irqrestore
#define spin_unlock_irqrestore(x, y)
#endif

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) */
    spinlock_t *lock;    /* protects concurrent modifications */
};

extern struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
                gfp_t gfp_mask, spinlock_t *lock);
extern struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask,
                 spinlock_t *lock);
extern void kfifo_free(struct kfifo *fifo);
extern unsigned int __kfifo_put(struct kfifo *fifo,
                const unsigned char *buffer, unsigned int len);
extern unsigned int __kfifo_get(struct kfifo *fifo,
                unsigned char *buffer, unsigned int len);

/**
 * __kfifo_reset - removes the entire FIFO contents, no locking version
 * @fifo: the fifo to be emptied.
 */
static inline void __kfifo_reset(struct kfifo *fifo)
{
    fifo->in = fifo->out = 0;
}

/**
 * kfifo_reset - removes the entire FIFO contents
 * @fifo: the fifo to be emptied.
 */
static inline void kfifo_reset(struct kfifo *fifo)
{
    unsigned long flags;

    spin_lock_irqsave(fifo->lock, flags);

    __kfifo_reset(fifo);

    spin_unlock_irqrestore(fifo->lock, flags);
}

/**
 * kfifo_put - puts some data into the FIFO
 * @fifo: the fifo to be used.
 * @buffer: the data to be added.
 * @len: the length of the data to be added.
 *
 * This function copies at most @len bytes from the @buffer into
 * the FIFO depending on the free space, and returns the number of
 * bytes copied.
 */
static inline unsigned int kfifo_put(struct kfifo *fifo,
                const unsigned char *buffer, unsigned int len)
{
    unsigned long flags;
    unsigned int ret;

    spin_lock_irqsave(fifo->lock, flags);

    ret = __kfifo_put(fifo, buffer, len);

    spin_unlock_irqrestore(fifo->lock, flags);

    return ret;
}

/**
 * kfifo_get - gets some data from the FIFO
 * @fifo: the fifo to be used.
 * @buffer: where the data must be copied.
 * @len: the size of the destination buffer.
 *
 * This function copies at most @len bytes from the FIFO into the
 * @buffer and returns the number of copied bytes.
 */
static inline unsigned int kfifo_get(struct kfifo *fifo,
                     unsigned char *buffer, unsigned int len)
{
    unsigned long flags;
    unsigned int ret;

    spin_lock_irqsave(fifo->lock, flags);

    ret = __kfifo_get(fifo, buffer, len);

    /*
     * optimization: if the FIFO is empty, set the indices to 0
     * so we don't wrap the next time
     */
    if (fifo->in == fifo->out)
        fifo->in = fifo->out = 0;

    spin_unlock_irqrestore(fifo->lock, flags);

    return ret;
}

/**
 * __kfifo_len - returns the number of bytes available in the FIFO, no locking version
 * @fifo: the fifo to be used.
 */
static inline unsigned int __kfifo_len(struct kfifo *fifo)
{
    return fifo->in - fifo->out;
}

/**
 * kfifo_len - returns the number of bytes available in the FIFO
 * @fifo: the fifo to be used.
 */
static inline unsigned int kfifo_len(struct kfifo *fifo)
{
    unsigned long flags;
    unsigned int ret;

    spin_lock_irqsave(fifo->lock, flags);

    ret = __kfifo_len(fifo);

    spin_unlock_irqrestore(fifo->lock, flags);

    return ret;
}

#endif

 

main.c

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kfifo.h"

struct KfifoNode {
    unsigned int num;
    char *string;
};

char *array[] = {
    "abcdefg",
    "gfedcba",
    "aaaaa",
    "bbbb",
    "ccc",
    "dd",
    "e",
    "12345",
    "1234",
    "123",
    "12",
    "1",
    "1111",
};

#define TAB_SIZE(array) (sizeof(array)/sizeof(array[0]))

static struct kfifo *pkfifoSpace;
static spinlock_t fifoLock; 

static void kfifo_check(char* str, int line, struct kfifo* pkfifo) 
{
    if(pkfifo != NULL) {
        printf("[%s-%d]: pkfifo->size = %-4d pkfifo->in = %-4d pkfifo->out = %-4d ", str, line, pkfifo->size, pkfifo->in, pkfifo->out);
    }
}


#ifndef GFP_KERNEL
#define GFP_KERNEL  1
#endif

int main(int argc, char* argv[])
{
    int i; 
    struct KfifoNode *pstNode;

    pkfifoSpace = kfifo_alloc((sizeof(struct KfifoNode) << 4), GFP_KERNEL, &fifoLock);
    if (pkfifoSpace == NULL) {
        printf("kfifo_alloc failed !\n");
        return -EFAULT;
    }
    spin_lock_init(&fifoLock); //Initial fifo spinlock 
    //pstNode = kzalloc(sizeof(struct KfifoNode), GFP_KERNEL);
    pstNode = malloc(sizeof(struct KfifoNode));
    printf("******insert*********************************************************************\n");
    kfifo_check((char *)__func__, __LINE__, pkfifoSpace);
    printf("\n");
    for(i = 0; i < TAB_SIZE(array); i++) {
        pstNode->num = i;
        pstNode->string = (char *)array[i];
        kfifo_put(pkfifoSpace, (unsigned char *)pstNode, sizeof(struct KfifoNode)); //将数据写入缓冲区
        kfifo_check((char *)__func__, __LINE__, pkfifoSpace);
        printf("Num: %-3d, Message: %s\n", pstNode->num, pstNode->string);
    }
    if(!kfifo_len(pkfifoSpace)) {
        printf("[%s-%d]: kfifo_len return 0, test failed !!! \n", __func__, __LINE__);
        kfifo_reset(pkfifoSpace);
        kfifo_free(pkfifoSpace);

        return -1;
    }

    printf("------get-and-display------------------------------------------------------------\n");
    //for(i = 0; i < TAB_SIZE(array); i++) {
    while(kfifo_len(pkfifoSpace)) {
        kfifo_get(pkfifoSpace, (unsigned char *)pstNode, sizeof(struct KfifoNode));
        kfifo_check((char *)__func__, __LINE__, pkfifoSpace);
        printf("Num is: %-3d, fifoMessage is: %s\n", pstNode->num, pstNode->string);
    }
    printf("------get-all-over----------------------------------------------------------------\n");
    kfifo_check((char *)__func__, __LINE__, pkfifoSpace);
    printf("\n--------------------------------------------------------------------------------\n");
    free(pstNode);
    kfifo_reset(pkfifoSpace);
    kfifo_free(pkfifoSpace);

    return  0;
}

 

编译链接运行, 输出如下:

 

posted @ 2016-02-06 00:47  zhanglong71  阅读(3676)  评论(0编辑  收藏  举报