linux内核网络队列,Linux驱动的等待队列、轮询及内核线程

1、简介

根据不同需求,linux内核有不同I/O操作模型:

非阻塞: 进程在不能进行设备操作时,并不挂起,它或者放弃,或者不停地查询,直到可以进行操作为止

阻塞: 指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作条件后再进行各项操作

等待队列:

用来阻塞或唤醒一个进程,实现阻塞I/O访问

轮询操作:

阻塞I/O访问的应用程序通常使用select()和poll()系统调用查询机制来实现的。

2、等待队列

等待队列在Linux内核中用来阻塞或唤醒一个进程,也可以用来同步对系统资源的访问,还可以实现延迟功能

2.1 主要方法

#include

?1.定义、初始化等待队列(指向等待队列链表)

//?定义一个等待队列头

wait_queue_head_t my_queue;

//?初始一个等待队列头

init_waitqueue_head(&my_queue);

//?定义并初始化一个等待队列头

DECLARE_WAIT_QUEUE_HEAD(my_queue);

2.进程的睡眠操作——条件睡眠

//判断condition条件,决定是否将当前进程推入等待队列

wait_event(wait_queue_head_t wq, int condition);

wait_event_interruptible(wait_queue_head_t wq,int condition);

wait_event_timeout(wait_queue_head_t wq, int condition, long timeout);

wait_event_interruptiblble_timeout(wait_queue_head_t wq, int condition, long timeout);

数wq:表示等待队列头

数condition:阻塞条件,为假(0)则进入休眠直到wake_up且condition为真条件成立才退出

数timeout:表示睡眠指定时长(时钟滴答度量,eg.延时2秒=2*HZ)后,自动转入唤醒状态

3.进程的睡眠操作——无条件睡眠

//将当前进程推入等待队列将其睡眠,wake_up唤醒

sleep_on(wait_queue_head_t *q);

interruptible_sleep_on(wait_queue_head_t *q);

long sleep_on_timeout(wait_queue_head_t *q, long timeout);

long interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout);

wq:表示等待队列头

timeout:表示睡眠指定时长后,自动转入唤醒状态

4.进程唤醒函数

wake_up(wait_queue_head_t *wq);

wake_up_interruptible(wait_queue_head_t *wq)

注意事项:

1.唤醒函数和导致睡眠函数要配对使用,如果导致睡眠函数使用带interruptible的,则唤醒函数也要使用interruptible的。

2.在使用wake_up唤醒进程之前要将wait_event中的condition变量的值赋为真,否则该进程被唤醒后会立即再次进入睡眠

3、轮询操作

轮询操作:应用程序通常会使用select()系统调用查询是否可对设备进行无阻塞的访问。

该函数通过系统调用最终会引发设备驱动中的poll()函数被执行

该机制还可以实现一个用户进程对多个设备驱动文件的监测

3.1 驱动层方法

//poll是file_operation的回调方法 为file_operation成员之一

static unsigned int poll(struct file *file, struct poll_table_struct *wait)

?参数file:是文件结构指针

?参数wait:轮询表指针,管理着一系列等待列表

//添加等待队列到wait参数指定的轮询列表中

void poll_wait(struct file *filp, wait_queue_heat_t *wq, poll_table *wait);

poll_wait()将可能引起文件状态变化的进程添加到轮询列表,由内核去监听进程状态的变化,不会阻塞进程

一旦进程有变化(wake_up),内核就会自动去调用poll() 而poll()是返回给select()的

所以当进程被唤醒以后,poll()应该将状态掩码返回给select(),从而select()退出阻塞。

完成一次监测,poll函数被调用一次或两次:

第一次为用户执行select函数时被执行

第二次调用poll为内核监测到进程的wake_up操作时或进程休眠时间到唤醒再或被信号唤醒时

poll函数返回的状态掩码

?可读状态掩码

POLLIN:有数据可读

POLLRDNORM:有普通数据可读

POLLRDBAND:有优先数据可读

POLLPRI:有紧迫数据可读

?可写状态掩码

POLLOUT:写数据不会导致阻塞

POLLWRNORM:写普通数据不会导致阻塞

POLLWRBAND:写优先数据不会导致阻塞

POLLMSG/SIGPOLL:消息可用

错误状态掩码

POLLER:指定的文件描述符发生错误

POLLHUP:指定的文件描述符挂起事件

POLLNVAL:指定的文件描述符非法

3.2 应用层方法

//文件描述符集合的变量的定义

fd_set fds;

//清空描述符集合

FD_ZERO(fd_set *set);

//加入一个文件描述符到集合中

FD_SET(int fd, fd_set *set);

//从集合中清除一个文件描述符

FD_CLR(int fd, fd_set *set);

//判断文件描述符是否被置位

FD_ISSET(int fd, fd_set *set);

返回非0,表示置位(该文件描述集合中有文件可进行读写操作,或产

生错误)

#include

//?在应用程序中调用的文件描述符监测函数

int select(

int numfds, //待监听中最大描述符值加一

fd_set *readfds, //监听读操作的文件描述符集合

fd_set *writefds, //监听写操作的文件描述符集合

fd_set *exceptfds, //监听异常处理的文件描述符集

struct timeval *timeout);// 监听等待超时退出select()

demo 基于itop4412

4、内核线程

1 内核线程类似于用户进程,通常用于并发处理些工作,它是一种在内核空间实现后台任务的方式,并且可以参与时间片轮转调度

2 内核线程可以进行繁忙的异步事件处理,也可以睡眠等待某事件的发生,内核线程可以访问内核函数和数据结构

3 很多设备驱动程序都是用了内核线程来完成辅助任务

4 用户使用ps命令可以查看系统中正在运行的内核线程(也称内核进程)

4.2、使用流程

1 定义一个线程指针

2 编写线程函数

3 创建线程

4 开启线程

5 ?内核线程的实现流程

6 停止线程(需接受)

4.3、主要方法

#include

1 内核线程的创建及开启

struct task_struct *kernel_thread; //定义线程指针?创建内核线程( 方法一),返回值为创建线程的指针

struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,const char namefmt[], ...);

threadfn:线程函数指针,线程开启后将运行此函数

data:函数参数data,传递给线程函数

namefmt:线程名称,这个函数可以像printk一样传入某种格式的线程名

内核线程创建后不会马上运行,需要通过以下函数启动

//启动线程

int wake_up_process(struct task_struct *p);

创建内核线程函数并运行( 方法二)

kthread_run(threadfn, data, namefmt, ...); //宏

2 内核线程的停止

//停止线程检测函数 (线程函数内使用)

int kthread_should_stop(void)

接收到停止信号,返回true

//停止内核线程函数 (线程函数外使用)

int kthread_stop(struct task_struct *k);

1.该函数发送信号给内核线程,如果线程函数不检测信号也不返回,那么此函数它将一直进行等待

2.在调用kthread_stop函数时,线程函数不能已经运行结束,否则,kthread_stop函数会一直进行等待。

3 线程函数的运行

//线程函数,内核线程开启后会运行该函数

int threadfunc(void *data);

1.该函数由用户自己实现,函数格式如上所示

2.该函数必须能让出CPU,以便其他线程能够得到执行,也必须能重新得到调度

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值