mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Stelian Pop <stelian@popies.net>
To: Andrew Morton <akpm@osdl.org>
Cc: linux-kernel@vger.kernel.org
Subject: Re: [RFC, 2.6] a simple FIFO implementation
Date: Thu, 16 Sep 2004 12:45:36 +0200	[thread overview]
Message-ID: <20040916104535.GA3146@crusoe.alcove-fr> (raw)
In-Reply-To: <20040916000438.46d91e94.akpm@osdl.org>

On Thu, Sep 16, 2004 at 12:04:38AM -0700, Andrew Morton wrote:

> Stelian Pop <stelian@popies.net> wrote:
> >
> > > Implementation-wise, the head and tail indices should *not* be constrained
> >  > to be less than the size of the buffer.  They should be allowed to wrap all
> >  > the way back to zero.  This allows you to distinguish between the
> >  > completely-empty and completely-full states while using 100% of the storage.
[...]

Here is the updated patch.

Changes from the previous version include:
- removed excessive inlining, extern functions go now to kernel/kfifo.c
- added __kfifo_get, __kfifo_put etc which do no locking at all
- kfifo_get/kfifo_put are now inline wrappers of the __ versions, which
  takes the spinlock to protect the fifo contents.
- corrected whitespace damage :)

> add(char c)
> {
> 	p->buf[p->head++ % p->number_of_bytes_at_buf] = c;
> }

I wonder if replacing the kfifo_get/kfifo_put implementations with
something like:

	while (remaining--)
		add(*buffer++);

instead of the memcpy() would be a gain in performance... I leaved
the memcpy() implementation for now but since the FIFOS are generally
used to buffer small structures (most of the time bytes or ints), the
character based method may be more efficient.

Stelian.

--- /dev/null	2004-02-23 22:02:56.000000000 +0100
+++ linux-2.6/include/linux/kfifo.h	2004-09-16 12:36:36.024185168 +0200
@@ -0,0 +1,131 @@
+/*
+ * 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
+
+#ifdef __KERNEL__
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+
+struct kfifo {
+	unsigned int head;
+	unsigned int tail;
+	unsigned int size;
+	spinlock_t lock;
+	unsigned char *buffer;
+};
+
+extern struct kfifo *kfifo_alloc(unsigned int size, int gfp_mask);
+extern void kfifo_free(struct kfifo *fifo);
+extern void __kfifo_reset(struct kfifo *fifo);
+extern unsigned int __kfifo_put(struct kfifo *fifo, 
+				unsigned char *buffer, unsigned int len);
+extern unsigned int __kfifo_get(struct kfifo *fifo, 
+				unsigned char *buffer, unsigned int len);
+extern unsigned int __kfifo_len(struct kfifo *fifo);
+
+/*
+ * 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, 
+				     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);
+
+	spin_unlock_irqrestore(&fifo->lock, flags);
+
+	return ret;
+}
+
+/*
+ * 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;
+}
+
+#else
+#warning "don't include kernel headers in userspace"
+#endif /* __KERNEL__ */
+#endif
--- /dev/null	2004-02-23 22:02:56.000000000 +0100
+++ linux-2.6/kernel/kfifo.c	2004-09-16 12:37:45.233663728 +0200
@@ -0,0 +1,138 @@
+/*
+ * 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/kfifo.h>
+
+/*
+ * kfifo_alloc - allocates a new FIFO
+ * @size: the size of the internal buffer.
+ * @gfp_mask: get_free_pages mask, passed to kmalloc()
+ */
+struct kfifo *kfifo_alloc(unsigned int size, int gfp_mask)
+{
+	struct kfifo *fifo;
+
+	fifo = kmalloc(sizeof(struct kfifo), gfp_mask);
+	if (!fifo)
+		return NULL;
+	
+	fifo->buffer = kmalloc(size, gfp_mask);
+	if (!fifo->buffer) {
+		kfree(fifo);
+		return NULL;
+	}
+
+	fifo->head = fifo->tail = 0;
+	fifo->size = size;
+	fifo->lock = SPIN_LOCK_UNLOCKED;
+
+	return fifo;
+}
+EXPORT_SYMBOL(kfifo_alloc);
+
+/*
+ * kfifo_free - frees the FIFO
+ * @fifo: the fifo to be freed.
+ */
+void kfifo_free(struct kfifo *fifo)
+{
+	kfree(fifo->buffer);
+	kfree(fifo);
+}
+EXPORT_SYMBOL(kfifo_free);
+
+/*
+ * __kfifo_reset - removes the entire FIFO contents, no locking version
+ * @fifo: the fifo to be emptied.
+ */
+void __kfifo_reset(struct kfifo *fifo)
+{
+	fifo->head = fifo->tail = 0;
+}
+EXPORT_SYMBOL(__kfifo_reset);
+
+/*
+ * __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. 
+ */
+unsigned int __kfifo_put(struct kfifo *fifo, 
+			 unsigned char *buffer, unsigned int len)
+{
+	unsigned int total, remaining, l;
+	
+	total = remaining = min(len, fifo->size - fifo->tail + fifo->head);
+	while (remaining > 0) {
+		l = min(remaining, fifo->size - (fifo->tail % fifo->size));
+		memcpy(fifo->buffer + (fifo->tail % fifo->size), buffer, l);
+		fifo->tail += l;
+		buffer += l;
+		remaining -= l;
+	}
+
+	return total;
+}
+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.
+ */
+unsigned int __kfifo_get(struct kfifo *fifo, 
+			 unsigned char *buffer, unsigned int len)
+{
+	unsigned int total, remaining, l;
+
+	total = remaining = min(len, fifo->tail - fifo->head);
+	while (remaining > 0) {
+		l = min(remaining, fifo->size - (fifo->head % fifo->size));
+		memcpy(buffer, fifo->buffer + (fifo->head % fifo->size), l);
+		fifo->head += l;
+		buffer += l;
+		remaining -= l;
+	}
+
+	return total;
+}
+EXPORT_SYMBOL(__kfifo_get);
+
+/*
+ * kfifo_len - returns the number of bytes available in the FIFO, no locking version
+ * @fifo: the fifo to be used.
+ */
+unsigned int __kfifo_len(struct kfifo *fifo)
+{
+	return fifo->tail - fifo->head;
+}
+EXPORT_SYMBOL(__kfifo_len);
--- linux-2.6/kernel/Makefile.orig	2004-09-16 12:27:29.012343608 +0200
+++ linux-2.6/kernel/Makefile	2004-09-16 11:58:26.000000000 +0200
@@ -7,7 +7,7 @@
 	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o workqueue.o pid.o \
 	    rcupdate.o intermodule.o extable.o params.o posix-timers.o \
-	    kthread.o
+	    kthread.o kfifo.o
 
 obj-$(CONFIG_FUTEX) += futex.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o

-- 
Stelian Pop <stelian@popies.net>    

  reply	other threads:[~2004-09-16 10:49 UTC|newest]

Thread overview: 64+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-09-13 13:52 Stelian Pop
2004-09-15 10:20 ` Stelian Pop
2004-09-15 11:10   ` Tonnerre
2004-09-15 11:25   ` Alan Cox
2004-09-15 13:27 ` Dmitry Torokhov
2004-09-15 14:21   ` Stelian Pop
2004-09-15 22:30 ` Andrew Morton
2004-09-16  6:43   ` Stelian Pop
2004-09-16  7:04     ` Andrew Morton
2004-09-16 10:45       ` Stelian Pop [this message]
2004-09-16 13:57         ` Paul Jackson
2004-09-16 14:09           ` Stelian Pop
2004-09-16 15:45             ` Paul Jackson
2004-09-16 15:59               ` Stelian Pop
2004-09-16 15:09         ` Buddy Lucas
2004-09-16 15:29           ` Stelian Pop
2004-09-16 15:51             ` Buddy Lucas
2004-09-16 15:52               ` Stelian Pop
2004-09-16 16:07                 ` Buddy Lucas
2004-09-16 18:30                   ` Stelian Pop
2004-09-16 22:52                     ` Buddy Lucas
2004-09-16 17:00         ` Andrew Morton
2004-09-16 18:09           ` Stelian Pop
2004-09-17  0:18             ` Andrew Morton
2004-09-17 10:24               ` Stelian Pop
2004-09-17 11:28                 ` Paul Jackson
2004-09-17 11:44                 ` Hugh Dickins
2004-09-17 12:24                   ` Stelian Pop
2004-09-17 12:37                     ` Duncan Sands
2004-09-17 12:48                       ` Stelian Pop
2004-09-17 13:00                         ` Duncan Sands
2004-09-17 13:05                           ` Stelian Pop
2004-09-17 13:16                             ` Duncan Sands
2004-09-17 13:15                     ` Andrea Arcangeli
2004-09-17 13:36                       ` Stelian Pop
2004-09-17 13:41                         ` Andrea Arcangeli
2004-09-17 14:00                           ` Stelian Pop
2004-09-17 15:14                             ` Andrea Arcangeli
2004-09-17 14:47                         ` Paul Jackson
2004-09-17 12:52       ` James R Bruce
2004-09-17 15:48         ` Stelian Pop
2004-09-17 16:01           ` Andrea Arcangeli
2004-09-17 16:14           ` Hugh Dickins
2004-09-17 20:50             ` Stelian Pop
2004-09-17 21:28               ` Andrea Arcangeli
2004-09-17 21:54                 ` Ryan Cumming
2004-09-17 22:00                   ` Andrea Arcangeli
2004-09-17 22:14                     ` Ryan Cumming
2004-09-17 22:35                       ` Andrew Morton
2004-09-18  0:07                         ` Ryan Cumming
2004-09-17 22:29                     ` Ryan Cumming
2004-09-18  3:41                       ` Kyle Moffett
2004-09-18  7:56                         ` Ryan Cumming
2004-09-17 22:07                 ` Andrew Morton
2004-09-20 15:14                 ` Stelian Pop
2004-09-20 18:01                   ` Sasha Khapyorsky
2004-09-20 18:22                     ` Stelian Pop
2004-09-20 19:00                       ` Richard B. Johnson
2004-09-16 15:57 ` Bill Davidsen
2004-09-17 10:25   ` Stelian Pop
     [not found] <260353727@toto.iv>
2004-09-17  1:00 ` Peter Chubb
2004-09-17  5:45   ` Chris Friesen
2004-09-17 11:58     ` Anton Blanchard
2004-09-17 10:32   ` Stelian Pop

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20040916104535.GA3146@crusoe.alcove-fr \
    --to=stelian@popies.net \
    --cc=akpm@osdl.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®