/** * \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 allocate a flow * * We check against the memuse counter. If it passes that check we increment * the counter first, then we try to alloc. * * \retval f the flow or NULL on out of memory */ Flow *FlowAlloc(void) { Flow *f; if (!(FLOW_CHECK_MEMCAP(sizeof(Flow)))) { return NULL; } (void) SC_ATOMIC_ADD(flow_memuse, sizeof(Flow)); f = SCMalloc(sizeof(Flow)); if (f == NULL) { (void) SC_ATOMIC_SUB(flow_memuse, sizeof(Flow)); return NULL; } FLOW_INITIALIZE(f); return f; }
/** \brief allocate a flow * * We check against the memuse counter. If it passes that check we increment * the counter first, then we try to alloc. * * \retval f the flow or NULL on out of memory */ Flow *FlowAlloc(void) { Flow *f; size_t size = sizeof(Flow) + FlowStorageSize(); if (!(FLOW_CHECK_MEMCAP(size))) { return NULL; } (void) SC_ATOMIC_ADD(flow_memuse, size); f = SCMalloc(size); if (unlikely(f == NULL)) { (void)SC_ATOMIC_SUB(flow_memuse, size); return NULL; } memset(f, 0, size); FLOW_INITIALIZE(f); return f; }