kfifo简单应用. 从linux内核源码中获取并修改得到.并在应用层使用之. 备忘
kfifo.c
/* * A simple kernel FIFO implementation. * * Copyright (C) 2004 Stelian Pop <[email protected]> * * 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 <[email protected]> * * 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; }
编译链接运行, 输出如下: