Kiểm tra chạy trạm lí thuyết giữa kì giải phẫu sinh lí
Timer kernel linux
1. MỤC LỤC
M C L CỤ Ụ .....................................................................................................................................................1
1. Gi i thi u chung v Timerớ ệ ề .......................................................................................................................2
1.1.Timer trong vi đi u khi nề ể .................................................................................................................2
1.2.Timer trong Linux Kernel...................................................................................................................2
2. Ví d t o Timer l y log đ nh kỳụ ạ ấ ị ...............................................................................................................5
3. Tài li u tham kh oệ ả ...................................................................................................................................8
2. 1. Giới thiệu chung về Timer
1.1.Timer trong vi điều khiển
Timer/Counter là module hoạt động độc lập và không thể thiếu của bất kỳ vi điều
khiển nào. Chức năng của Timer/Counter gồm: định thời, đếm sự kiện, tạo xung PWM…
Trong đó Timer có chức năng định thời, tức là tạo ra một khoảng thời gian, đếm thời
gian.
Timer hoạt động như thế nào ? Hiểu một cách đơn giản, người lập trình cấu hình
khởi tạo timer và cho phép Timer chạy. Sau một khoảng thời gian định sẵn, chương trình
chính tạm dừng và thực hiện chương trình con mà người lập trình muốn vi điều khiển
thực hiện. Trong thời gian định sẵn đó, vi điều khiển vẫn thực hiện công việc khác. Sau
khi thực hiện xong chương trình con, vi điều khiển tiếp tục thực hiện công việc trước đó.
Timer hoạt động độc lập với CPU.
1.2.Timer trong Linux Kernel
Trong Linux, thời gian được đo lường bởi bởi một biến toàn cục là jiffies. Linux
có hai loại timer hệ thống là timer theo cơ chế cũ, timer theo cơ chế mới.
Timer theo cơ chế cũ
Có một mảng static gồm 32 con trỏ tới các cấu trúc dữ liệu timer_struct và một
mặt nạ ( mask ) của các timer kích hoạt timer_active
Ở đó các Timer đi tới bảng timer được định nghĩa tĩnh (statically defined). Các lối
vào được thêm vào bảng này chủ yếu tại thời điểm khởi tạo hệ thống. Mặt nạ bit
timer_active kiểm tra xem bit nào được thiết lập (set).
Timer theo cơ chế mới
3. Cơ chế này sử dụng một danh sách liên kết các cấu trúc dữ liệu timer_list , được tổ
chức theo thứ tự tăng dần của expiry time.
Nếu expiry time của một timer đang hoạt động hết hiệu lực thì chương trình con
phục vụ Timer được gọi, và bit/ cờ active của timer đó được xóa. Trong timer hệ thống
cơ chế mới, đầu vào danh sách liên kết của các cấu trúc dữ liệu timer_list được kiểm tra.
Tham khảo tại: http://www.tldp.org/LDP/tlk/kernel/kernel.html
Nguồn gốc của thời gian ( Linux time)
Trong Linux kernel, thời gian (time) được đo lường bởi một biến toàn cục là jiffies,
biến này xác định số lượng tick đã xảy ra từ lúc hệ thống được khởi động. Cách thức tính
tick phụ thuộc vào mức thấp nhất của nó trên nền tảng phần cứng cụ thể mà bạn đang
chạy, tuy nhiên nó thường tăng lên thông qua 1 ngắt. Giá trị của tick ( đơn vị có nghĩa
nhỏ nhất của jiffies) có thể cấu hình được, ở kernel 2.6 cho x86, 1 tick bằng 4 ms
(250Hz). Biến toàn cục jiffies được sử dụng rộng rãi trong kernel nhằm một số mục đích,
một trong số đó là thời gian tuyệt đối hiện tại để tính toán giá trị định thời (time–out) cho
một timer.
Kernel timers
Có một vài chương trình làm việc khác nhau cho Timer trong kernel 2.6. Đơn giản
nhất và chính xác nhất trong mọi Timer là timer API (Application Programming
Interface). API cho phép việc xây dựng các Timer, mà các timer này vận hành trong miền
jiffies (minimum 4ms time-out). Đó cũng là Timer API độ phân giải cao (high-resolution
timer API), cho phép việc xây dựng timer trong đó thời gian được định nghĩa ở mức nano
giây (ns). Phụ thuộc vào vi xử lý của bạn và tốc độ vận hành của xi xử lý, chi phí có thể
thay đổi, nhưng API hiện đang cung cấp một cách tạo ra time-out dưới khoảng jiffies
tick.
Standard timers
Timer API tiêu chuẩn đã từng là một phần của Linux kernel trong một thời gian (Kể
từ phiên bản đầu của Linux kernel). Mặc dù nó cho độ chính xác thấp hơn timer độ phân
giải cao, nhưng nó là ý tưởng cho các time-out driver truyền thống.
The timer API
4. Linux cung cấp một API đơn giản cho việc xây dựng và quản lý các Timer. Nó
bao gồm các hàm (và các hàm phụ trợ) cho khởi tạo Timer, xóa bỏ Timer, quản lý Timer.
Timer được định nghĩa bởi cấu trúc timer_list, cấu trúc này chứa mọi dữ liệu cần
thiết đề thực thi một Timer ( bao gồm danh sách các con trỏ và thống kê các Timer có thể
chọn, được cấu hình ở compile time ). Với người dùng, timer_list chứa một expiration
time , một hàm callback ( khi timer kết thúc), và một user-provided context
Khởi tạo Timer: Gọi hàm setup_timer( ) , hàm này khởi tạo timer và thiết lập các
hàm gọi lại user-provided và user-provided context. Cách khác người dùng có thể thiết
lập các giá trị (hàm và dữ liệu) trong timer và gọi hàm init_timer , init_timer được gọi
trong setup_timer( )
void init_timer( struct timer_list *timer );
void setup_timer( struct timer_list *timer,
void (*function)(unsigned long), unsigned long data );
Thiết lập expiration time sau khi khởi tạo Timer: bằng cách gọi hàm mod_timer() ,
và thêm jiffies
Xóa Timer (nếu Timer chưa kết thúc): Gọi hàm del_timer( )
int mod_timer( struct timer_list *timer, unsigned long expires );
void del_timer( struct timer_list *timer );
Người dùng có thể xác định liệu Timer đang chạy (pending) hay không bằng cách
gọi hàm timer_pending( ), nếu trả về 1 thì Timer đang chạy.
int timer_pending( const struct timer_list *timer );
Ví dụ về timer API:
Với init_module ta có thể khởi tạo Timer với hàm setup_timer( ) , thiết lập
expiration time với việc gọi hàm mod_timer(), khi Timer kết thúc gọi hàm
my_timer_callback( ) . Và cuối cùng, xóa timer bằng hàm del_timer( )
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>
MODULE_LICENSE("GPL");
static struct timer_list my_timer;
void my_timer_callback( unsigned long data )
{
printk( "my_timer_callback called (%ld).n", jiffies );
}
int init_module( void )
{
5. int ret;
printk("Timer module installingn");
// my_timer.function, my_timer.data
setup_timer( &my_timer, my_timer_callback, 0 );
printk( "Starting timer to fire in 200ms (%ld)n", jiffies );
ret = mod_timer( &my_timer, jiffies + msecs_to_jiffies(200) );
if (ret) printk("Error in mod_timern");
return 0;
}
void cleanup_module( void )
{
int ret;
ret = del_timer( &my_timer );
if (ret) printk("The timer is still in use...n");
printk("Timer module uninstallingn");
return;
}
Đây là ví dụ đơn giản về timer API, chưa đạt yêu cầu chính xác cao cho các ứng
dụng thời gian thực. Vì vậy, trên Linux có các Timer độ phân giải cao hỗ trợ.
2. Ví dụ tạo Timer lấy log định kỳ
Thực hiện trên source B2017 R18, đường dẫn
Trong file Kconfig:
# DinhLK add
select SND_SOC_HELLO
#DinhLK add
config SND_SOC_HELLO
default y
Trong file Makefile:
#DinhLK add
snd-soc-hello-objs := hello.o
#DinhLK add
obj-$(CONFIG_SND_SOC_HELLO) += snd-soc-hello.o
Trong file wcd-mbhc-v2.h
//DinhLK add
struct delayed_work DinhLK_dwork;
//DinhLK end
Trong file wcd-mbhc-v2.c
static void DinhLK_function(struct work_struct *work)
6. {
struct delayed_work *dwork;
struct wcd_mbhc *mbhc;
dwork = to_delayed_work(work);
mbhc = container_of(dwork, struct wcd_mbhc, DinhLK_dwork);
pr_err("%s: DinhLK function is running!n", __func__);
schedule_delayed_work(&mbhc->DinhLK_dwork,
msecs_to_jiffies(1000));
}
Giải thích các hàm được sử dụng
Hàm schedule_delayed_work() được định nghĩa trong thư viện <linux/workqueue.h> -
work queue handling for Linux
/**
* schedule_delayed_work - put work task in global workqueue after
delay
* @dwork: job to be done
* @delay: number of jiffies to wait or 0 for immediate execution
*
* After waiting for a given time this puts a job in the kernel-global
* workqueue.
*/
static inline bool schedule_delayed_work(struct delayed_work *dwork,
unsigned long delay)
{
return queue_delayed_work(system_wq, dwork, delay);
}
Hàm queue_delayed_work( ) được định nghĩa trong thư viện <linux/workqueue.h>
/**
* queue_delayed_work - queue work on a workqueue after delay
* @wq: workqueue to use
* @dwork: delayable work to queue
* @delay: number of jiffies to wait before queueing
*
* Equivalent to queue_delayed_work_on() but tries to use the local
CPU.
*/
static inline bool queue_delayed_work(struct workqueue_struct *wq,
struct delayed_work *dwork,
unsigned long delay)
{
return queue_delayed_work_on(WORK_CPU_UNBOUND, wq, dwork,
delay);
7. }
container_of () Là một tool trong Linux Kernel
#ifndef container_of
/**
* container_of - cast a member of a structure out to the containing
structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({
const typeof(((type *)0)->member) * __mptr = (ptr);
(type *)((char *)__mptr - offsetof(type, member)); })
#endif
Hàm msecs_to_jiffies() là hàm chuyển từ mini giây sang jiffies
/**
* msecs_to_jiffies: - convert milliseconds to jiffies
* @m: time in milliseconds
*
* conversion is done as follows:
*
* - negative values mean 'infinite timeout' (MAX_JIFFY_OFFSET)
*
* - 'too large' values [that would result in larger than
* MAX_JIFFY_OFFSET values] mean 'infinite timeout' too.
*
* - all other values are converted to jiffies by either multiplying
* the input value by a factor or dividing it with a factor and
* handling any 32-bit overflows.
* for the details see __msecs_to_jiffies()
*
* msecs_to_jiffies() checks for the passed in value being a constant
* via __builtin_constant_p() allowing gcc to eliminate most of the
* code, __msecs_to_jiffies() is called if the value passed does not
* allow constant folding and the actual conversion must be done at
* runtime.
* the HZ range specific helpers _msecs_to_jiffies() are called both
* directly here and from __msecs_to_jiffies() in the case where
* constant folding is not possible.
*/
static __always_inline unsigned long msecs_to_jiffies(const unsigned int m)
{
if (__builtin_constant_p(m)) {
if ((int)m < 0)
8. return MAX_JIFFY_OFFSET;
return _msecs_to_jiffies(m);
} else {
return __msecs_to_jiffies(m);
}
}
Hàm to_delayed_work() được định nghĩa trong thư viện <linux/workqueue.h>
static inline struct delayed_work *to_delayed_work(struct work_struct *work)
{
return container_of(work, struct delayed_work, work);
}
Hàm INIT_DELAYED_WORK() được định nghĩa trong thư viện <linux/workqueue.h>
#define INIT_DELAYED_WORK(_work, _func)
__INIT_DELAYED_WORK(_work, _func, 0)
3. Tài liệu tham khảo
https://www.ibm.com/developerworks/library/l-timers-list/index.html
http://www.tldp.org/LDP/tlk/kernel/kernel.html