本文共 5070 字,大约阅读时间需要 16 分钟。
1 使用背景
对定时器做相关配置,使得每隔时间T,触发定时器中断,可以在定时器中断处理函数处理算法,这样就可以周期性的执行特定的任务。但如果不想在定时器中断处理函数中添加算法,比如说用户只想在应用程序里面执行他们的任务,那么钩子函数就是一个不错的选择。2 钩子函数的原理本章以定时器中断为例说明SylixOS钩子的使用方法。2.1 API_InterVectorIsr函数函数原型如程序清单 2.1程序清单 2.1#include <SylixOS>irqreturn_t API_InterVectorIsr (ULONG ulVector);API_InterVectorIsr该内核接口是向量中断的总服务入口,根据中断号得到对应的中断服务函数链表,找到具体中断服务函数。流程图如图 2.1 所示。图 2.1 中断向量处理流程从流程图可以看到,该函数入口处调用LW_CPU_INT_ENTER_HOOK。该宏的定义如程序清单 2.2所示。这就是钩子函数的调用流程,其实就是调用一个函数指针指向的函数。程序清单 2.2#define LW_CPU_INT_ENTER_HOOK(ulVector, ulNesting) \if (_K_hookKernel.HOOK_CpuIntEnter) { \_K_hookKernel.HOOK_CpuIntEnter(ulVector, ulNesting); \}2.2 钩子的设置函数
SylixOS内核提供了钩子的设置接口API_KernelHookSet,函数的实现如程序清单 2.3所示。程序清单 2.3LW_API ULONG API_KernelHookSet (LW_HOOK_FUNC hookfuncPtr, ULONG ulOpt){ INTREG iregInterLevel;iregInterLevel = __KERNEL_ENTER_IRQ(); /* 进入内核同时关闭中断 */switch (ulOpt) {case LW_OPTION_THREAD_CREATE_HOOK: /* 线程建立钩子 */ _K_hookKernel.HOOK_ThreadCreate = hookfuncPtr; break;case LW_OPTION_THREAD_DELETE_HOOK: /* 线程删除钩子 */ _K_hookKernel.HOOK_ThreadDelete = hookfuncPtr; break;case LW_OPTION_THREAD_SWAP_HOOK: /* 线程切换钩子 */ _K_hookKernel.HOOK_ThreadSwap = hookfuncPtr; break;case LW_OPTION_THREAD_TICK_HOOK: /* 系统时钟中断钩子 */ _K_hookKernel.HOOK_ThreadTick = hookfuncPtr; break;case LW_OPTION_THREAD_INIT_HOOK: /* 线程初始化钩子 */ _K_hookKernel.HOOK_ThreadInit = hookfuncPtr; break;case LW_OPTION_THREAD_IDLE_HOOK: /* 空闲线程钩子 */ _K_hookKernel.HOOK_ThreadIdle = hookfuncPtr; break;case LW_OPTION_KERNEL_INITBEGIN: /* 内核初始化开始钩子 */ _K_hookKernel.HOOK_KernelInitBegin = hookfuncPtr; break;case LW_OPTION_KERNEL_INITEND: /* 内核初始化结束钩子 */ _K_hookKernel.HOOK_KernelInitEnd = hookfuncPtr; break;case LW_OPTION_KERNEL_REBOOT: /* 内核重新启动钩子 */ _K_hookKernel.HOOK_KernelReboot = hookfuncPtr; break;case LW_OPTION_WATCHDOG_TIMER: /* 看门狗定时器钩子 */ _K_hookKernel.HOOK_WatchDogTimer = hookfuncPtr; break;case LW_OPTION_OBJECT_CREATE_HOOK: /* 创建内核对象钩子 */ _K_hookKernel.HOOK_ObjectCreate = hookfuncPtr; break;case LW_OPTION_OBJECT_DELETE_HOOK: /* 删除内核对象钩子 */ _K_hookKernel.HOOK_ObjectDelete = hookfuncPtr; break;case LW_OPTION_FD_CREATE_HOOK: /* 文件描述符创建钩子 */ _K_hookKernel.HOOK_FdCreate = hookfuncPtr; break;case LW_OPTION_FD_DELETE_HOOK: /* 文件描述符删除钩子 */ _K_hookKernel.HOOK_FdDelete = hookfuncPtr; break;case LW_OPTION_CPU_IDLE_ENTER: /* CPU 进入空闲模式 */ _K_hookKernel.HOOK_CpuIdleEnter = hookfuncPtr; break;case LW_OPTION_CPU_IDLE_EXIT: /* CPU 退出空闲模式 */ _K_hookKernel.HOOK_CpuIdleExit = hookfuncPtr; break;case LW_OPTION_CPU_INT_ENTER: /* CPU 进入中断(异常)模式 */ _K_hookKernel.HOOK_CpuIntEnter = hookfuncPtr; break;case LW_OPTION_CPU_INT_EXIT: /* CPU 退出中断(异常)模式 */ _K_hookKernel.HOOK_CpuIntExit = hookfuncPtr; break;case LW_OPTION_STACK_OVERFLOW_HOOK: /* 堆栈溢出 */ _K_hookKernel.HOOK_StkOverflow = hookfuncPtr; break;case LW_OPTION_FATAL_ERROR_HOOK: /* 致命错误 */ _K_hookKernel.HOOK_FatalError = hookfuncPtr; break;case LW_OPTION_VPROC_CREATE_HOOK: /* 进程建立钩子 */ _K_hookKernel.HOOK_VpCreate = hookfuncPtr; break;case LW_OPTION_VPROC_DELETE_HOOK: /* 进程删除钩子 */ _K_hookKernel.HOOK_VpDelete = hookfuncPtr; break;default: __KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核同时打开中断 */ _ErrorHandle(ERROR_KERNEL_OPT_NULL); return (ERROR_KERNEL_OPT_NULL);}__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核同时打开中断 */return (ERROR_NONE);
}
该函数可以设置各种类型钩子函数,由此可见,只要调用API_KernelHookSet设置中断相关的钩子函数,当进入中断入口的函数的入口时都会调用钩子。2.3 钩子函数的定义假设设置了中断的钩子函数,那么任何中断都会调用这个钩子函数。现在只关心定时器中断,因此需要用中断号来过滤不关心的中断。例程如程序清单 2.4所示。程序清单 2.4#define TIMER_INTVECTOR 69void HookFun(ULONG ulVector,ULONG ulnest){ if(TIMER_INTVECTOR != ulVector){ return;}/* 用户在此添加自己算法*//* 注意:不要调用中断上下文不能执行的语句,比如sleep,printf等*/
}
这样,系统会周期性的进入定时器中断,处理 HookFun函数。只要知道中断号,就可以不用知晓定时器驱动的实现机制,直接挂接想要处理的任务。3 参考资料《SylixOS_driver_usermanual》转载于:https://blog.51cto.com/12142768/2162820