/** * \brief Get a new flow * * Get a new flow. We're checking memcap first and will try to make room * if the memcap is reached. * * \param tv thread vars * \param dtv decode thread vars (for flow log api thread data) * * \retval f *LOCKED* flow on succes, NULL on error. */ static Flow *FlowGetNew(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p) { Flow *f = NULL; if (FlowCreateCheck(p) == 0) { return NULL; } /* get a flow from the spare queue */ f = FlowDequeue(&flow_spare_q); if (f == NULL) { /* If we reached the max memcap, we get a used flow */ if (!(FLOW_CHECK_MEMCAP(sizeof(Flow) + FlowStorageSize()))) { /* declare state of emergency */ if (!(SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)) { SC_ATOMIC_OR(flow_flags, FLOW_EMERGENCY); FlowTimeoutsEmergency(); /* under high load, waking up the flow mgr each time leads * to high cpu usage. Flows are not timed out much faster if * we check a 1000 times a second. */ FlowWakeupFlowManagerThread(); } f = FlowGetUsedFlow(tv, dtv); if (f == NULL) { /* max memcap reached, so increments the counter */ if (tv != NULL && dtv != NULL) { StatsIncr(tv, dtv->counter_flow_memcap); } /* very rare, but we can fail. Just giving up */ return NULL; } /* freed a flow, but it's unlocked */ } else { /* now see if we can alloc a new flow */ f = FlowAlloc(); if (f == NULL) { if (tv != NULL && dtv != NULL) { StatsIncr(tv, dtv->counter_flow_memcap); } return NULL; } /* flow is initialized but *unlocked* */ } } else { /* flow has been recycled before it went into the spare queue */ /* flow is initialized (recylced) but *unlocked* */ } FLOWLOCK_WRLOCK(f); FlowUpdateCounter(tv, dtv, p->proto); return f; }
/** * \brief Set a thread flag */ void TmThreadsSetFlag(ThreadVars *tv, uint8_t flag) { SC_ATOMIC_OR(tv->flags, flag); }