Re: [ANNOUNCE] 2.6.15-rc5-hrt2 - hrtimers based high resolution patches
From: Jeff Carr
Date: Wed Dec 14 2005 - 19:35:37 EST
On 12/12/05 03:02, Thomas Gleixner wrote:
> The rebased version of the high resolution patches on top of the
> hrtimers base patch is available from the new project home:
>
> http://www.tglx.de/projetcs/hrtimers
>
> The current patch is available here:
>
> http://www.tglx.de/projects/hrtimers/2.6.15-rc5/patch-2.6.15-rc5-hrt2.patch
This is a simple module to start a hrtimer about 20k times a second. I
don't see a way to correctly restart a hrtimer or set one to be periodic
so this is inefficiently bouncing between two timers. Calling
restart_hrtimer() from within the hrtimer.function causes a panic. I was
wondering what the correct method would be.
I had to export some symbols from hrtimer.c so I could build this as a
module.
/*
*
* A simple module that starts a hrtimer ~20k/sec
*
* This software is available to you under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree.
*
*/
#include <asm/semaphore.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
#include <linux/time.h>
#include <linux/workqueue.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/hrtimer.h>
MODULE_AUTHOR("Jeff Carr");
MODULE_DESCRIPTION("simple hrtimer test");
MODULE_LICENSE("GPL");
static struct workqueue_struct *testwq;
static struct work_struct testwork;
static struct hrtimer restart_hrtimer;
static struct hrtimer trigger_hrtimer;
static int done = 0;
static int hrtimer_count = 0;
#define HT_TEST_PERIOD 20000; // In nanoseconds
static void do_test_work(void *data)
{
restart_hrtimer.expires.tv64 = (u64) HT_TEST_PERIOD;
hrtimer_start(&restart_hrtimer, restart_hrtimer.expires, HRTIMER_REL);
return;
}
static int do_restart_hrtimer(void *data)
{
if (!done) {
trigger_hrtimer.expires.tv64 = (u64) HT_TEST_PERIOD;
hrtimer_start(&trigger_hrtimer, trigger_hrtimer.expires,
HRTIMER_REL);
}
return 0;
}
static int do_trigger_hrtimer(void *data)
{
static struct timeval now;
++hrtimer_count;
do_gettimeofday(&now);
if (printk_ratelimit())
printk(KERN_DEBUG
"do_trigger_hrtimer() ran %d times (%li.%li)\n",
hrtimer_count, now.tv_sec, now.tv_usec);
if (!done) {
restart_hrtimer.expires.tv64 = (u64) HT_TEST_PERIOD;
hrtimer_start(&restart_hrtimer, restart_hrtimer.expires,
HRTIMER_REL);
}
return 0;
}
static int __init hrtimer_test_init(void)
{
testwq = create_singlethread_workqueue("simple_hrtimer_test");
if (!testwq)
return -1;
INIT_WORK(&testwork, do_test_work, NULL);
hrtimer_init(&restart_hrtimer, (const clockid_t)CLOCK_REALTIME);
restart_hrtimer.data = (unsigned long)NULL;
restart_hrtimer.function = do_restart_hrtimer;
hrtimer_init(&trigger_hrtimer, (const clockid_t)CLOCK_REALTIME);
trigger_hrtimer.data = (unsigned long)NULL;
trigger_hrtimer.function = do_trigger_hrtimer;
queue_work(testwq, &testwork);
return 0;
}
static void __exit hrtimer_test_cleanup(void)
{
done = 1;
flush_workqueue(testwq);
destroy_workqueue(testwq);
// not sure how to destroy this correctly
hrtimer_cancel(&restart_hrtimer);
remove_hrtimer(&restart_hrtimer);
// not sure how to destroy this correctly
hrtimer_cancel(&trigger_hrtimer);
remove_hrtimer(&trigger_hrtimer);
}
module_init(hrtimer_test_init);
module_exit(hrtimer_test_cleanup);
--- linux-2.6.15-rc5-hrt3/kernel/hrtimer.c 2005-12-14 19:03:20.000000000 -0800
+++ linux-2.6.15-rc5-hrt2/kernel/hrtimer.c 2005-12-13 03:29:57.000000000 -0800
@@ -498,6 +495,7 @@
return orun;
}
+EXPORT_SYMBOL_GPL(hrtimer_forward);
/*
* enqueue_hrtimer - internal function to (re)start a timer
@@ -591,6 +589,7 @@
}
return 0;
}
+EXPORT_SYMBOL_GPL(remove_hrtimer);
/**
* hrtimer_start - (re)start an relative timer on the current CPU
@@ -628,6 +627,7 @@
return ret;
}
+EXPORT_SYMBOL_GPL(hrtimer_start);
/**
* hrtimer_try_to_cancel - try to deactivate a timer
@@ -675,6 +675,7 @@
return ret;
}
}
+EXPORT_SYMBOL_GPL(hrtimer_cancel);
/**
* hrtimer_get_remaining - get remaining time for the timer
@@ -719,6 +720,7 @@
memset(timer, 0, sizeof(struct hrtimer));
hrtimer_rebase(timer, clock_id);
}
+EXPORT_SYMBOL_GPL(hrtimer_init);
/**
* hrtimer_get_res - get the timer resolution for a clock
@@ -992,6 +995,7 @@
else
return (ktime_t) {.tv64 = 0 };
}
+EXPORT_SYMBOL_GPL(schedule_hrtimer);
static inline ktime_t __sched
schedule_hrtimer_interruptible(struct hrtimer *timer,
@@ -1001,6 +1005,7 @@
return schedule_hrtimer(timer, mode);
}
+EXPORT_SYMBOL_GPL(schedule_hrtimer_interruptible);
static long __sched
nanosleep_restart(struct restart_block *restart, clockid_t clockid)
@@ -1031,6 +1036,7 @@
/* The other values in restart are already filled in */
return -ERESTART_RESTARTBLOCK;
}
+EXPORT_SYMBOL_GPL(nanosleep_restart);
static long __sched nanosleep_restart_mono(struct restart_block *restart)
{
@@ -1076,6 +1082,7 @@
return -ERESTART_RESTARTBLOCK;
}
+EXPORT_SYMBOL_GPL(hrtimer_nanosleep);
asmlinkage long
sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
@@ -1090,6 +1097,7 @@
return hrtimer_nanosleep(&tu, rmtp, HRTIMER_REL, CLOCK_MONOTONIC);
}
+EXPORT_SYMBOL_GPL(sys_nanosleep);
/*
* Functions related to boot-time initialization: