Linux学习笔记(2)--一些内核接口

1)dump_stack

dump_stack()是Linux内核中的一个函数,用于在内核中输出当前的函数调用栈。该函数会输出当前线程(或进程)的函数调用栈信息,以及相应的调用地址和虚拟内存地址等信息,一般用于诊断程序运行时的错误或异常。使用该函数可以帮助开发者找到程序崩溃的原因所在,并进行快速排错。它常常被用于内核调试和性能分析。

2)kref_put

kref_put 是 Linux 内核中的一个函数,用于在引用计数器(也称为 kref)归零时释放内核资源。

具体来说,当内核中的某个结构体需要在多个地方被引用,通过使用 kref 引用计数器可以追踪该结构体被引用的数量。当该结构体不再被需要时,可以通过 kref_put 函数来将该结构体的引用计数减 1,如果此时引用计数为 0,则说明该结构体可以被安全地释放。

以下是 kref_put 函数的原型:

void kref_put(struct kref *kref, void (*release)(struct kref *kref));

其中,kref 是指向内核引用计数器的指针,release 是一个回调函数,用于在引用计数达到 0 时释放资源。

使用 kref_put 函数可以避免由于引用计数器未正确管理引用计数而导致的内存泄漏和资源占用过多等问题。

3)kfree_rcu

kfree_rcu是Linux内核中提供的一种资源释放接口,用于在RCU(Read-Copy-Update)保护下释放内存。RCU是一种经典的读写锁算法,用于保护共享的数据结构,它的特点是在读的过程中不需要获取锁,在写的过程中通过复制一份数据来保证读操作不受写操作的影响。因此在释放内存时,需要使用RCU使得所有对该内存的访问都已完成,否则可能会触发未定义的行为。kfree_rcu接口是在RCU保护下调用kfree接口来释放内存所使用的函数。+

4)atomic_dec()

是一个原子操作接口,用于将一个整数变量减小 1,并保证这个操作是原子的。

在并发程序中,如果多个线程同时对同一个变量进行修改操作,可能会产生竞争条件(Race Condition)的问题。其中一种解决方式是使用原子操作,即将整个操作作为一个不可分割的单元执行,从而保证操作的完整性。atomic_dec() 就是 Linux 内核中提供的一种原子减 1 操作。

使用 atomic_dec() 接口时,需要将待减小的整数变量以指针的方式传入函数中。函数会自动将该变量减小 1,并返回减小后的结果。该操作是原子的,也就是说,在该操作执行完之前,任何其他线程无法修改该变量。

5)container_of

是一个宏定义,常用于 C 语言中的链表实现中,用于从链表节点的地址计算出整个数据结构的地址。它的定义和用法如下:

#define container_of(ptr, type, member) \
    ((type *)((char *)(ptr) - offsetof(type, member)))

struct my_struct {
    int x;
    float y;
    struct list_head list;
};
  • ptr:指向结构体中某个成员的指针,例如 &some_struct.list
  • type:结构体类型,例如 struct my_struct
  • member:结构体中某个成员的名称,例如 list

那么 container_of(&some_struct.list, struct my_struct, list) 的计算过程如下:

  1. 首先使用 offsetof() 宏计算出结构体中 list 成员相对于结构体首地址的偏移量。
  2. 然后使用 (char *) 把 ptr 转换为 char * 类型,方便执行指针运算。这里使用的是 char * 而不是其他类型的指针,是因为 char 类型的大小为 1 字节,所以可以精确计算出指针偏移量。
  3. 对 ptr 进行指针减法运算,结果为 &(some_struct) - offsetof(struct my_struct, list)。也就是说,这里减去了 list 成员相对于整个结构体首地址的偏移量,从而得到了整个结构体的首地址。
  4. 最后使用 (type *) 把结果强制转换为结构体类型 struct my_struct *,即可得到整个结构体的地址。

需要注意的是,container_of() 的使用必须保证 ptr 指向的是某个结构体成员,否则计算结果将不正确。另外,该宏也不支持嵌套结构体。

5)wait_for_completion() 函数

是 Linux 内核中的一个同步原语,它用于等待一个完成量被另一个进程或线程完成。等待队列和 completion 结构体在 Linux 内核中被广泛使用,比如读写锁、自旋锁、信号量、定时器等都会用到它们。

在调用 wait_for_completion() 函数之前,首先要初始化一个 completion 结构体,而这个结构体通常被作为一个等待队列中的头结点使用,用于等待某个事件的完成。

当一个线程或进程执行 wait_for_completion() 函数时,如果它所等待的事件还没有完成,那么就会进入睡眠状态(即挂起当前线程或进程),直到所等待的事件完成,并调用 complete() 函数告知等待队列中的所有等待者事件已经完成为止。此时 wait_for_completion() 函数才返回,线程或进程才被唤醒,接着继续执行下面的代码。

6)spin_unlock_irqrestore() 函数

是用于解锁自旋锁并恢复中断的函数。在 Linux 内核中,自旋锁是一种线程同步机制,用于保护共享资源免受并发访问的干扰。当一个线程获取了自旋锁之后,其他线程会被阻塞,直到该线程释放自旋锁。

在多核CPU系统中,中断处理程序在运行时可能会产生竞争问题。当中断处理程序需要访问被自旋锁保护的共享资源时,需要临时禁止本地CPU中断以确保同步。函数 spin_lock_irqsave() 和 spin_unlock_irqrestore() 提供了这项功能,spin_lock_irqsave() 禁止中断,并尝试获取自旋锁。spin_unlock_irqrestore() 函数则释放自旋锁,并在解锁后恢复特定的中断状态。

因此 spin_unlock_irqrestore() 函数用于解锁一个被自旋锁保护的资源,并将中断的状态恢复为调用 spin_lock_irqsave() 时的状态,以避免干扰其他需要使用该状态的程序。

7)spin_lock_irqsave() 函数

是 Linux 内核中用于获得自旋锁并且禁用中断的函数。

自旋锁是一种在多线程环境下保护共享资源的机制,当多个线程尝试往同一个共享资源中写入数据时,自旋锁能够确保同一时刻只有一个线程能够访问该资源,从而避免竞态条件的出现。

spin_lock_irqsave() 函数在获取自旋锁时会先禁止中断,确保当前 CPU 不会被切换到别的上下文中执行其他的中断处理程序。在获取自旋锁成功后,函数会返回一个无符号整数值,这个值包含了此时 CPU 执行中断的状态,以便后续使用 spin_unlock_irqrestore() 函数恢复当前 CPU 的中断状态。

8)getenv() 函数

是一个 C 标准库函数,用于获取环境变量的值。它的原型如下:

char *getenv(const char *name);

传递一个环境变量名 name,函数将返回该环境变量的值,如果该环境变量不存在,则返回 NULL。

使用方法示例:

char *path = getenv("PATH");
if (path != NULL) {
    printf("PATH=%s\n", path);
}

上述代码将获取环境变量名为 PATH 的值,并打印出来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值