Linux驱动笔记(二.API篇)


前言

本文主要记录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>

下面是一个一般的步骤示例,展示了如何在驱动程序中创建并使用一个等待队列:

  1. 定义等待队列头: 在驱动的数据结构中定义一个等待队列头。这通常在设备结构体中进行,用于跟踪与特定设备相关的等待队列。
#include <linux/wait.h>

struct my_device_data {
    // ... 其他设备数据成员 ...
    wait_queue_head_t wait_queue;
};
  1. 初始化等待队列头: 在设备初始化过程中,使用init_waitqueue_head函数初始化等待队列头。
struct my_device_data my_dev;

void device_init(void) {
    // ... 其他初始化操作 ...
    init_waitqueue_head(&my_dev.wait_queue);
}
  1. 等待和唤醒: 在需要等待某个条件满足的地方,可以使用wait_eventwait_event_interruptible等函数来阻塞当前进程,直到条件满足。
// 在某个地方等待条件满足
wait_event_interruptible(my_dev.wait_queue, condition);
  1. 唤醒等待队列: 在另一个地方,当条件满足时,通过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提供了大量能使我们快速便捷地处理数据的函数和方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值