>From 602a3340fa5b11e6cfff91719f85668980bb338b Mon Sep 17 00:00:00 2001 From: Alessandro Di Marco Date: Wed, 24 Jan 2007 18:28:47 +0100 Subject: [PATCH] Time-warp bug fixed --- 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 #include #include +#include + +#include "debug.h" #include "sin.h" #include "table.h" @@ -36,7 +39,11 @@ MODULE_AUTHOR("Alessandro Di Marco "); 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 \n"); + printk(KERN_DEBUG "System Inactivity Notifier 1.5 - (c) Alessandro Di Marco \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 #include +#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