#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/notifier.h>
#include <linux/kmemprof.h>
#include "cgprof.h"

MODULE_LICENSE("GPL");

static unsigned int overflow;

static unsigned int max_stack_traversal = 50;
MODULE_PARM(max_stack_traversal, "i");

int cgprof_notifier(struct notifier_block *self, unsigned long val,
			void *arg)
{
	int ret;
	struct kmemprof_event * event = (struct kmemprof_event *) arg;

	ret = kmemprof_cgprof_populate_arcs(
		(enum kmemprof_event_type) val,
		kmem_cache_size(event->cache),
		(unsigned int) event->frame,
		(unsigned int) event->eip, max_stack_traversal);

	if (ret < 0)
		overflow++;

	return NOTIFY_OK;
}

static struct notifier_block cgprof_nb = {
	.notifier_call = &cgprof_notifier,
	.priority = 0
};

static int __init mymodule_init(void)
{
	int ret;

	if ((ret = kmemprof_cgprof_init ()) < 0)
		return ret;

	kmemprof_notifier_chain_register(&cgprof_nb);

	return 0;
}

static void __exit mymodule_exit(void)
{
	kmemprof_notifier_chain_unregister(&cgprof_nb);
	schedule();
	kmemprof_cgprof_destroy ();
}

module_init(mymodule_init);
module_exit(mymodule_exit);

