内核工作队列
简介与原理
在内核代码中,经常希望将部分工作推迟到将来的某个时间执行,这样做的原因有很多,比如:
- 在持有锁的情况下做耗时操作。
- 希望将工作集中起来以获取批处理的性能。
- 调用了可能导致睡眠的函数。
SylixOS 内核提供了一种机制来提供延迟执行的功能,即工作队列。工作队列是将操作延期执行的一种手段。工作队列可以把工作推后,交由一个内核线程去执行,并且工作队列是执行在进程上下文中,因此工作队列可以被重新调度和抢占甚至睡眠。
一个 SylixOS 工作队列必须要调用 API_WorkQueueCreate 函数创建之后才能使用,如果创建成功,API_WorkQueueCreate 函数将返回一个工作队列的句柄。
如果需要插入一个工作到工作队列中,可以调用 API_WorkQueueInsert 函数。
当一个工作队列使用完毕之后,应该调用 API_WorkQueueDelete 函数将其删除,SylixOS 会回收该工作队列占用的内核资源。
工作队列的应用
工作队列的创建
#include <SylixOS.h>
PVOID API_WorkQueueCreate (CPCHAR pcName,
UINT uiQSize,
BOOL bDelayEn,
ULONG ulScanPeriod,
PLW_CLASS_THREADATTR pthreadattr);
函数 API_WorkQueueCreate 原型分析:
- 此函数成功返回工作队列句柄,失败返回 LW_NULL 并设置错误号。
- pcName 参数是工作队列的名称。
- uiQSize 参数是工作队列的大小。
- bDelayEn 参数是工作队列的延迟执行功能选项。
- ulScanPeriod 参数是当带有延迟执行选项时,指定服务线程的扫描周期。
- pthreadattr 参数是队列服务线程选项。
工作队列的删除
#include <SylixOS.h>
ULONG API_WorkQueueDelete (PVOID pvWQ);
函数 API_WorkQueueDelete 原型分析:
- 此函数成功返回 ERROR_NONE ,失败返回错误号。
- pvWQ 参数是工作队列句柄。
向工作队列中插入一个工作
#include <SylixOS.h>
ULONG API_WorkQueueInsert (PVOID pvWQ,
ULONG ulDelay,
VOIDFUNCPTR pfunc,
PVOID pvArg0,
PVOID pvArg1,
PVOID pvArg2,
PVOID pvArg3,
PVOID pvArg4,
PVOID pvArg5);
函数 API_WorkQueueInsert 原型分析:
- 此函数成功返回 ERROR_NONE ,失败返回错误号。
- pvWQ 参数是工作队列句柄。
- ulDelay 参数是最小延迟执行时间。
- pfunc 参数是执行函数。
- pvArg0 ~ pvArg5 参数是执行参数。 。
工作队列的清空
#include <SylixOS.h>
ULONG API_WorkQueueFlush (PVOID pvWQ);
函数 API_WorkQueueFlush 原型分析:
- 此函数成功返回 ERROR_NONE ,失败返回错误号。
- pvWQ 参数是工作队列句柄。
工作队列的状态获取
#include <SylixOS.h>
ULONG API_WorkQueueStatus (PVOID pvWQ, UINT *puiCount);
函数 API_WorkQueueStatus 原型分析:
- 此函数成功返回 ERROR_NONE ,失败返回错误号。
- pvWQ 参数是工作队列句柄。
- puiCount 参数是当前工作队列中的作业数量。
工作队列的应用场景有很多:比如需要在中断(下半部)里面要做很多的耗时操作,这时就可以把耗时的工作放到工作队列中。
以下程序展示了 SylixOS 工作队列的使用,加载此内核模块会创建了一个不带有延迟执行功能的 SylixOS 工作队列,然后向工作队列中插入了一个工作,卸载内核模块时删除工作队列。
#define __SYLIXOS_KERNEL
#include <SylixOS.h>
#include <module.h>
PVOID _G_pvWorkQueue;
static VOID __workHandler (VOID)
{
printk("work handler function.\n");
}
VOID module_init (VOID)
{
LW_CLASS_THREADATTR threadattr;
printk("WorkQueue_module init!\n");
API_ThreadAttrBuild(&threadattr,
4 * LW_CFG_KB_SIZE,
LW_PRIO_NORMAL,
LW_OPTION_THREAD_STK_CHK,
LW_NULL);
_G_pvWorkQueue = API_WorkQueueCreate("t_workqueue",
10,
FALSE,
0,
&threadattr);
if (_G_pvWorkQueue == LW_NULL) {
printk("WorkQueue create failed.\n");
return;
}
API_WorkQueueInsert(_G_pvWorkQueue,
0,
__workHandler,
LW_NULL,
LW_NULL,
LW_NULL,
LW_NULL,
LW_NULL,
LW_NULL);
}
VOID module_exit (VOID)
{
API_WorkQueueDelete(_G_pvWorkQueue);
printk("WorkQueue_module exit!\n");
}
在 SylixOS Shell 下装载模块:
#insmod ./WorkQueue.ko
WorkQueue_module init!
module WorkQueue.ko register ok, handle: 0x13338f0
work handler function.
在 SylixOS Shell 下卸载模块:
#rmmod WorkQueue.ko
WorkQueue_module exit!
module /lib/modules/WorkQueue.ko unregister ok.