# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.1350  -> 1.1351 
#	     kernel/Makefile	1.35    -> 1.36   
#	               (new)	        -> 1.2     include/linux/watch64.h
#	               (new)	        -> 1.2     kernel/watch64.c
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/09/21	jeffpc@jeff.home	1.1347.4.1
# watch64.patch
# --------------------------------------------
# 03/09/21	jeffpc@jeff.home	1.1347.4.2
# Added copyright notice
# --------------------------------------------
# 03/09/21	jeffpc@jeff.home	1.1351
# Merge jeff.home:/home/jeffpc/linux/linux-2.5
# into jeff.home:/home/jeffpc/linux/linux-watch64
# --------------------------------------------
#
diff -Nru a/include/linux/watch64.h b/include/linux/watch64.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/watch64.h	Sun Sep 21 13:03:35 2003
@@ -0,0 +1,58 @@
+/*
+ *  inclue/linux/watch64.h
+ *
+ *  Copyright (C) 2003 Josef "Jeff" Sipek <jeffpc@optonline.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _LINUX_64WATCH_H
+#define _LINUX_64WATCH_H
+
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/seqlock.h>
+#include <linux/spinlock.h>
+
+#define WATCH64_INTERVAL	(HZ/10)
+#define WATCH64_MINIMUM		(HZ/20)
+#define WATCH64_MAGIC		0x573634
+
+#if (BITS_PER_LONG == 64)
+
+struct watch64 {
+};
+
+#else
+
+struct watch64 {
+	struct list_head list;
+	unsigned long *ptr;
+	unsigned long oldval;
+	u_int64_t total;
+	unsigned int interval;
+	int active;
+	seqlock_t lock;
+};
+
+#endif /* (BITS_PER_LONG == 64) */
+
+/*
+ *   Prototypes
+ */
+
+void watch64_init(void);
+void watch64_run(unsigned long var);
+int watch64_register(unsigned long* ptr, unsigned int interval);
+int watch64_unregister(unsigned long* ptr, struct watch64* st);
+struct watch64* watch64_find(unsigned long* ptr);
+int watch64_disable(unsigned long* ptr, struct watch64* st);
+int watch64_enable(unsigned long* ptr, struct watch64* st);
+int watch64_toggle(unsigned long* ptr, struct watch64* st);
+inline u_int64_t watch64_getval(unsigned long* ptr, struct watch64* st);
+
+#endif /* _LINUX_WATCH64_H */
diff -Nru a/kernel/Makefile b/kernel/Makefile
--- a/kernel/Makefile	Sun Sep 21 13:03:35 2003
+++ b/kernel/Makefile	Sun Sep 21 13:03:35 2003
@@ -6,7 +6,8 @@
 	    exit.o itimer.o time.o softirq.o resource.o \
 	    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
+	    rcupdate.o intermodule.o extable.o params.o posix-timers.o \
+	    watch64.o
 
 obj-$(CONFIG_FUTEX) += futex.o
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
diff -Nru a/kernel/watch64.c b/kernel/watch64.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/kernel/watch64.c	Sun Sep 21 13:03:35 2003
@@ -0,0 +1,319 @@
+/*
+ *  kernel/watch64.c
+ *
+ *  Copyright (C) 2003 Josef "Jeff" Sipek <jeffpc@optonline.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+ 
+#include <asm/param.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/kernel.h>
+#include <linux/seqlock.h>
+#include <linux/spinlock.h>
+#include <linux/watch64.h>
+
+/*
+ *   Watch64 global variables
+ */
+
+spinlock_t watch64_biglock = SPIN_LOCK_UNLOCKED;
+LIST_HEAD(watch64_head);
+struct timer_list watch64_timer;
+int watch64_setup;
+
+#if (BITS_PER_LONG == 64)
+
+void watch64_init(void)
+{
+}
+
+void watch64_run(unsigned long var)
+{
+}
+
+int watch64_register(unsigned long* ptr, unsigned int interval)
+{
+	return 0;
+}
+
+int watch64_unregister(unsigned long* ptr, struct watch64* st)
+{
+	return 0;
+}
+
+struct watch64* watch64_find(unsigned long* ptr)
+{
+	return NULL;
+}
+
+int watch64_disable(unsigned long* ptr, struct watch64* st)
+{
+	return 0;
+}
+
+int watch64_enable(unsigned long* ptr, struct watch64* st)
+{
+	return 0;
+}
+
+int watch64_toggle(unsigned long* ptr, struct watch64* st)
+{
+	return 0;
+}
+
+inline u_int64_t watch64_getval(unsigned long* ptr, struct watch64* st)
+{
+	return (u_int64_t) *ptr;
+}
+
+#else
+
+/*
+ *   Initiate watch64 system
+ */
+
+void watch64_init(void)
+{
+	spin_lock(&watch64_biglock);
+	
+	if (watch64_setup==WATCH64_MAGIC) {
+		spin_unlock(&watch64_biglock);
+		return;
+	}
+	
+	printk(KERN_WARNING "watch64: 2003/08/22 Josef 'Jeff' Sipek <jeffpc@optonline.net>\n");
+	printk(KERN_WARNING "watch64: Enabling Watch64 extensions...");
+
+	init_timer(&watch64_timer);
+	watch64_timer.function = watch64_run;
+	watch64_timer.data = (unsigned long) NULL;
+	watch64_timer.expires = jiffies + WATCH64_MINIMUM;
+	add_timer(&watch64_timer);
+
+	printk("done.\n");
+	
+	watch64_setup = WATCH64_MAGIC;
+	
+	spin_unlock(&watch64_biglock);
+}
+
+/*
+ *   Go through the list of registered variables and check them for changes
+ */
+
+void watch64_run(unsigned long var)
+{
+	struct list_head* entry;
+	struct watch64* watch_struct;
+	unsigned long tmp;
+
+	spin_lock(&watch64_biglock);
+	list_for_each(entry, &watch64_head) {
+		watch_struct = list_entry(entry, struct watch64, list);
+		if (*watch_struct->ptr != watch_struct->oldval) {
+			tmp = *watch_struct->ptr;
+			if (tmp > watch_struct->oldval) {
+				write_seqlock(&watch_struct->lock);
+				watch_struct->total += tmp - watch_struct->oldval;
+				write_sequnlock(&watch_struct->lock);
+			} else if (tmp < watch_struct->oldval) {
+				write_seqlock(&watch_struct->lock);
+				watch_struct->total += ((u_int64_t) 1<<BITS_PER_LONG) - watch_struct->oldval + tmp;
+				write_sequnlock(&watch_struct->lock);
+			}
+			watch_struct->oldval = tmp;
+		}
+	}
+	spin_unlock(&watch64_biglock);
+	
+	mod_timer(&watch64_timer, jiffies + WATCH64_MINIMUM);
+}
+
+/*
+ *   Register a new variable with watch64
+ */
+
+int watch64_register(unsigned long* ptr, unsigned int interval)
+{
+	struct watch64* temp;
+	
+	temp = (struct watch64*) kmalloc(sizeof(struct watch64),GFP_ATOMIC);
+
+	if (!temp)
+		return -ENOMEM;
+
+	if (watch64_setup!=WATCH64_MAGIC)
+		watch64_init();
+
+	temp->ptr = ptr;
+	temp->oldval = 0;
+	temp->total = 0;
+	if (interval==0)
+		temp->interval = WATCH64_INTERVAL;
+	else if (interval<WATCH64_MINIMUM) {
+		temp->interval = WATCH64_MINIMUM;
+		printk("watch64: attempted to add new watch with interval below %d jiffies",WATCH64_MINIMUM);
+	} else
+		temp->interval = interval;
+
+	temp->active = 0;
+	
+	seqlock_init(&temp->lock);
+
+	spin_lock(&watch64_biglock);
+	list_add(&temp->list, &watch64_head); // append node
+	spin_unlock(&watch64_biglock);
+	
+	if (list_empty(&watch64_head))
+		return -EINVAL;
+		
+	return 0;
+}
+
+/*
+ *   Unregister a variable with watch64
+ */
+
+int watch64_unregister(unsigned long* ptr, struct watch64* st)
+{
+	if (!st)
+		st = watch64_find(ptr);
+
+	if (!st)
+		return -EINVAL;
+
+	watch64_disable(ptr, st);
+	spin_lock(&watch64_biglock);
+	list_del(&st->list);
+	spin_unlock(&watch64_biglock);
+
+	kfree(st);
+
+	return 0;
+}
+
+/*
+ *   Find watch64 structure
+ */
+
+struct watch64* watch64_find(unsigned long* ptr)
+{
+	struct list_head* tmp;
+	struct watch64* watch64_struct;
+
+	spin_lock(&watch64_biglock);
+	list_for_each(tmp, &watch64_head) {
+		watch64_struct = list_entry(tmp, struct watch64, list);
+		if (watch64_struct->ptr==ptr) {
+			spin_unlock(&watch64_biglock);
+			return watch64_struct;
+		}
+	}
+	spin_unlock(&watch64_biglock);
+
+	return NULL;
+}
+
+/*
+ *   Disable a variable watch
+ */
+
+int watch64_disable(unsigned long* ptr, struct watch64* st)
+{
+	if (!st)
+		st = watch64_find(ptr);
+
+	if (!st)
+		return -EINVAL;
+
+	st->active = 0;
+
+	return 0;
+}
+
+/*
+ *   Enable a variable watch
+ */
+
+int watch64_enable(unsigned long* ptr, struct watch64* st)
+{
+	if (!st)
+		st = watch64_find(ptr);
+
+	if (!st)
+		return -EINVAL;
+
+	st->oldval = *ptr;
+	write_seqlock(&st->lock);
+	st->total  = (u_int64_t) st->oldval;
+	write_sequnlock(&st->lock);
+	st->active = 1;
+
+	return 0;
+}
+
+/*
+ *   Toggle a variable watch
+ */
+
+int watch64_toggle(unsigned long* ptr, struct watch64* st)
+{
+	if (!st)
+		st = watch64_find(ptr);
+
+	if (!st)
+		return -EINVAL;
+
+	if (st->active)
+		watch64_disable(ptr,st);
+	else
+		watch64_enable(ptr,st);
+
+	return 0;
+}
+
+/*
+ *   Return the total 64-bit value
+ */
+
+inline u_int64_t watch64_getval(unsigned long* ptr, struct watch64* st)
+{
+	unsigned int seq;
+	u_int64_t total;
+
+	if (!st)
+		st = watch64_find(ptr);
+
+	if (!st)
+		return *ptr;
+
+	do {
+		seq = read_seqbegin(&st->lock);
+		total = st->total;
+	} while (read_seqretry(&st->lock, seq));
+	
+	return total;
+}
+
+#endif /* (BITS_PER_LONG == 64) */
+
+/*
+ *   Export all the necessary symbols
+ */
+
+EXPORT_SYMBOL(watch64_register);
+EXPORT_SYMBOL(watch64_unregister);
+EXPORT_SYMBOL(watch64_find);
+EXPORT_SYMBOL(watch64_disable);
+EXPORT_SYMBOL(watch64_enable);
+EXPORT_SYMBOL(watch64_toggle);
+EXPORT_SYMBOL(watch64_getval);
