diff --git a/06-TimeManagement/Makefile b/06-TimeManagement/Makefile new file mode 100644 index 0000000..b804fb5 --- /dev/null +++ b/06-TimeManagement/Makefile @@ -0,0 +1,5 @@ +obj-m+=omod6_kern_time.o +all: + make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules +clean: + make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean diff --git a/06-TimeManagement/chkpatch.sh b/06-TimeManagement/chkpatch.sh new file mode 100755 index 0000000..4f5c710 --- /dev/null +++ b/06-TimeManagement/chkpatch.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +curdir=$(pwd) +cd ~/kernel/linux +./scripts/checkpatch.pl --no-tree --no-signoff --ignore LONG_LINE,LONG_LINE_COMMENT,LONG_LINE_STRING -f $curdir/$1 +cd $curdir diff --git a/06-TimeManagement/omod6_kern_time.c b/06-TimeManagement/omod6_kern_time.c new file mode 100644 index 0000000..ca43957 --- /dev/null +++ b/06-TimeManagement/omod6_kern_time.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: AFL-3.0 +/* + * Copyright (C) 2018 + * Author: Oleg Khokhlov + * + * SysFS kernel module for test kernel timing functions + * + * doc links: + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + + +//Internal Kernel API (Time Management): + +//1. Implement kernel module with API in sysfs or procfs, which is able to: +// - return time (in seconds) passed since previous read; +// - return absolute time of previous reading; +// - periodically print some message to log, make period adjustable; + +// --------------- MODULE PARAMETERS DESCRIPTION ------------------- +//int iParam; +//module_param(iParam, int, 0); +//MODULE_PARM_DESC(iParam, "iParam: ReturnCode"); + +//char *sParam = "Default"; +//module_param(sParam, charp, 0); +//MODULE_PARM_DESC(sParam, "sParam: string parameter"); + +//------------ GLOBAL MODULE DATA --------------------- +static struct class *attr_class; + +#define SysFS_DIR_NAME "omod6" +#define SysFS_ATTR_NAME "ktime" + +uint32_t ModCallCount; +uint32_t LastCallTimeSec; +uint32_t LastCall_dT; +uint32_t LastCallTicks; + +uint32_t TimerInterval; +uint32_t TimerCounter; +uint32_t TimerStartTick; + +char LogMessage[256]; + +uint32_t GetTimeStamp(void) +{ + return (uint32_t) (ktime_to_ms(ktime_get_real()) / 1000); +} + +uint32_t GetTickCount(void) +{ + return (uint32_t) (get_jiffies_64() * 1000 / HZ); +} + + +//--------------- SysFS read/write functions ---------------------- + +static ssize_t ktime_show(struct class *cl, + struct class_attribute *attr, + char *buf) +{ + int L; + uint32_t TS, dT, T; + struct rtc_time tm; + + T = GetTickCount(); + TS = GetTimeStamp(); + dT = TS - LastCallTimeSec; + + if (dT == 0) + dT = LastCall_dT; + else + LastCall_dT = dT; + + LastCallTicks = T; + + ModCallCount++; + + sprintf(buf, "ktime (%u ticks, %u HZ):\n", (uint32_t)get_jiffies_64(), HZ); + sprintf(strchr(buf, 0), "%u module call\n", ModCallCount); + sprintf(strchr(buf, 0), "%u sec from last call\n", dT); + rtc_time64_to_tm(TS, &tm); + //https://ru.wikipedia.org/wiki/Time.h + sprintf(strchr(buf, 0), "%u sec curr abs time from Epoch (%d.%02d.%02d, %02d:%02d:%02d)\n", TS, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + sprintf(strchr(buf, 0), "%u sec prev call abs time from Epoch\n", LastCallTimeSec); + sprintf(strchr(buf, 0), "%u ms - Timer Interval\n", TimerInterval); + sprintf(strchr(buf, 0), "%u times timer called\n", TimerCounter); + + LastCallTimeSec = TS; + + L = strlen(buf); + return L; +} + +// Kernel Timer object +struct timer_list MyTimer; + +// +// Kernel Timer Function. Run in interrupt context! Called only once after start/mod +// +void KernelTimerFunc(struct timer_list *t) +{ + uint32_t T, dT; + + TimerCounter++; + T = GetTickCount(); + dT = T - TimerStartTick; + pr_info("omod6 timer[%u]: %s (delay = %u ms)\n", TimerCounter, LogMessage, dT); +} + + +static ssize_t ktime_store(struct class *cl, + struct class_attribute *attr, + const char *buf, size_t count) +{ + int interval = 0; + char *cp; + int n; + + if (sscanf(buf, "%d", &interval) == 1) { + cp = strchr(buf, ' '); + if (cp) { + while (*cp == ' ') + cp++; + for (n = 0; n < sizeof(LogMessage) - 1; n++) { + if (*cp < ' ') + break; + LogMessage[n] = *cp++; + } + LogMessage[n] = 0; + } + } + + pr_info("omod6 store (%d, \'%s\')\n", interval, LogMessage); + + TimerInterval = interval; + + // start, stop or reconfig timer + if (interval == 0) { + if (timer_pending(&MyTimer)) { + del_timer(&MyTimer); + pr_info("omod6 Timer disabled\n"); + } + } else { + unsigned long expired = get_jiffies_64() + interval * HZ / 1000; + mod_timer(&MyTimer, expired); + TimerStartTick = GetTickCount(); + pr_info("omod6 Timer started (interval=%u)\n", interval); + } + return count; +} + +static struct class_attribute class_attr_ktime = { + .attr = { .name = SysFS_ATTR_NAME, .mode = 0666 }, + .show = ktime_show, + .store = ktime_store +}; + + +static int __init omod_init(void) +{ + int ret; + + attr_class = class_create(THIS_MODULE, SysFS_DIR_NAME); + if (attr_class == NULL) { + pr_err("omod6: error creating sysfs class\n"); + return -EEXIST; + } + + ret = class_create_file(attr_class, &class_attr_ktime); + if (ret) { + pr_err("omod6: error creating sysfs class attribute\n"); + class_destroy(attr_class); + return ret; + } + + timer_setup(&MyTimer, KernelTimerFunc, 0); + + pr_info("omod6 Kernel time function test module started.\n"); + LastCallTimeSec = GetTimeStamp(); + return 0; +} + +static void __exit omod_exit(void) +{ + class_remove_file(attr_class, &class_attr_ktime); + class_destroy(attr_class); + + pr_info("omod6 module normal shutdown.\n"); +} + +module_init(omod_init); +module_exit(omod_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Oleg Khokhlov"); +MODULE_DESCRIPTION("OlegH Lesson06 module: test kernel time funcs"); +MODULE_VERSION("0.2"); + diff --git a/06-TimeManagement/omod6_kern_time.chklog b/06-TimeManagement/omod6_kern_time.chklog new file mode 100644 index 0000000..ba805ab --- /dev/null +++ b/06-TimeManagement/omod6_kern_time.chklog @@ -0,0 +1,8 @@ +bash$ +bash$ ./chkpatch.sh omod6_kern_time.c +total: 0 errors, 0 warnings, 204 lines checked + +/home/olegh/gl-kernel-training-2018/06-TimeManagement/omod6_kern_time.c has no obvious style problems and is ready for submission. + +NOTE: Ignored message types: LONG_LINE LONG_LINE_COMMENT LONG_LINE_STRING +bash$ diff --git a/06-TimeManagement/omod6_kern_time.log b/06-TimeManagement/omod6_kern_time.log new file mode 100644 index 0000000..0ab5cde --- /dev/null +++ b/06-TimeManagement/omod6_kern_time.log @@ -0,0 +1,76 @@ +bash$ +bash$ sudo dmesg -C +bash$ sudo insmod omod6_kern_time.ko +bash$ dmesg +[164257.292896] omod6 Kernel time function test module started. +bash$ +bash$ cat /sys/class/omod6/ktime +ktime (40995296 ticks, 250 HZ): +1 module call +24 sec from last call +1542096090 sec curr abs time from Epoch (year:2018) +1542096066 sec prev call abs time from Epoch +0 ms - Timer Interval +0 times timer called +bash$ +bash$ +bash$ cat /sys/class/omod6/ktime +ktime (40997586 ticks, 250 HZ): +2 module call +9 sec from last call +1542096099 sec curr abs time from Epoch (year:2018) +1542096090 sec prev call abs time from Epoch +0 ms - Timer Interval +0 times timer called +bash$ +bash$ +bash$ echo "5000 Hello from timer" > /sys/class/omod6/ktime +bash$ +bash$ dmesg +[164257.292896] omod6 Kernel time function test module started. +[164312.443489] omod6 store (5000, 'Hello') +[164312.443495] omod6 Timer started (interval=5000) +bash$ +bash$ dmesg +[164257.292896] omod6 Kernel time function test module started. +[164312.443489] omod6 store (5000, 'Hello') +[164312.443495] omod6 Timer started (interval=5000) +[164317.680785] omod6 timer[1]: Hello (delay = 5240 ms) +bash$ +bash$ +bash$ cat /sys/class/omod6/ktime +ktime (41007134 ticks, 250 HZ): +3 module call +38 sec from last call +1542096137 sec curr abs time from Epoch (year:2018) +1542096099 sec prev call abs time from Epoch +5000 ms - Timer Interval +1 times timer called +bash$ +bash$ +bash$ echo "10000 Hello from timer2" > /sys/class/omod6/ktime +bash$ echo "0 Hello from timer2" > /sys/class/omod6/ktime +bash$ dmesg +[164257.292896] omod6 Kernel time function test module started. +[164312.443489] omod6 store (5000, 'Hello') +[164312.443495] omod6 Timer started (interval=5000) +[164317.680785] omod6 timer[1]: Hello (delay = 5240 ms) +[164348.845400] omod6 store (10000, 'Hello') +[164348.845406] omod6 Timer started (interval=10000) +[164353.156345] omod6 store (0, 'Hello') +[164353.156350] omod6 Timer disabled +bash$ +bash$ +bash$ cat /sys/class/omod6/ktime +ktime (41018014 ticks, 250 HZ): +4 module call +44 sec from last call +1542096181 sec curr abs time from Epoch (year:2018) +1542096137 sec prev call abs time from Epoch +0 ms - Timer Interval +1 times timer called +bash$ +bash$ +bash$ sudo rmmod omod6_kern_time +bash$ +bash$ diff --git a/06-TimeManagement/omod6_kern_time2.chklog b/06-TimeManagement/omod6_kern_time2.chklog new file mode 100644 index 0000000..8d7da4a --- /dev/null +++ b/06-TimeManagement/omod6_kern_time2.chklog @@ -0,0 +1,30 @@ +bash$ +bash$ ./chkpatch.sh omod6_kern_time.c +WARNING: Prefer kstrto to single variable sscanf +#138: FILE: /home/olegh/gl-kernel-training-2018/06-TimeManagement/omod6_kern_time.c:138: ++ if (sscanf(buf, "%d", &interval) == 1) { ++ cp = strchr(buf, ' '); ++ if (cp) { ++ while (*cp == ' ') ++ cp++; ++ for (n = 0; n < sizeof(LogMessage) - 1; n++) { ++ if (*cp < ' ') ++ break; ++ LogMessage[n] = *cp++; ++ } ++ LogMessage[n] = 0; ++ } ++ } + +total: 0 errors, 1 warnings, 222 lines checked + +NOTE: For some of the reported defects, checkpatch may be able to + mechanically convert to the typical style using --fix or --fix-inplace. + +/home/olegh/gl-kernel-training-2018/06-TimeManagement/omod6_kern_time.c has style problems, please review. + +NOTE: Ignored message types: LONG_LINE LONG_LINE_COMMENT LONG_LINE_STRING + +NOTE: If any of the errors are false positives, please report + them to the maintainer, see CHECKPATCH in MAINTAINERS. +bash$ diff --git a/06-TimeManagement/omod6_kern_time2.log b/06-TimeManagement/omod6_kern_time2.log new file mode 100644 index 0000000..cb0287a --- /dev/null +++ b/06-TimeManagement/omod6_kern_time2.log @@ -0,0 +1,35 @@ +bash$ +bash$ +bash$ sudo insmod omod6_kern_time.ko +bash$ cat /sys/class/omod6/ktime +ktime (50320923 ticks, 250 HZ): +1 module call +4 sec from last call +1542138138 sec curr abs time from Epoch (2018.11.13, 19:42:18) +1542138134 sec prev call abs time from Epoch +0 ms - Timer Interval +0 times timer called +bash$ +bash$ +bash$ echo "2000 Hello from module timer!" > /sys/class/omod6/ktime +bash$ +bash$ cat /sys/class/omod6/ktime +ktime (50325075 ticks, 250 HZ): +2 module call +17 sec from last call +1542138155 sec curr abs time from Epoch (2018.11.13, 19:42:35) +1542138138 sec prev call abs time from Epoch +2000 ms - Timer Interval +1 times timer called +bash$ +bash$ +bash$ dmesg +[201578.642960] omod6 Kernel time function test module started. +[201593.096793] omod6 store (2000, 'Hello from module timer!') +[201593.096800] omod6 Timer started (interval=2000) +[201595.113490] omod6 timer[1]: Hello from module timer! (delay = 2020 ms) +bash$ +bash$ +bash$ sudo rmmod omod6_kern_time +bash$ +bash$