[PATCH] Time-warp bug fixed

From: Alessandro Di Marco
Date: Wed Jan 24 2007 - 12:28:47 EST


---
Makefile | 2 +
debug.h | 36 +++++++++++++
sin.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
sin.h | 13 +++++
table.c | 45 +++++++++-------
table.h | 6 +--
6 files changed, 239 insertions(+), 37 deletions(-)

diff --git a/Makefile b/Makefile
index d45fa58..8b80de6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,7 @@
MODLPATH = kernel/drivers/char

+#DEBUG="-D SIN_DEBUG"
+
MODL = sinmod
OBJS = sin.o procfs.o sysfs.o table.o input_enumerator.o acpi_enumerator.o

diff --git a/debug.h b/debug.h
new file mode 100644
index 0000000..e1c4bcc
--- /dev/null
+++ b/debug.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2007 Alessandro Di Marco
+ */
+
+/*
+ * This file is part of SIN.
+ *
+ * SIN 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; version 2 of the License.
+ *
+ * SIN 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 SIN; if not, write to the Free Software Foundation, Inc., 51 Franklin
+ * St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#ifdef SIN_DEBUG
+extern int debug;
+#define set_debug(val) debug = (val)
+#define printd(fmt...) if (unlikely(debug)) { printk("SIN: " fmt); }
+#else
+#define SORRY "SIN: debugging support was disabled at compile time, sorry!\n"
+
+#define set_debug(val) if (val) { printk(KERN_DEBUG SORRY); }
+#define printd(fmt...)
+#endif
+
+#endif /* DEBUG_H */
diff --git a/sin.c b/sin.c
index c3633ff..bf06999 100644
--- a/sin.c
+++ b/sin.c
@@ -24,6 +24,9 @@
#include <linux/acpi.h>
#include <linux/mutex.h>
#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+
+#include "debug.h"

#include "sin.h"
#include "table.h"
@@ -36,7 +39,11 @@ MODULE_AUTHOR("Alessandro Di Marco <dmr@xxxxxx>");
MODULE_DESCRIPTION("System Inactivity Notifier");
MODULE_LICENSE("GPL v2");

-MODULE_VERSION("1.4");
+MODULE_VERSION("1.5");
+
+#ifdef SIN_DEBUG
+int debug;
+#endif

static struct acpi_device *acpi_device;

@@ -68,27 +75,33 @@ inline void signal_interaction(void)

WARN_ON(test_bit(RULE_OVER, &status) && timer_pending(&timer));

- clear_bit(RULE_WRAP, &status);
- clear_bit(RULE_OVER, &status);
-
next = occasionally_generate_event(acpi_device,
last_activity(&uact));

if (!shutdown) {
- (void) mod_timer(&timer, next);
+ printd("mod_timer() last = %lu, next = %lu\n",
+ last_activity(&uact) / HZ, next / HZ);
+
+ if (likely(mod_timer(&timer, next))) {
+ WARN_ON(test_bit(RULE_OVER, &status));
+ }
}
+
+ clear_bit(RULE_WRAP, &status);
+ clear_bit(RULE_OVER, &status);
}
}

inline void simulate_event(void)
{
- signal_interaction();
(void) simulate_activity();
+ signal_interaction();
}

static void event(struct input_handle *handle,
unsigned int type, unsigned int code, int value)
{
+ printd("user interaction at %lu\n", jiffies / HZ);
simulate_event();
}

@@ -122,6 +135,8 @@ void timer_fn(unsigned long data)
if (!shutdown) {
unsigned long next;

+ printd(">>>>>>>>>>>> timer_fn()\n");
+
set_bit(RULE_LOCK, &status);

next = timely_generate_event(acpi_device,
@@ -133,10 +148,15 @@ void timer_fn(unsigned long data)
signal_interaction();
}

- if (!test_and_clear_bit(RULE_OVER, &status)) {
+ if (!test_bit(RULE_OVER, &status)) {
+ printd("add_timer() now %lu, timer set to %lu\n",
+ jiffies / HZ, next / HZ);
+
timer.expires = next;
add_timer(&timer);
}
+
+ printd("timer_fn() >>>>>>>>>>>>\n");
}
}

@@ -227,38 +247,41 @@ static struct miscdevice sin_miscdev = {
.fops = &sin_miscfops,
};

-static int __init sih_init(void)
+static int __devinit sin_probe(struct platform_device *dev)
{
int err;

err = misc_register(&sin_miscdev);
if (err < 0) {
+ printk(KERN_ERR "SIN: miscdev initialization failed\n");
goto out;
}

err = input_enum();
if (err < 0) {
+ printk(KERN_ERR "SIN: input enumeration failed\n");
goto cleanout1;
}

err = acpi_enum();
if (err < 0) {
+ printk(KERN_ERR "SIN: acpi enumeration failed\n");
goto cleanout2;
}

err = start_sysfs(sin_miscdev.this_device);
if (err < 0) {
- printk(KERN_ERR "sin: sysfs initialization failed\n");
+ printk(KERN_ERR "SIN: sysfs initialization failed\n");
goto cleanout3;
}

err = start_procfs();
if (err < 0) {
- printk(KERN_ERR "sin: procfs initialization failed\n");
+ printk(KERN_ERR "SIN: procfs initialization failed\n");
goto cleanout4;
}

- printk("System Inactivity Notifier 1.4 - (c) Alessandro Di Marco <dmr@xxxxxx>\n");
+ printk(KERN_DEBUG "System Inactivity Notifier 1.5 - (c) Alessandro Di Marco <dmr@xxxxxx>\n");

return 0;

@@ -274,7 +297,7 @@ out:
return err;
}

-static void __exit sih_exit(void)
+static int __devexit sin_remove(struct platform_device *dev)
{
stop_procfs();
stop_sysfs();
@@ -284,6 +307,133 @@ static void __exit sih_exit(void)
(void) stop_monitor();

misc_deregister(&sin_miscdev);
+
+ return 0;
+}
+
+static void sin_shutdown(struct platform_device *dev)
+{
+ printd("shutdown() >>>>>>>>>>>>\n");
+ printd(">>>>>>>>>>>> shutdown()\n");
+}
+
+#ifdef CONFIG_PM
+static unsigned long left, right, now;
+
+static int sin_suspend(struct platform_device *dev, pm_message_t state)
+{
+ printd("suspend() >>>>>>>>>>>>\n");
+
+ if (running) {
+ printd("stopping timer!\n");
+
+ shutdown = 1;
+ del_timer(&timer);
+
+ now = jiffies;
+
+ left = (long) now - (long) last_activity(&uact);
+ right = (long) timer.expires - (long) now;
+
+ printd("left %lu, now %lu, right %lu\n",
+ left / HZ, now / HZ, right / HZ);
+ } else {
+ printd("not running!\n");
+ }
+
+ printd(">>>>>>>>>>>> suspend()\n");
+
+ return 0;
+}
+
+static int sin_resume(struct platform_device *dev)
+{
+ printd("resume() >>>>>>>>>>>>\n");
+
+ shutdown = 0;
+
+ if (running) {
+ if (!test_bit(RULE_OVER, &status)) {
+ printd("restarting timer!\n");
+
+ if (test_and_clear_bit(RULE_WRAP, &status)) {
+ printd("wrapped rule found\n");
+ special_event(acpi_device);
+ }
+
+ now = trim_activity(&uact, left);
+
+ timer.expires = now + right;
+
+ printd("last = %lu, now is %lu, timer set to %lu\n",
+ last_activity(&uact) / HZ,
+ now / HZ, timer.expires / HZ);
+
+ add_timer(&timer);
+ } else {
+ printd("rule over found\n");
+ }
+ } else {
+ printd("not running!\n");
+ }
+
+ printd(">>>>>>>>>>>> resume()\n");
+
+ return 0;
+}
+#else
+#define sin_suspend NULL
+#define sin_resume NULL
+#endif
+
+static struct platform_driver sin_driver = {
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = sin_probe,
+ .remove = __devexit_p(sin_remove),
+ .shutdown = sin_shutdown,
+ .suspend = sin_suspend,
+ .resume = sin_resume,
+};
+
+static struct platform_device *sin_platform_device;
+
+static int __init sih_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&sin_driver);
+ if (err < 0) {
+ goto out;
+ }
+
+ sin_platform_device = platform_device_alloc(MODULE_NAME, -1);
+ if (!sin_platform_device) {
+ err = -ENOMEM;
+ goto cleanout1;
+ }
+
+ err = platform_device_add(sin_platform_device);
+ if (err < 0) {
+ goto cleanout2;
+ }
+
+ return 0;
+
+cleanout2:
+ platform_device_put(sin_platform_device);
+cleanout1:
+ platform_driver_unregister(&sin_driver);
+out:
+ return err;
+}
+
+static void __exit sih_exit(void)
+{
+ platform_device_unregister(sin_platform_device);
+ platform_driver_unregister(&sin_driver);
}

module_init(sih_init);
diff --git a/sin.h b/sin.h
index 1ef52d2..929b1e5 100644
--- a/sin.h
+++ b/sin.h
@@ -59,6 +59,19 @@ static inline unsigned long last_activity(struct user_activity *uact)
return last;
}

+static inline unsigned long trim_activity(struct user_activity *uact,
+ unsigned long offset)
+{
+ unsigned long last;
+
+ spin_lock(&uact->lock);
+ last = jiffies;
+ uact->last = (long) last - (long) offset;
+ spin_unlock(&uact->lock);
+
+ return last;
+}
+
extern unsigned long simulate_activity(void);
extern void signal_interaction(void);
extern void simulate_event(void);
diff --git a/table.c b/table.c
index b51e905..c55f230 100644
--- a/table.c
+++ b/table.c
@@ -24,6 +24,8 @@
#include <linux/acpi.h>
#include <linux/sort.h>

+#include "debug.h"
+
#include "sin.h"
#include "uniq.h"
#include "table.h"
@@ -39,15 +41,24 @@ static int next_rule;
* event service routines (e.g. /etc/acpid/default.sh).
*/

-unsigned long occasionally_generate_event(struct acpi_device *acpi_device,
- unsigned long last)
+static inline void generate_event(struct acpi_device *acpi_device, int rnum)
{
- printd("generating special event [%d, %d]\n",
- rt.rules[rt.rnum].type, rt.rules[rt.rnum].data);
+ struct rule *rule = &rt.rules[rnum];
+
+ printd("generating event [%d, %d]\n", rule->type, rule->data);

- (void) acpi_bus_generate_event(acpi_device, rt.rules[rt.rnum].type,
- rt.rules[rt.rnum].data);
+ (void) acpi_bus_generate_event(acpi_device, rule->type, rule->data);
+}
+
+inline void special_event(struct acpi_device *acpi_device)
+{
+ generate_event(acpi_device, rt.rnum);
+}

+unsigned long occasionally_generate_event(struct acpi_device *acpi_device,
+ unsigned long last)
+{
+ special_event(acpi_device);
return last + rt.rules[next_rule = 0].target;
}

@@ -55,26 +66,18 @@ unsigned long timely_generate_event(struct acpi_device *acpi_device,
unsigned long last, unsigned long *status)
{
printd("last %lu [status %lu], now %lu -> next target is %lu (%d)\n",
- last, *status, jiffies,
- last + rt.rules[next_rule].target, next_rule);
+ last / HZ, *status, jiffies / HZ,
+ (last + rt.rules[next_rule].target) / HZ, next_rule);

for (; next_rule < rt.rnum &&
time_after_eq(jiffies, last + rt.rules[next_rule].target);
next_rule++) {
if (unlikely(test_and_clear_bit(RULE_WRAP, status))) {
- printd("passive wrap, generating special event\n");
-
- (void) acpi_bus_generate_event(acpi_device,
- rt.rules[rt.rnum].type,
- rt.rules[rt.rnum].data);
+ printd("passive wrap, user forgot to interact!\n");
+ special_event(acpi_device);
}

- printd("generating event [%d, %d]\n",
- rt.rules[next_rule].type, rt.rules[next_rule].data);
-
- (void) acpi_bus_generate_event(acpi_device,
- rt.rules[next_rule].type,
- rt.rules[next_rule].data);
+ generate_event(acpi_device, next_rule);
set_bit(RULE_TRIG, status);
}

@@ -87,7 +90,7 @@ unsigned long timely_generate_event(struct acpi_device *acpi_device,

last = simulate_activity();
} else {
- printd("reached the last rule, disconnecting timer\n");
+ printd("last rule, disconnecting the timer\n");
set_bit(RULE_OVER, status);
}
}
@@ -271,6 +274,8 @@ int push_table(const char *buf, unsigned long count)
goto cleanout3;
}

+ set_debug(rt.debug);
+
err = start_monitor(get_hardware_id(rt.handle), idi);
if (err < 0) {
goto cleanout3;
diff --git a/table.h b/table.h
index fd6b91f..d2a86ae 100644
--- a/table.h
+++ b/table.h
@@ -39,11 +39,6 @@ struct table {
struct rule *rules;
};

-#define printd(fmt...) \
- if (unlikely(rt.debug)) { \
- printk(fmt); \
- }
-
static inline int tablecmp(struct table *l, struct table *r)
{
if (l->debug != r->debug ||
@@ -73,6 +68,7 @@ static inline int tablecmp(struct table *l, struct table *r)

#define TABLE_BUFFER_SIZE (8 + rt.dnum + rt.rnum * 3 + (TABLE_SIZE << 3) / 3)

+extern void special_event(struct acpi_device *acpi_device);
extern unsigned long occasionally_generate_event(struct acpi_device *acpi_device, unsigned long last);
extern unsigned long timely_generate_event(struct acpi_device *acpi_device, unsigned long last, unsigned long *notify);

--
1.4.4.4


--=-=-=
Content-Disposition: inline; filename=0002-procfs.txt