vxWorks中延后执行任务队列(workQ)
来源:互联网 发布:网络舆情分析师待遇 编辑:程序博客网 时间:2024/05/29 18:35
在多核系统中为每一个cpu设置了一个如下的结构体,分别记录了当前核的运行的任务ID,延后执行任务
队列,延后任务队列是否为空等重要信息。
系统每次获取具体的延后执行任务时,就是从这里进行获取的。
再看一下对于这个任务延后执行队列的初始化:
函数调用:
1,设置了这个环形队列( WORK_Q_IX)的大小为0x0b
2,设置 WORK_Q_IX->read 为0
3,设置 WORK_Q_IX->write 为0
OK,初始化完成了下面在看看怎么把任务存放进去,以及怎么获取到。
先展示一下对这个修改这个结构体的宏操作:
typedef struct
{
volatile UINT32 read; /* workQ read index */
UINT32 bitmask; /* workQ index bitmask */
volatile UINT32 write; /* workQ write index */
} WORK_Q_IX;
这个环形区由三个成员组成,read,write,bitmask,其中read表示要读取的任务的index,write记录写入的任务的index,bitmask就表示这个环形区的大小。
每次插入一个任务时,write都增加1,但是这个值的 大小不会超过bitmask的值,也就是这个write再一个环形区中循环而当write再写入时等于read拉,就说明这个环形区满了;而read呢,每次读取一个任务时,read加1,最后当read==wirte时,也就执行完所有的任务了。
如下面这图所示:read和write都是从0开始,然后递增,大小由bitmask指定。
队列,延后任务队列是否为空等重要信息。
#define VX_MAX_SMP_CPUS 4WIND_VARS _WRS_VX_KERNEL_VARS_SECTION_ATTR vxKernelVars[VX_MAX_SMP_CPUS];
typedef struct _windVars { WIND_TCB *cpu_taskIdCurrent;/* 0x00: current task ID */ ISR_IDcpu_isrIdCurrent;/* 0x04: current ISR ID */ intcpu_errno;/* 0x08: errno location (for ISRs) */ intcpu_intCnt;/* 0x0c: interrupt nesting count */ intcpu_windPwrOffState;/* 0x10: power management state */ char *cpu_vxIntStackBase;/* 0x14: interrupt stack base */ char *cpu_vxIntStackEnd;/* 0x18: interrupt stack end */ WORK_Q_IX cpu_workQIx; /* 0x1c: read, 0x20: bitmask, */ /* 0x24: write */ volatile BOOL cpu_workQIsEmpty; /* 0x28: each workQ status */ atomic_t cpu_spinLockIsrCnt; /* 0x2c: counting help spinlocks */ atomic_t cpu_spinLockTaskCnt; /* 0x30: counting help spinlocks */ WIND_TCB * cpu_idleTaskId; /* 0x34: idle task ID */ BOOLcpu_kernelIsIdle;/* 0x38: kernel idle state */ int cpu_reschedMode; /* 0x3c: call "reschedule()" or not */ atomicVal_t cpu_my_tkt;/* 0x40: ticket for kernel lock */ char *cpu_reserved1;/* 0x44: Reserved field one */ char *cpu_reserved2;/* 0x48: Reserved field two */#ifdef _WRS_WIND_VARS_ARCH /* * _WRS_WIND_VARS_ARCH macro-definition can be used for specifying * architecture an specific fields for WIND_VARS. */ _WRS_WIND_VARS_ARCH;/* 0x4c: architecture specific */#endif /* _WRS_WIND_VARS_ARCH */ } _WIND_VARS _WRS_DATA_ALIGN_BYTES (_WRS_WIND_VARS_ALIGN);
typedef struct windVars { _WIND_VARS vars; } WIND_VARS;
下面这个结构体构成了对延后任务队列的记录工作:具体原理后面会说到
typedef struct { volatile UINT32 read;/* workQ read index */ UINT32 bitmask; /* workQ index bitmask */ volatile UINT32 write; /* workQ write index */ } WORK_Q_IX;不出所料,这个任务池时全局的,这是一个2维数组,可以分别为每个核记录64个延后执行的任务。
系统每次获取具体的延后执行任务时,就是从这里进行获取的。
#define WIND_JOBS_MAX 64#define VX_MAX_SMP_CPUS 4JOB pJobPool [WIND_JOBS_MAX][VX_MAX_SMP_CPUS];
typedef struct/* JOB */ { FUNCPTR function;/* 00: function to invoke */ intarg1;/* 04: argument 1 */ int arg2;/* 08: argument 2 */ UINT isrTag;/* 12: tag of ISR that queued up work */ } JOB;好,到这里就知道延迟后的任务其实都存储在pJobPool这个任务池之中,但是要获取时的ID号呢就存储在vxKernelVars-->cpu_workQIx之中,就可以了,这样就和每个cpu对应起来了。
再看一下对于这个任务延后执行队列的初始化:
函数调用:
usrInit-->usrKernelInit-->workQInit初始化都做了什么呢?
1,设置了这个环形队列( WORK_Q_IX)的大小为0x0b
2,设置 WORK_Q_IX->read 为0
3,设置 WORK_Q_IX->write 为0
void workQInit ( UINT queueSize/* size of the work queue in jobs */ ) { UINT8 msb;/* most significant bit set in queueSize */ UINT32 bitMask;#ifdef _WRS_CONFIG_SMP int ix = 0;#endif /* _WRS_CONFIG_SMP *//*这里的两行是计算这个mask值,最后得到的值为0x0b,这里了解这个环形区大小为mask就行,不需要知道具体过程*/ msb = (UINT8) (ffsMsb((UINT32) min (0x10000, queueSize)) - 1); bitMask = (1 << msb) - 1; workQWorkInProgress = WORKQ_WORK_NOT_IN_PROGRESS;/*如果是多核,就每个核都进行初始化*/#ifdef _WRS_CONFIG_SMP for (; ix < _WRS_CPU_CONFIGURED (); ix++) {#endif /* _WRS_CONFIG_SMP */ _WRS_KERNEL_CPU_GLOBAL_SET (ix, workQIsEmpty, TRUE);WORKQ_IX_SET (ix, bitmask, bitMask); WORKQ_IX_SET (ix, write, 0); WORKQ_IX_SET (ix, read, 0);#ifdef _WRS_CONFIG_SMP }#endif /* _WRS_CONFIG_SMP */ }
OK,初始化完成了下面在看看怎么把任务存放进去,以及怎么获取到。
先展示一下对这个修改这个结构体的宏操作:
/*获取任务*/#define WORKQ_JOB_GET(cpuid, index)\ (*(pJobPool + index) + cpuid)/*设置wirteIx,记录有任务延后执行*/#define WORKQ_IX_SET(cpuid, globMemb, var)\ _WRS_KERNEL_CPU_GLOBAL_SET(cpuid, workQIx.globMemb, var)# define _WRS_KERNEL_CPU_GLOBAL_SET(cpuid, glob, var)\ vxKernelVars[cpuid].vars.cpu_##glob = var/*读取readIx,通过这个得到对应的任务*/#define WORKQ_IX_GET(cpuid, globMemb)\ _WRS_KERNEL_CPU_GLOBAL_GET(cpuid, workQIx.globMemb)# define _WRS_KERNEL_CPU_GLOBAL_GET(cpuid, glob)\ vxKernelVars[cpuid].vars.cpu_##glob添加任务函数:
void workQAdd0 ( FUNCPTR func /* function to invoke */ ) { int level = KERNEL_INT_CPU_LOCK(); int cpuid = _WRS_CPU_INDEX_GET (); UINT32 writeIx = WORKQ_IX_GET (cpuid, write); JOB * pJob = WORKQ_JOB_GET (cpuid, writeIx); UINT32 bitMask; bitMask = WORKQ_IX_GET (cpuid, bitmask);/*这里核mask进行与操作,就是严格按照初始化时的大小来进行设置,以防越过大小*/ writeIx = (writeIx + 1) & bitMask;/*设置对应cpu结构体中的write,就是延后一位,也就是指向下一个为空的位,记录有一个任务延后执行了*/ WORKQ_IX_SET (cpuid, write, writeIx);/*如果write==read说明以及满了*/ if (writeIx == WORKQ_IX_GET(cpuid, read))workQPanic (); /* panic while intLocked *//*设置vxKernelVars->workQIsEmpty为false,告诉cpu有任务延后执行*/ _WRS_KERNEL_CPU_GLOBAL_SET (cpuid, workQIsEmpty, FALSE);/*记录任务*/ pJob->function = func;/* fill in function */ WORKQ_ISR_TAG_SET (cpuid, pJob); }
执行延后任务队列中任务的函数:
/*执行延后执行的任务*/void workQDoWork (void) { JOB *pJob; int oldErrno; UINT32 readIx; int cpuid = _WRS_CPU_INDEX_GET (); int intCtx; UINT32 bitMask = WORKQ_IX_GET (cpuid, bitmask); intCtx = _WRS_KERNEL_CPU_GLOBAL_GET (cpuid, intCnt); /*判断是否时中断嵌套*/ if (intCtx){oldErrno = _WRS_KERNEL_CPU_GLOBAL_GET (cpuid, errno);} else{workQWorkInProgress = cpuid;}/*判断是否已经空了,当read=write时,环形区为空,如果不为空就获取任务,并使read指向下一个任务,并执行取出来的任务,最后设置vxKernelVars->workQIsEmpty为true,告诉cpu这个队列中的任务已经i执行完毕*/ while ((readIx = WORKQ_IX_GET(cpuid, read)) != WORKQ_IX_GET(cpuid, write)){pJob = WORKQ_JOB_GET(cpuid, readIx); /* get job */readIx = (readIx + 1) & bitMask;WORKQ_IX_SET (cpuid, read, readIx); (FUNCPTR *)(pJob->function) (pJob->arg1, pJob->arg2);_WRS_KERNEL_CPU_GLOBAL_SET(cpuid, workQIsEmpty, TRUE);} }说一说这个记录任务的环形区的使用。
typedef struct
{
volatile UINT32 read; /* workQ read index */
UINT32 bitmask; /* workQ index bitmask */
volatile UINT32 write; /* workQ write index */
} WORK_Q_IX;
这个环形区由三个成员组成,read,write,bitmask,其中read表示要读取的任务的index,write记录写入的任务的index,bitmask就表示这个环形区的大小。
每次插入一个任务时,write都增加1,但是这个值的 大小不会超过bitmask的值,也就是这个write再一个环形区中循环而当write再写入时等于read拉,就说明这个环形区满了;而read呢,每次读取一个任务时,read加1,最后当read==wirte时,也就执行完所有的任务了。
如下面这图所示:read和write都是从0开始,然后递增,大小由bitmask指定。
(时机总结可能不全面)
执行的时机:
1,再调度函数中,选择任务先执行延后执行任务队列中的任务
2,中断返回
阅读全文
0 0
- vxWorks中延后执行任务队列(workQ)
- 关于延后执行
- vxWorks中就绪队列小结
- vxworks中任务间的通信支持信号量、消息队列、管道、信号、事件、共享内存等
- vxworks中任务间的通信支持信号量、消息队列、管道、信号、事件、共享内存等
- vxworks中任务间的通信支持信号量、消息队列、管道、信号、事件
- vxworks中任务间的通信支持信号量、消息队列、管道、信号、事件、共享内存等
- 任务队列执行结构
- 理解GCD中任务和队列执行的原理
- VxWorks 任务
- VxWorks 任务
- VxWorks 任务
- VxWorks任务编程中常见异常分析
- VxWorks任务编程中常见异常分析
- VxWorks任务编程中常见异常分析
- vxworks下任务间消息队列通信例程
- 【VxWorks系列】任务间同步与通信之消息队列
- 异步任务执行之-队列
- JS中JSON字符串转JSON对象
- 有关Apache Storm设置tick的相关的坑
- django-缓存的使用
- 【leetcode】454. 4Sum II 总结
- 软件功耗总公式
- vxWorks中延后执行任务队列(workQ)
- mysql 对时间进行操作
- Matesploit在中文版系统上安装出错解决方法
- HDU 6077 Time To Get Up -暴力枚举-2017多校联盟4 第11题
- 面向对象 练习题1
- data类型的Url格式--url(data:image/gif;base64,AAAA):把小数据直接嵌入到Url中
- 1.11.ARM的37个寄存器详解
- spring事务回滚的部分说明及出现问题解决
- Java中的final修饰符