对数据包进行进一步处理的TmThreadsSlotVarRun函数原型如下:
TmEcode TmThreadsSlotVarRun(ThreadVars *tv, Packet *p,TmSlot *slot)
按照函数头的注释说明,这个函数被从母函数中拉出来独立存在的原因是,为了能够对其进行递归调用。函数主流程是一个遍历所有slot的for循环,
/**
* \brief Separate run function so we can call it recursively.
*
* \todo Deal with post_pq for slots beyond the first.
*/
TmEcode TmThreadsSlotVarRun(ThreadVars *tv, Packet *p,
TmSlot *slot)
{
TmEcode r;
TmSlot *s;
Packet *extra_p;
for (s = slot; s != NULL; s = s->slot_next) {
TmSlotFunc SlotFunc = SC_ATOMIC_GET(s->SlotFunc);
/*获取 SlotFunc函数(类似于DecodePcap这种,注册时挂在全局变量
tmm_modules[TMM_DECODEPCAP].Func上)*/
PACKET_PROFILING_TMM_START(p, s->tm_id);
if (unlikely(s->id == 0)) {
r = SlotFunc(tv, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, &s->slot_post_pq);
} else {
r = SlotFunc(tv, p, SC_ATOMIC_GET(s->slot_data), &s->slot_pre_pq, NULL);
}
//调用slot的处理函数SlotFunc
PACKET_PROFILING_TMM_END(p, s->tm_id);
/* handle error */
if (unlikely(r == TM_ECODE_FAILED)) {
/* Encountered error. Return packets to packetpool and return */
TmqhReleasePacketsToPacketPool(&s->slot_pre_pq);
SCMutexLock(&s->slot_post_pq.mutex_q);
TmqhReleasePacketsToPacketPool(&s->slot_post_pq);
SCMutexUnlock(&s->slot_post_pq.mutex_q);
TmThreadsSetFlag(tv, THV_FAILED);
return TM_ECODE_FAILED;
/*若调用SlotFunc返回失败,则调用TmqhOutputPacketpool将数据包(以及各个slot的
slot_post_pq中的数据包)进行回收或释放。然后设置线程标志为THV_FAILED,等待主线程处理*/
}
/* handle new packets */
while (s->slot_pre_pq.top != NULL) {
extra_p = PacketDequeue(&s->slot_pre_pq);
if (unlikely(extra_p == NULL))
continue;
/* see if we need to process the packet */
if (s->slot_next != NULL) {
r = TmThreadsSlotVarRun(tv, extra_p, s->slot_next);
if (unlikely(r == TM_ECODE_FAILED)) {
TmqhReleasePacketsToPacketPool(&s->slot_pre_pq);
SCMutexLock(&s->slot_post_pq.mutex_q);
TmqhReleasePacketsToPacketPool(&s->slot_post_pq);
SCMutexUnlock(&s->slot_post_pq.mutex_q);
TmqhOutputPacketpool(tv, extra_p);
TmThreadsSetFlag(tv, THV_FAILED);
return TM_ECODE_FAILED;
}
}
/*若调用SlotFunc返回成功,则继续处理slot_pre_pq:对其中每个数据包,都递归调用
TmThreadsSlotVarRun,将其送入下一个slot进行处理。
注: slot_pre_pq vs. slot_post_pq: 某个slot在处理某个母数据包时新产生的子数据包,若放入
slot_pre_pq中,则这个数据包将在本个slot处理完母数据包后,在后续slot处理母数据包之前,
先将这些子数据包放到后续的slot去处理;而如果是放如slot_post_pq,则需要等到母数据包被所有
slot都处理完后,在下一个数据包处理之前,再去集中处理*/
tv->tmqh_out(tv, extra_p);
/*则调用tmqh_out将数据包extra_p送到后续队列中去。在这里会通过队列交给
FlowWorker线程来处理*/
}
}
return TM_ECODE_OK;
}