LDD3学习9--数据类型和定时器

这部分对应的是第七章和第十一章,因为内容也不是很多,就一起写了。里面的内容基本上就是一个个的点,所以也就一个个点简单总结一下。

1 数据类型

1.1 数据长度

不同操作系统类型长度可能不一样,看图的话最好用u8,u16,u32,u64。

内存页最好使用PAGE_SIZE,而不要使用4K,因为很多平台可能不是4K。

1.2 字节序大小端

这个在网络编程涉及到也很多,用的时候查一下就知道了。

1.3 数据对齐

书里面说的是最后加一个__attribute__ ((packed)) scsi;,这个是取消对齐,不过我记得在一般常用的时候,都是手动指定对齐:

cpp 复制代码
struct BitFieldStruct {
    unsigned int a : 4;  // 占用 4 位
    unsigned int b : 3;  // 占用 3 位
    unsigned int c : 1;  // 占用 1 位
};

具体用的时候再看吧。。

1.4 判断指针

不要用NULL,用ERR_PTR,IS_ERR,PTR_ERR。

1.5 链表

这个不用自己搞,用内核里面的<linux/list.h>

2 定时器

内核通过定时器中断来跟踪时间的流动,大部分平台运行在 100 或者 1000 中断每秒; 流行的 x86 PC 缺省是 1000。

2.1 定时器

一般用的是 jiffies定时器,是在<linux/jiffies.h>。用法就不多写了,要用的时候搜一下或者GPT,答案都很标准。

高进度的定时器,可以用TSC,例子是:

cpp 复制代码
unsigned long ini, end;
rdtscl(ini); rdtscl(end);
printk("time lapse: %li\n", end - ini); 

两者的区别:

特性 TSC 定时器 jiffies 定时器
依赖硬件 依赖 CPU 硬件支持 不依赖硬件,完全由内核实现
精度 纳秒级 毫秒级
性能 非常高效 开销较小,但需依赖时钟中断
多核一致性 可能存在问题 无多核一致性问题
功耗 较高(高频访问可能增加功耗) 较低(只在时钟中断时更新)
时间跨度 通常不适合长时间跨度 可用于长时间跨度(只需考虑溢出)
典型场景 高精度时间戳,性能测量,延迟计算 调度、内核延迟、一般计时需求

2.2 当前时间

获取当前时间,时间戳,这些和应用层好像差不多,就不多说了。

延迟,在应用层,基本上就是一个sleep打天下。在内核好像东西多了不少。

long wait_event_interruptible_timeout(wait_queue_head_t *q, condition, signed long timeout);这个是用在条件变量。

signed long schedule_timeout(signed long timeout);这个会让当前任务进行休眠,但是会被唤醒,比如信号量。

例子:

cpp 复制代码
#include <linux/jiffies.h>
#include <linux/sched.h>
#include <linux/delay.h>

void example_function(void) {
    long timeout = msecs_to_jiffies(100); // 将100毫秒转换为jiffies
    set_current_state(TASK_INTERRUPTIBLE); // 设置当前任务状态为可中断睡眠
    schedule_timeout(timeout); // 让当前任务睡眠指定的时间
}

ndelay,udelay,mdelay。这几个都是让CPU空转,会占用很多CPU资源。所以只能用在短时间。

msleep。基于调度器调度,不会占用太多CPU资源。

2.3 内核定时器

定义是在<linux/timer.h>,让内核在指定时间后执行某个任务,某个事件或函数。通过timer_list结构,使用 init_timer() 或 timer_setup() 初始化定时器。 使用 add_timer() 启动定时器。 使用 del_timer() 删除定时器。

例子:

cpp 复制代码
void setup_my_timer(void) {
    timer_setup(&my_timer, my_timer_callback, 0);
    my_timer.expires = jiffies + msecs_to_jiffies(1000); // 设置定时1秒
    add_timer(&my_timer);
}

2.4 Tasklets机制

Tasklets 是 Linux 内核中一种轻量级的底半部(Bottom Half)机制,专门用于在软中断(SoftIRQ)上下文中执行延迟处理任务。它可以延迟执行某些非时间敏感的任务,而不会阻塞中断处理程序(Top Half)。

这里有一个例子:

cpp 复制代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Simple Tasklet Example");

// Tasklet 函数
void my_tasklet_func(unsigned long data) {
    printk(KERN_INFO "Tasklet executed! Data: %lu\n", data);
}

// 定义 Tasklet,初始化时指定执行函数和参数
DECLARE_TASKLET(my_tasklet, my_tasklet_func, 42);

// 模块加载时调用
static int __init tasklet_example_init(void) {
    printk(KERN_INFO "Tasklet example module loaded.\n");

    // 调度 Tasklet
    tasklet_schedule(&my_tasklet);
    printk(KERN_INFO "Tasklet scheduled.\n");

    return 0;
}

// 模块卸载时调用
static void __exit tasklet_example_exit(void) {
    // 确保 Tasklet 在卸载前被销毁
    tasklet_kill(&my_tasklet);
    printk(KERN_INFO "Tasklet example module unloaded.\n");
}

module_init(tasklet_example_init);
module_exit(tasklet_example_exit);

运行结果如下:

bash 复制代码
[553563.141606] Tasklet example module loaded. //insmod
[553563.141615] Tasklet scheduled.
[553563.141618] Tasklet executed with data: 42
[553595.066381] Tasklet example module unloaded. //rmmod

看看代码就基本明白,tasklet其实就是将任务提交给CPU调度。比如说收到一个网络包,中断处理中收到包,之后还有繁琐的解包操作,如果还是占用中断,会阻塞其它任务。这个是可以调用tasklet来处理,不用全部占用CPU,提高系统整体性能。

这样中断的前半部分就是硬中断,后半部分就是软中断,tasklet这些。

例子:

cpp 复制代码
irqreturn_t my_interrupt_handler(int irq, void *dev_id)
{
    // 检查中断源是否来自预期设备
    if (check_device_irq(irq)) {
        // 读取设备状态寄存器
        unsigned int status = read_device_status();
        // 清除中断标志
        clear_device_irq(irq);
        // 做一些简单的处理,如将数据从设备缓冲区拷贝到内存的临时位置
        copy_data_from_device();
        // 触发中断下半部处理
        schedule_delayed_work(&my_work, msecs_to_jiffies(10));
        return IRQ_HANDLED;
    }
    return IRQ_NONE;
}

2.5 工作队列

在#include <linux/workqueue.h>中。create_workqueue,create_singlethread_workqueue,DECLARE_WORK,INIT_WORK,PREPARE_WORK。。。

说实话之前也没用过这个,查了一下,本质上就是优先级更低的tasklet,可以被内核调度,适用于耗时更长,可以阻塞的任务。不过貌似现在要被kthread替代了。

最后:之前知乎看到一篇写定时器的,写的哇塞:C/C++中如何稳定地每隔5ms执行某个函数?

相关推荐
三体世界7 分钟前
Linux --TCP协议实现简单的网络通信(中英翻译)
linux·c语言·开发语言·网络·c++·windows·tcp/ip
YY_pdd1 小时前
安卓jetpack compose学习笔记-UI基础学习
笔记·学习
瑶光守护者1 小时前
【深度学习】自编码器:数据压缩与特征学习的神经网络引擎
人工智能·深度学习·神经网络·学习·机器学习·强化学习
Moonnnn.1 小时前
【电赛培训课程】测量与信号类赛题知识点讲解与赛题解析
笔记·学习
余厌厌厌1 小时前
Golang学习之旅
开发语言·学习·golang
冰茶_2 小时前
结构型设计模式之桥接模式
学习·设计模式·微软·c#·.netcore·桥接模式
杀神lwz2 小时前
JVM学习(七)--JVM性能监控
jvm·学习
杀神lwz2 小时前
JVM学习(六)--垃圾回收
java·jvm·学习
Johny_Zhao2 小时前
Burp Suite 企业级深度实战教程
linux·网络·网络安全·信息安全·云计算·shell·burp suite·系统运维·itsm
良辰美景好时光3 小时前
keepalived定制日志bug
linux·运维·bug