[PATCH 09/30] kfifo_sample
From: Huang Ying
Date: Fri Jul 02 2010 - 01:51:45 EST
---
kernel/Makefile | 1
kernel/kfifo_sample.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 126 insertions(+)
create mode 100644 kernel/kfifo_sample.c
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -104,6 +104,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
obj-$(CONFIG_PADATA) += padata.o
+obj-m += kfifo_sample.o
ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
# According to Alan Modra <alan@xxxxxxxxxxxxxxxx>, the -fno-omit-frame-pointer is
--- /dev/null
+++ b/kernel/kfifo_sample.c
@@ -0,0 +1,125 @@
+/* kfifo_sample.c */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kfifo.h>
+#include <linux/percpu.h>
+
+enum record_type {
+ /* The record is just a pad in fifo, no valid data */
+ RECORD_TYPE_PAD = 0x1,
+ RECORD_TYPE_NMI = 0x2,
+ RECORD_TYPE_IRQ = 0x3,
+};
+
+/* Variable length data structure to put into fifo */
+struct base_record {
+ unsigned short len;
+ unsigned short type;
+ unsigned char data[0];
+};
+
+/* Data collected in NMI handler */
+struct nmi_record {
+ struct base_record base;
+ int nmi_field1;
+ int nmi_field2;
+};
+
+/* Data collected in IRQ handler */
+struct irq_record {
+ struct base_record base;
+ int irq_field1;
+};
+
+static DEFINE_PER_CPU(struct kfifo, fifos);
+
+int record_fifo_write(unsigned int len,
+ void (*fill_data)(struct base_record *rcd))
+{
+ struct kfifo *fifo;
+ struct base_record *rcd;
+ unsigned int rlen;
+ int rc = 0;
+
+ fifo = &get_cpu_var(fifos);
+ for (;;) {
+ rlen = len;
+ rcd = kfifo_reserve_continuous_ptr(fifo, &rlen);
+ /* Overflow, this record is thrown away */
+ if (!rcd) {
+ rc = -ENOBUFS;
+ goto out;
+ }
+ /*
+ * Continuous space is not big enough, the requested
+ * space will be marked as pad, then retry
+ */
+ if (rlen != len) {
+ rcd->len = rlen;
+ rcd->type = RECORD_TYPE_PAD;
+ kfifo_commit_ptr(fifo, rcd);
+ } else {
+ rcd->len = len;
+ /* Fill other fields */
+ fill_data(rcd);
+ kfifo_commit_ptr(fifo, rcd);
+ break;
+ }
+ }
+out:
+ put_cpu_var(fifos);
+ return rc;
+}
+
+void nmi_fill_data(struct base_record *rcd)
+{
+ struct nmi_record *nmi_rcd = (struct nmi_record *)rcd;
+
+ rcd->type = RECORD_TYPE_NMI;
+ /* Fill other NMI specific field */
+}
+
+void nmi_handler(void)
+{
+ record_fifo_write(sizeof(struct nmi_record), nmi_fill_data);
+ /* other processing */
+}
+
+void irq_fill_data(struct base_record *rcd)
+{
+ struct irq_record *irq_rcd = (struct irq_record *)rcd;
+
+ rcd->type = RECORD_TYPE_IRQ;
+ /* Fill other IRQ specific field */
+}
+
+void irq_handler(void)
+{
+ record_fifo_write(sizeof(struct irq_record), irq_fill_data);
+ /* other processing */
+}
+
+int record_fifo_for_each(int (*func)(struct base_record *rcd))
+{
+ struct kfifo *fifo;
+ int cpu, rc;
+ struct kfifo_iter iter;
+ struct base_record *rcd;
+
+ for_each_possible_cpu(cpu) {
+ fifo = &per_cpu(fifos, cpu);
+ kfifo_iter_init(&iter, fifo);
+ while ((rcd = kfifo_iter_get_ptr(&iter))) {
+ if (rcd->type != RECORD_TYPE_PAD) {
+ rc = func(rcd);
+ if (rc)
+ return rc;
+ }
+ /* goto next record, the pad space is just skipped */
+ kfifo_iter_advance(&iter, rcd->len);
+ }
+ }
+
+ return 0;
+}
--=-k8O7C1kbihQUCfRzqQz4--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/