suricata之Threads

src/tm-threads.h,src/tm-threads.c

一、结构体

c 复制代码
typedef struct Thread_ {
    ThreadVars *tv;     /**< threadvars structure */
    const char *name;
    int type;
    int in_use;         /**< bool to indicate this is in use */

    SC_ATOMIC_DECLARE(SCTime_t, pktts); /**< current packet time of this thread
                                         *   (offline mode) */
    SCTime_t sys_sec_stamp; /**< timestamp in real system
                             *   time when the pktts was last updated. */
    SCSpinlock spin;
} __attribute__((aligned(CLS))) Thread;

typedef struct Threads_ {
    Thread *threads;
    size_t threads_size;
    int threads_cnt;
} Threads;

二、API

c 复制代码
int TmThreadsRegisterThread(ThreadVars *tv, const int type);

三、实现

3.1 TmThreadsRegisterThread

线程注册,将存储到全局动态数组thread_store.threads 中,数组空间不足时,以32为步长扩容,返回idx+1

c 复制代码
#define STEP 32
/**
 *  \retval id thread id, or 0 if not found
 */
int TmThreadsRegisterThread(ThreadVars *tv, const int type)
{
    SCMutexLock(&thread_store_lock);
    DEBUG_VALIDATE_BUG_ON(thread_store_sealed);
    if (thread_store.threads == NULL) {
        thread_store.threads = SCCalloc(STEP, sizeof(Thread));
        BUG_ON(thread_store.threads == NULL);
        thread_store.threads_size = STEP;
    }

    size_t s;
    for (s = 0; s < thread_store.threads_size; s++) {
        if (thread_store.threads[s].in_use == 0) {
            Thread *t = &thread_store.threads[s];
            SCSpinInit(&t->spin, 0);
            SCSpinLock(&t->spin);
            t->name = tv->name;
            t->type = type;
            t->tv = tv;
            t->in_use = 1;
            SCSpinUnlock(&t->spin);

            SCMutexUnlock(&thread_store_lock);
            return (int)(s+1);
        }
    }

    /* if we get here the array is completely filled */
    void *newmem = SCRealloc(thread_store.threads, ((thread_store.threads_size + STEP) * sizeof(Thread)));
    BUG_ON(newmem == NULL);
    thread_store.threads = newmem;
    memset((uint8_t *)thread_store.threads + (thread_store.threads_size * sizeof(Thread)), 0x00, STEP * sizeof(Thread));

    Thread *t = &thread_store.threads[thread_store.threads_size];
    SCSpinInit(&t->spin, 0);
    SCSpinLock(&t->spin);
    t->name = tv->name;
    t->type = type;
    t->tv = tv;
    t->in_use = 1;
    SCSpinUnlock(&t->spin);

    s = thread_store.threads_size;
    thread_store.threads_size += STEP;

    SCMutexUnlock(&thread_store_lock);
    return (int)(s+1);
}
#undef STEP

从实现上看,每次都是从0开始逐一遍历,查找in_use=0的项,并且也没有更新threads_cnt, 此字段并没有使用,猜测最开始想使用此字段表示当前已经注册了多少个线程。

3.2 TmThreadsUnregisterThread

根据线程id进行线程注销,当所有线程都被注销后,释放thread_store.threads。

c 复制代码
void TmThreadsUnregisterThread(const int id)
{
    SCMutexLock(&thread_store_lock);
    DEBUG_VALIDATE_BUG_ON(thread_store_sealed);
    if (id <= 0 || id > (int)thread_store.threads_size) {
        SCMutexUnlock(&thread_store_lock);
        return;
    }

    /* id is one higher than index */
    int idx = id - 1;

    /* reset thread_id, which serves as clearing the record */
    thread_store.threads[idx].in_use = 0;

    /* check if we have at least one registered thread left */
    size_t s;
    for (s = 0; s < thread_store.threads_size; s++) {
        Thread *t = &thread_store.threads[s];
        if (t->in_use == 1) {
            goto end;
        }
    }

    /* if we get here no threads are registered */
    SCFree(thread_store.threads);
    thread_store.threads = NULL;
    thread_store.threads_size = 0;
    thread_store.threads_cnt = 0;

end:
    SCMutexUnlock(&thread_store_lock);
}

3.3 TmThreadsSetThreadTimestamp

更新线程时间戳。

c 复制代码
void TmThreadsSetThreadTimestamp(const int id, const SCTime_t ts)
{
    SCTime_t now = SCTimeGetTime();
    int idx = id - 1;
    Thread *t = &thread_store.threads[idx];
    SCSpinLock(&t->spin);
    SC_ATOMIC_SET(t->pktts, ts);

    t->sys_sec_stamp = now;
    SCSpinUnlock(&t->spin);
}

3.4 TmThreadsTimeSubsysIsReady

检查所有已注册线程中TVT_PPT类型的线程:若其sys_sec_stamp等于零值nullts,则表明尚未进行初始化,此时整个子系统处于未就绪状态。

c 复制代码
bool TmThreadsTimeSubsysIsReady(void)
{
    static SCTime_t nullts = SCTIME_INITIALIZER;
    bool ready = true;
    for (size_t s = 0; s < thread_store.threads_size; s++) {
        Thread *t = &thread_store.threads[s];
        if (!t->in_use) {
            break;
        }
        SCSpinLock(&t->spin);
        if (t->type != TVT_PPT) {
            SCSpinUnlock(&t->spin);
            continue;
        }
        if (SCTIME_CMP_EQ(t->sys_sec_stamp, nullts)) {
            ready = false;
            SCSpinUnlock(&t->spin);
            break;
        }
        SCSpinUnlock(&t->spin);
    }
    return ready;
}

3.5 TmThreadsInitThreadsTimestamp

初始化所有已注册线程中TVT_PPT类型的线程,设置pkttssys_sec_stamp 。此函数仅在lib和pcapfile模式下被调用。

c 复制代码
void TmThreadsInitThreadsTimestamp(const SCTime_t ts)
{
    SCTime_t now = SCTimeGetTime();
    for (size_t s = 0; s < thread_store.threads_size; s++) {
        Thread *t = &thread_store.threads[s];
        if (!t->in_use) {
            break;
        }
        SCSpinLock(&t->spin);
        if (t->type != TVT_PPT) {
            SCSpinUnlock(&t->spin);
            continue;
        }
        SC_ATOMIC_SET(t->pktts, ts);
        t->sys_sec_stamp = now;
        SCSpinUnlock(&t->spin);
    }
}

3.6 TmThreadsGetThreadTime

获取指定线程当前数据包的时间戳(仅用于离线模式下,如pcapfile模式)。

数组下标从0开始,而idx是下标加1,因此需要将idx减1进行转换。

c 复制代码
SCTime_t TmThreadsGetThreadTime(const int idx)
{
    DEBUG_VALIDATE_BUG_ON(idx == 0);
    const int i = idx - 1;
    Thread *t = &thread_store.threads[i];
    return SC_ATOMIC_GET(t->pktts);
}

3.7 TmThreadsGetMinimalTimestamp

在所有注册线程中筛选出类型为TVT_PPTpktts不为空的线程,然后从中找出非休眠线程的最小pktts值。

c 复制代码
void TmThreadsGetMinimalTimestamp(struct timeval *ts)
{
    struct timeval local = { 0 };
    static SCTime_t nullts = SCTIME_INITIALIZER;
    bool set = false;
    SCTime_t now = SCTimeGetTime();

    for (size_t s = 0; s < thread_store.threads_size; s++) {
        Thread *t = &thread_store.threads[s];
        if (t->in_use == 0) {
            break;
        }
        SCSpinLock(&t->spin);
        /* only packet threads set timestamps based on packets */
        if (t->type != TVT_PPT) {
            SCSpinUnlock(&t->spin);
            continue;
        }
        SCTime_t pktts = SC_ATOMIC_GET(t->pktts);
        if (SCTIME_CMP_NEQ(pktts, nullts)) {
            SCTime_t sys_sec_stamp = SCTIME_ADD_SECS(t->sys_sec_stamp, 5);
            /* ignore sleeping threads */
            if (SCTIME_CMP_LT(sys_sec_stamp, now)) {
                SCSpinUnlock(&t->spin);
                continue;
            }
            if (!set) {
                SCTIME_TO_TIMEVAL(&local, pktts);
                set = true;
            } else {
                if (SCTIME_CMP_LT(pktts, SCTIME_FROM_TIMEVAL(&local))) {
                    SCTIME_TO_TIMEVAL(&local, pktts);
                }
            }
        }
        SCSpinUnlock(&t->spin);
    }
    *ts = local;
    SCLogDebug("ts->tv_sec %"PRIuMAX, (uintmax_t)ts->tv_sec);
}

3.8 TmThreadsGetWorkerThreadMax

获取worker线程的最大值,取值范围[1,1024]

c 复制代码
uint16_t TmThreadsGetWorkerThreadMax(void)
{
    uint16_t ncpus = UtilCpuGetNumProcessorsOnline();
    int thread_max = TmThreadGetNbThreads(WORKER_CPU_SET);
    /* always create at least one thread */
    if (thread_max == 0)
        thread_max = ncpus * threading_detect_ratio;
    if (thread_max < 1)
        thread_max = 1;
    if (thread_max > 1024) {
        SCLogWarning("limited number of 'worker' threads to 1024. Wanted %d", thread_max);
        thread_max = 1024;
    }
    return (uint16_t)thread_max;
}

四、总结

  • 所有注册的线程均保存在全局数组thread_store.threads
  • 该数组每次扩容时容量增加32个元素
  • 通过检查in_use标志位判断节点是否已被占用
  • 每次都需要从数组首元素开始遍历,且未使用threads_cnt字段
相关推荐
大海里的番茄1 小时前
让操作系统的远程管理更简单用openEuler+cpolar
linux·c语言·c++
赖small强1 小时前
【音视频开发】CMOS Sensor图像采集原理及Linux主控ISP处理流程
linux·音视频·cmos·isp·v4l2
津渡7411 小时前
【技术实战】Linux 服务器网络流量统一配置(TUN模式):解决 Docker/开发环境连接难题
linux
胖咕噜的稞达鸭1 小时前
基础IO 文件在内核中是怎么被管理的 重定向的含义 在自定义shell中加入重定向
linux·c++·git·腾讯云·visual studio·csdn开发云
天宁1 小时前
Ubuntu 一键切换吉林大学镜像源
linux·ubuntu
代码栈上的思考1 小时前
Linux 核心基础实操(含远程登录、编辑器、用户管理等)
linux·运维·服务器
礼拜天没时间.1 小时前
《Grafana 企业级可视化监控实战指南:从安装、配置到智能告警》:Grafana 使用
linux·运维·信息可视化·zabbix·grafana·监控
代码游侠1 小时前
数据结构——单向链表
linux·开发语言·数据结构·学习·算法·链表
工具人55552 小时前
如何确认当前登录的系统是QNX还是Linux
linux·运维·服务器