文章目录
前言
本文主要记录linux驱动下用到的api及宏
宏定义类
__init
:配置驱动入口函数
int __init imx6uirq_init(void)
//#################################
__section(.init.text) __cold notrace
1. section:通过lds,定义到.init.txt段
2. cold:冷代码,表示函数很少调用,为了减少cache污染
3. notrace 配置函数钩子?(待验证)
__exit
:配置驱动出口函数
void __exit imx6uirq_exit(void)
//#################################
__section(.init.text) __cold notrace
1. section:通过lds,定义到.exit.text段
2. cold:冷代码,表示函数很少调用,为了减少cache污染
3. notrace 配置函数钩子?(待验证)
进程锁类
用于提供共享资源保护
atomic
原子操作
函数 | 功能 |
---|---|
ATOMIC_INIT(int i) | 初始化原子变量,如atomic_t v = ATOMIC_INIT(0); |
int atomic_read(atomic_t *v) | 读取 v 的值,并且返回 |
void atomic_set(atomic_t *v, int i) | 向 v 写入 i 值 |
void atomic_add(int i, atomic_t *v) | 给 v 加上 i 值 |
void atomic_sub(int i, atomic_t *v) | 从 v 减去 i 值 |
void atomic_inc(atomic_t *v) | 给 v 加 1,也就是自增 |
void atomic_dec(atomic_t *v) | 从 v 减 1,也就是自减 |
int atomic_dec_return(atomic_t *v) | 从 v 减 1,并且返回 v 的值 |
int atomic_inc_return(atomic_t *v) | 给 v 加 1,并且返回 v 的值 |
int atomic_sub_and_test(int i, atomic_t *v) | 从 v 减 i,如果结果为 0 就返回真,否则返回假 |
int atomic_dec_and_test(atomic_t *v) | 从 v 减 1,如果结果为 0 就返回真,否则返回假 |
int atomic_inc_and_test(atomic_t *v) | 给 v 加 1,如果结果为 0 就返回真,否则返回假 |
int atomic_add_negative(int i, atomic_t *v) | 给 v 加 i,如果结果为负就返回真,否则返回假 |
spinlock
自旋锁
自旋锁的基本结构
一般先获取锁再设置变量
函数 | 功能 |
---|---|
int spin_lock_init(spinlock_t *lock) | 初始化一个自选锁 |
void spin_lock(spinlock_t *lock) | 获取指定的自旋锁,也叫做加锁 |
void spin_unlock(spinlock_t *lock) | 释放指定的自旋锁 |
int spin_trylock(spinlock_t *lock) | 尝试获取指定的自旋锁,如果没有获取到就返回 0 |
int spin_is_locked(spinlock_t *lock) | 检查指定的自旋锁是否被获取,如果没有被获取就返回非 0,否则返回 0 |
void spin_lock_irqsave(spinlock_t *lock,unsigned long flags) | 保存中断状态,禁止本地中断,并获取自旋锁 |
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) | 将中断状态恢复到以前的状态,并且激活本地中断,释放自旋锁 |
semaphore
信号量
使用基本流程
struct semaphore sem; /* 定义信号量 */
sema_init(&sem, 1); /* 初始化信号量 */
down(&sem); /* 申请信号量 */
/* 临界区 */
up(&sem); /* 释放信号量 */
mutex
互斥锁
互斥锁的基本结构,主要定义了一个原子变量以及一个自旋锁
主要的使用API如下
函数 | 功能 |
---|---|
DEFINE_MUTEX(name) | 定义并初始化一个 mutex 变量 |
void mutex_init(mutex *lock) | 初始化 mutex |
void mutex_lock(struct mutex *lock) | 获取 mutex,也就是给 mutex 上锁。如果获取不到就进休眠 |
void mutex_unlock(struct mutex *lock) | 释放 mutex,也就给 mutex 解锁 |
int mutex_trylock(struct mutex *lock) | 尝试获取 mutex,如果成功就返回 1,如果失败就返回 0 |
int mutex_is_locked(struct mutex *lock) | 判断 mutex 是否被获取,如果是的话就返回1,否则返回 0 |
int mutex_lock_interruptible(struct mutex *lock) | 使用此函数获取信号量失败进入休眠以后可以被信号打断 |
定时器
函数 | 功能 |
---|---|
#define init_timer(timer) | 初始化定时器,形参 struct timer_list *timer |
void add_timer(struct timer_list *timer) | 向 Linux 内核注册定时器,使用 add_timer以后,定时器就会开始运行 |
进程状态类
__set_current_state
设置当前进程状态
void __set_current_state(unsigned long state);
其中,state参数表示新的进程状态,它应该是以下宏之一:
TASK_RUNNING
:表示进程正在运行或可运行。
TASK_INTERRUPTIBLE
:表示进程处于可中断的等待态,即进程正在等待某个事件的发生,如果收到一个信号,进程会被唤醒。
TASK_UNINTERRUPTIBLE
:表示进程处于不可中断的等待态,即进程正在等待某个事件的发生,但即使收到一个信号,进程也不会被唤醒。
TASK_STOPPED
:表示进程被停止。
通过调用__set_current_state函数,可以将当前进程的状态设置为指定的值。这通常在内核中的等待操作中使用,以便将进程置于适当的等待状态,使得调度器可以根据进程状态来决定下一步的调度行为。
进程同步&通信类
wait_queue
等待列队
在驱动中实现poll,select,epoll等功能,使用的api,位于头文件<linux/wait.h>
下面是一个一般的步骤示例,展示了如何在驱动程序中创建并使用一个等待队列:
- 定义等待队列头: 在驱动的数据结构中定义一个等待队列头。这通常在设备结构体中进行,用于跟踪与特定设备相关的等待队列。
#include <linux/wait.h>
struct my_device_data {
// ... 其他设备数据成员 ...
wait_queue_head_t wait_queue;
};
- 初始化等待队列头: 在设备初始化过程中,使用
init_waitqueue_head
函数初始化等待队列头。
struct my_device_data my_dev;
void device_init(void) {
// ... 其他初始化操作 ...
init_waitqueue_head(&my_dev.wait_queue);
}
- 等待和唤醒: 在需要等待某个条件满足的地方,可以使用
wait_event
或wait_event_interruptible
等函数来阻塞当前进程,直到条件满足。
// 在某个地方等待条件满足
wait_event_interruptible(my_dev.wait_queue, condition);
- 唤醒等待队列: 在另一个地方,当条件满足时,通过
wake_up
函数来唤醒等待队列中的进程。
// 在某个地方唤醒等待队列中的进程
wake_up(&my_dev.wait_queue);
总之,内核并不会自动知道新的等待队列的创建。你需要在适当的地方初始化等待队列头,然后在需要等待和唤醒的地方使用等待队列。这通常在设备驱动的上下文中进行,以确保正确的同步和通信。
poll_wait
用在驱动中的poll函数中,实现应用层面的select,poll功能
void poll_wait(struct file *filp, wait_queue_head_t *queue, poll_table *p);
*filp:指向相关文件的指针。通常是由驱动程序中的 open 或 poll 方法传递的文件指针。
*queue:等待队列的头指针。等待队列是一种数据结构,用于管理等待特定事件发生的进程或线程。
*p:指向 poll_table 结构的指针,包含了与等待事件相关的信息
fasync_helper
注册&注销异步通知处理函数
一般用于驱动中的fsync函数中,用于实现驱动的异步功能
#define fasync_helper(filp, fd, fa, flag) \
({ \
int __retval = 0; \
if ((flag)) { \
__retval = fasync(fd, filp, 1); \
if (__retval >= 0) \
atomic_set(&(fa)->fa_flags, 1); \
} else { \
if (atomic_read(&(fa)->fa_flags)) \
__retval = fasync(fd, filp, 0); \
atomic_set(&(fa)->fa_flags, 0); \
} \
__retval; \
})
fasync_helper 宏接受四个参数:
filp:指向相关文件的指针。
fd:文件描述符。
fa:指向 fasync_struct 结构体的指针,用于管理异步通知。
flag:指示是否注册异步通知处理函数的标志,为非零值表示注册,为零表示注销
fasync_helper
宏的作用是根据 flag
的值来注册或注销异步通知处理函数,并在注册成功后设置 fa_flags
标志位。如果 flag 为非零值,表示需要注册异步通知,宏内部会调用 fasync 函数注册,并使用 atomic_set 函数设置 fa_flags 为 1。如果 flag
为零,表示需要注销异步通知,宏内部会首先检查 fa_flags 是否为 1,若是,则调用 fasync
函数注销,并使用 atomic_set 函数将 fa_flags
设置为 0
kill_fasync
用于向异步通知队列中的进程发送信号以通知它们发生了异步事件
int kill_fasync(struct fasync_struct **fa, int sig, int band);
**fa:指向异步通知结构体指针的指针。通过该参数,函数可以遍历异步通知链表,
并向每个异步通知结构体所关联的进程发送信号。
sig:要发送的信号的值。通常使用预定义的信号常量,如 SIGIO。
band:信号发送的带号(band)。在一些特定的异步通知机制中,不同的事件可能被分成多个带号,
这个参数用于指定要发送信号的带号。大多数情况下,可以将其设置为 0。
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。