>From 7ea29ebb151f4822b3091c018b3b6401f2a36e3e Mon Sep 17 00:00:00 2001 From: Huang Ying Date: Fri, 2 Jul 2010 13:51:45 +0800 Subject: [PATCH 09/30] kfifo_sample --- 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 , the -fno-omit-frame-pointer is --- /dev/null +++ b/kernel/kfifo_sample.c @@ -0,0 +1,125 @@ +/* kfifo_sample.c */ + +#include +#include +#include +#include + +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; +}