/* * A generic kernel FIFO implementation * * Copyright (C) 2009/2010 Stefani Seibold * * 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 __GE_KFIFO_H__ #define __GE_KFIFO_H__ /** * 仿照linux内核中的kfifo实现 */ #ifndef GE_MEMORY_BARRIR #define GE_MEMORY_BARRIR() __sync_synchronize() #endif #ifndef GE_ARRAY_SIZE #define GE_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif struct __ge_kfifo { unsigned int in; unsigned int out; unsigned int mask; unsigned int esize; void *data; }; #define __STRUCT_GE_KFIFO(type, size) \ { \ struct __ge_kfifo kfifo; \ type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \ } /** * DECLARE_KFIFO - macro to declare a fifo object * @fifo: name of the declared fifo * @type: type of the fifo elements * @size: the number of elements in the fifo, this must be a power of 2 */ #define DECLARE_GE_KFIFO(fifo, type, size, tname) struct tname __STRUCT_GE_KFIFO(type, size) fifo #define INIT_GE_KFIFO(fifo) do { \ struct __ge_kfifo *__kfifo = &((fifo)->kfifo); \ __kfifo->in = 0; \ __kfifo->out = 0; \ __kfifo->mask = GE_ARRAY_SIZE((fifo)->buf) - 1; \ __kfifo->esize = sizeof(*((fifo)->buf)); \ __kfifo->data = (fifo)->buf; \ } while (0) /** * DEFINE_KFIFO - macro to define and initialize a fifo * @fifo: name of the declared fifo datatype * @type: type of the fifo elements * @size: the number of elements in the fifo, this must be a power of 2 * * Note: the macro can be used for global and local fifo data type variables. */ #define DEFINE_GE_KFIFO(fifo, type, size, tname) \ DECLARE_GE_KFIFO(fifo, type, size, tname) = \ (struct tname) { { \ .in = 0, \ .out = 0, \ .mask = GE_ARRAY_SIZE((fifo).buf) - 1, \ .esize = sizeof(*(fifo).buf), \ .data = (fifo).buf, \ }, { 0 } } /** * kfifo_size - returns the size of the fifo in elements * @fifo: address of the fifo to be used */ #define ge_kfifo_size(fifo) \ ((fifo)->kfifo.mask + 1) /** * kfifo_len - returns the number of used elements in the fifo * @fifo: address of the fifo to be used */ #define ge_kfifo_len(fifo) \ ((fifo)->kfifo.in - (fifo)->kfifo.out) /** * kfifo_is_empty - returns true if the fifo is empty * @fifo: address of the fifo to be used */ #define ge_kfifo_is_empty(fifo) \ ((fifo)->kfifo.in == (fifo)->kfifo.out) /** * kfifo_is_full - returns true if the fifo is full * @fifo: address of the fifo to be used */ #define ge_kfifo_is_full(fifo) (ge_kfifo_len(fifo) > (fifo)->kfifo.mask) /** * kfifo_put - put data into the fifo * @fifo: address of the fifo to be used * @val: the data to be added * * This macro copies the given value into the fifo. * It returns 0 if the fifo was full. Otherwise it returns the number * processed elements. * * Note that with only one concurrent reader and one concurrent * writer, you don't need extra locking to use these macro. */ #define ge_kfifo_put(fifo, val) do { \ unsigned int __ret; \ struct __ge_kfifo *__kfifo = &((fifo)->kfifo); \ __ret = !ge_kfifo_is_full(fifo); \ if (__ret) { \ ((fifo)->buf)[__kfifo->in & __kfifo->mask] = val; \ /*smp_wmb();*/ \ GE_MEMORY_BARRIR(); \ __kfifo->in++; \ } \ /*__ret;*/ \ } while(0) /** * kfifo_get - get data from the fifo * @fifo: address of the fifo to be used * @val: address where to store the data * * This macro reads the data from the fifo. * It returns 0 if the fifo was empty. Otherwise it returns the number * processed elements. * * Note that with only one concurrent reader and one concurrent * writer, you don't need extra locking to use these macro. */ #define ge_kfifo_get(fifo, val) do { \ unsigned int __ret; \ struct __ge_kfifo *__kfifo = &((fifo)->kfifo); \ __ret = !ge_kfifo_is_empty(fifo); \ if (__ret) { \ *val = ((fifo)->buf)[__kfifo->out & __kfifo->mask]; \ /*smp_wmb();*/ \ GE_MEMORY_BARRIR(); \ __kfifo->out++; \ } \ /*__ret;*/ \ } while(0) /** * kfifo_peek - get data from the fifo without removing * @fifo: address of the fifo to be used * @val: address where to store the data * * This reads the data from the fifo without removing it from the fifo. * It returns 0 if the fifo was empty. Otherwise it returns the number * processed elements. * * Note that with only one concurrent reader and one concurrent * writer, you don't need extra locking to use these macro. */ #define ge_kfifo_peek(fifo, val) do { \ unsigned int __ret; \ struct __ge_kfifo *__kfifo = &((fifo)->kfifo); \ __ret = !ge_kfifo_is_empty(fifo); \ if (__ret) { \ *val = ((fifo)->buf)[__kfifo->out & __kfifo->mask]; \ /*smp_wmb();*/ \ GE_MEMORY_BARRIR(); \ } \ /*__ret;*/ \ } while(0) /** * kfifo_in - put data into the fifo * @fifo: address of the fifo to be used * @buf: the data to be added * @n: number of elements to be added * * This macro copies the given buffer into the fifo and returns the * number of copied elements. * * Note that with only one concurrent reader and one concurrent * writer, you don't need extra locking to use these macro. */ /* #define kfifo_in(fifo, buf, n) \ ({ \ typeof((fifo) + 1) __tmp = (fifo); \ typeof(__tmp->ptr_const) __buf = (buf); \ unsigned long __n = (n); \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ (__recsize) ?\ __kfifo_in_r(__kfifo, __buf, __n, __recsize) : \ __kfifo_in(__kfifo, __buf, __n); \ }) */ /** * kfifo_out - get data from the fifo * @fifo: address of the fifo to be used * @buf: pointer to the storage buffer * @n: max. number of elements to get * * This macro gets some data from the fifo and returns the numbers of elements * copied. * * Note that with only one concurrent reader and one concurrent * writer, you don't need extra locking to use these macro. */ /* #define kfifo_out(fifo, buf, n) \ ({ \ typeof((fifo) + 1) __tmp = (fifo); \ typeof(__tmp->ptr) __buf = (buf); \ unsigned long __n = (n); \ const size_t __recsize = sizeof(*__tmp->rectype); \ struct __kfifo *__kfifo = &__tmp->kfifo; \ (__recsize) ?\ __kfifo_out_r(__kfifo, __buf, __n, __recsize) : \ __kfifo_out(__kfifo, __buf, __n); \ }) */ #endif // __GE_KFIFO_H__