diff --git a/05_timers/kernel_module/Makefile b/05_timers/kernel_module/Makefile new file mode 100644 index 0000000..d1cda77 --- /dev/null +++ b/05_timers/kernel_module/Makefile @@ -0,0 +1,9 @@ +KERNELDIR ?= ../../../buildroot/buildroot-2021.02.7/output/build/linux-5.10.7/ #WARNING relative path + +obj-m := mytimeobj.o + +all: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules + +clean: + $(MAKE) -C $(KERNELDIR) M=$(PWD) clean diff --git a/05_timers/kernel_module/mytimeobj.c b/05_timers/kernel_module/mytimeobj.c new file mode 100644 index 0000000..6ce3471 --- /dev/null +++ b/05_timers/kernel_module/mytimeobj.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Nazarii Kurylko "); +MODULE_DESCRIPTION("time in kernel module"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); + +static ssize_t time_prev_call_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + static struct timespec64 ts_prev; + ssize_t count; + + count = scnprintf(buf, PAGE_SIZE, "%llds.%ldns\n", ts_prev.tv_sec, + ts_prev.tv_nsec); + + ktime_get_real_ts64(&ts_prev); + return count; +} + +static ssize_t time_since_prev_call_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct timespec64 ts; + ktime_t now = 0; + static int inited; + static ktime_t prev; + + now = ktime_get(); + if (!inited) { + prev = now; + inited = 1; + } + + now = ktime_get(); + ts = ktime_to_timespec64(ktime_sub(now, prev)); + prev = now; + + return scnprintf((char *)buf, PAGE_SIZE, "%llds.%ldns\n", ts.tv_sec, + ts.tv_nsec); +} + +static struct kobj_attribute attribute1 = + __ATTR(time_prev_call, 0444, time_prev_call_show, NULL); + +static struct kobj_attribute attribute2 = + __ATTR(time_since_prev_call, 0444, time_since_prev_call_show, NULL); + +static struct kobject *myobject_kobj; + +static struct attribute *attrs[] = { + &attribute1.attr, &attribute2.attr, NULL, + /* need to NULL terminate the list of attributes */ +}; + +static struct attribute_group attr_group = { + .attrs = attrs, +}; + +static int myobject_init(void) +{ + int res = 0; + + myobject_kobj = kobject_create_and_add("MyTimeObject", kernel_kobj); + if (!myobject_kobj) + return -ENOMEM; + res = sysfs_create_group(myobject_kobj, &attr_group); + if (res) + kobject_put(myobject_kobj); + + return res; +} + +static void myobject_exit(void) +{ + kobject_put(myobject_kobj); +} + +module_init(myobject_init); +module_exit(myobject_exit); diff --git a/05_timers/userspace_time/Makefile b/05_timers/userspace_time/Makefile new file mode 100644 index 0000000..84a0fcd --- /dev/null +++ b/05_timers/userspace_time/Makefile @@ -0,0 +1,11 @@ +default: mytime + +rpscissors.o: mytime.c + gcc -c mytime.c -o mytime.o + +rpscissors: mytime.o + gcc mytime.o -o mytime + +clean: + -rm -f mytime.o + -rm -f mytime diff --git a/05_timers/userspace_time/mytime.c b/05_timers/userspace_time/mytime.c new file mode 100644 index 0000000..a2dcacf --- /dev/null +++ b/05_timers/userspace_time/mytime.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: 0BSD +/** + * Description: My Time + * Author: Nazarii Kurylko + * Created: 09.12.2021 + **/ + +#include +#include +#include +#include + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +// see https://man7.org/linux/man-pages/man3/clock_gettime.3.html for details + +clockid_t clk_id_arr[] = { CLOCK_REALTIME, CLOCK_REALTIME_ALARM, + CLOCK_REALTIME_COARSE, CLOCK_TAI, + CLOCK_MONOTONIC, CLOCK_MONOTONIC_RAW, + CLOCK_MONOTONIC_COARSE, CLOCK_PROCESS_CPUTIME_ID, + CLOCK_THREAD_CPUTIME_ID, CLOCK_BOOTTIME, + CLOCK_BOOTTIME_ALARM }; + +char *clk_id_arr_str[] = { + "CLOCK_REALTIME", "CLOCK_REALTIME_ALARM", + "CLOCK_REALTIME_COARSE", "CLOCK_TAI", + "CLOCK_MONOTONIC", "CLOCK_MONOTONIC_RAW", + "CLOCK_MONOTONIC_COARSE", "CLOCK_PROCESS_CPUTIME_ID", + "CLOCK_THREAD_CPUTIME_ID", "CLOCK_BOOTTIME", + "CLOCK_BOOTTIME_ALARM" +}; + +int timespec2str(char *buf, uint len, struct timespec *ts) +{ + int ret; + struct tm t; + + tzset(); + if (localtime_r(&(ts->tv_sec), &t) == NULL) + return 1; + + ret = strftime(buf, len, "%F %T", &t); + if (ret == 0) + return 2; + len -= ret - 1; + + ret = snprintf(&buf[strlen(buf)], len, ".%09ld", ts->tv_nsec); + if (ret >= len) + return 3; + + return 0; +} + +/*main algorithm*/ +int main(int argc, char **argv) +{ + static int i; + static struct timespec mytime, mytimeres; + char tmp[100]; + + for (i = 0; i < ARRAY_SIZE(clk_id_arr); ++i) { + //print clock output + if (!clock_gettime(clk_id_arr[i], &mytime)) + printf("%s: time: %ld sec, %ld nsec\n", + clk_id_arr_str[i], mytime.tv_sec, + mytime.tv_nsec); + //print time in formated string + timespec2str(tmp, sizeof(tmp), &mytime); + printf("%s: %s\n", clk_id_arr_str[i], tmp); + + //print clock resolution + if (!clock_getres(clk_id_arr[i], &mytimeres)) + printf("%s: resolution: %ld sec, %ld nsec\n", + clk_id_arr_str[i], mytimeres.tv_sec, + mytimeres.tv_nsec); + printf("==================================\n"); + } + + return 0; +}