###一. 网络数据异步处理简介
SylixOS中为了解决网络数据拥堵的问题,采取数据异步处理的方式,提供了网络工作队列。采用网络工作队列,可以使得网卡驱动程序无需阻塞等待处理完成。
SylixOS内核网络netdev封装了函数netdev_notify,提供了使用网络工作队列处理网卡数据的功能。
###二. 网络异步处理工作队列初始化
系统初始化时会调用函数_netJobqueueInit
创建网络驱动作业处理队列。网络驱动作业处理队列是通过系统异步工作队列来实现的。
netJobqueueInit函数执行流程如下:
- 获取系统配置
LW_CFG_LWIP_JOBQUEUE_NUM
,得到系统配置的可以并行工作的netjob个数,存入全局变量_G_uiJobqNum
中; - 比较
_G_uiJobqNum
和CPU核数,_G_uiJobqNum
不能超过CPU核数; - 对每个工作队列调用
_jobQueueInit
函数进行初始化; - 对每个工作队列创建job处理线程
_NetJobThread
。
###三. 网络异步处理线程
网络异步处理线程_NetJobThread
的工作非常简单,死循环执行函数_jobQueueExec
,执行工作队列中的工作。
_jobQueueExec
函数执行流程如下:
- 死循环等待二进制信号量,一旦发现工作队列中存在未处理数据,则退出循环;
- 根据工作队列中未处理数据个数,循环调用注册的异步处理回调函数进行数据处理工作;
- 处理完成后,修改工作队列中待处理数据计数值。
###四. 加入网络异步处理工作队列
SylixOS提供API_NetJobAdd
和API_NetJobAddEx
两个API接口实现了添加网络异步处理工作队列的功能。
函数API_NetJobAdd
通过调用内核添加工作队列接口函数_jobQueueAdd
,实现添加工作队列到0号网络工作队列中。函数API_NetJobAddEx
则提供了扩展功能,可以指定添加工作队列的编号。
函数_jobQueueAdd
根据函数API_NetJobAdd
传入的回调函数和参数注册到工作队列中,增加待处理数据计数值,同时释放二进制信号量。网络异步处理线程接收到此二进制信号量后调用回调函数进行数据处理。
###五. 删除网络异步处理工作队列
SylixOS提供API_NetJobDelete
和API_NetJobDeleteEx
两个API接口实现删除网络异步处理工作队列。
函数API_NetJobDelete
通过调用内核删除工作队列接口函数_jobQueueDel
,实现删除0号网络工作队列中的一个工作。函数API_NetJobDeleteEx
则提供了扩展功能,可以指定删除工作队列的编号。
函数_jobQueueDel
从工作队列中删除一个工作采用的是懒惰删除方式,也即根据传入参数,从当前记录的最近处理完成的工作队列编号之后,找到第一个匹配的一条工作队列并将其删除。
###六. 网络异步处理工作队列应用
SylixOS中提供的网络异步处理工作队列主要应用于网卡接收数据的处理问题,SylixOS封装的netdev层,提供了函数netdev_notify
和函数netdev_notify_ex
供驱动程序使用。
以MPC8313网卡驱动为例,介绍函数netdev_notify
的使用方法。程序代码示例如程序清单 6.1所示。
程序清单 6.1 异步处理示例代码
#include "SylixOS.h"
/****************************************************************
** 函数名称: __eTSECRxIsr
** 功能描述: 接收中断
** 输 入 : pvArg : 中断参数
** uiVector : 中断向量号
** 输 出 : NONE
** 返 回 : LW_IRQ_HANDLED : 正常处理
** LW_IRQ_NONE : 处理异常
****************************************************************/
static irqreturn_t __eTSECRxIsr (PVOID pvArg, UINT32 uiVector)
{
netdev_t *pNetDev = (netdev_t *)pvArg;
__PENET pEnet;
UINT32 uiIevent;
UINT32 uiImask;
UINT32 uiBaseaddr;
pEnet = pNetDev->priv;
uiBaseaddr = pEnet->uiBaseaddr;
uiIevent = read32(REG_ETSEC_IEVENT(uiBaseaddr));
uiImask = read32(REG_ETSEC_IMASK(uiBaseaddr));
/*
* 接收成功
*/
if ((uiIevent & ETSEC_IEVENT_RXF)) {
/*
* 清除RXF位
*/
write32(uiIevent, REG_ETSEC_IEVENT(uiBaseaddr));
/*
* 关闭接收中断
*/
write32(uiImask & ~(ETSEC_IEVENT_RXF), REG_ETSEC_IMASK(uiBaseaddr));
/*
* 通知系统进行接收
*/
netdev_notify(pNetDev, LINK_INPUT, 1);
}
return (LW_IRQ_HANDLED);
}
通过在接收中断中调用函数netdev_notify
,调用网络数据异步处理函数,通过内核工作队列调用到驱动接收函数,对网络数据进行处理,提高系统的运行效率。
对于多核系统,调用函数netdev_notify_ex
创建多个网络异步处理函数,同时需要注意修改内核参数LW_CFG_LWIP_JOBQUEUE_NUM
修改队列个数。