概述

freeswitch是由事件驱动的,fs内部有各种事件来标识状态的变化包括呼叫的变化、配置的变化、号码的变化等等。

而一个框架内的事件引擎需要实现哪些基本的功能呢?

让我们来看一下fs的事件引擎是如何实现的。

环境

centos:CentOS  release 7.0 (Final)或以上版本

freeswitch:v1.8.7

GCC:4.8.5

数据结构

fs中event事件的实现主要在以下俩个文件。

src\include\switch_event.h

src\switch_event.c

涉及到的主要结构体如下

其中switch_event是传递事件消息的结构体,switch_event_node则是记录事件回调的结构体。

struct switch_event_header {

/*! the header name */

char *name;

/*! the header value */

char *value;

/*! array space */

char **array;

/*! array index */

int idx;

/*! hash of the header name */

unsigned long hash;

struct switch_event_header *next;

};

struct switch_event {

/*! the event id (descriptor) */

switch_event_types_t event_id;

/*! the priority of the event */

switch_priority_t priority;

/*! the owner of the event */

char *owner;

/*! the subclass of the event */

char *subclass_name;

/*! the event headers */

switch_event_header_t *headers;

/*! the event headers tail pointer */

switch_event_header_t *last_header;

/*! the body of the event */

char *body;

/*! user data from the subclass provider */

void *bind_user_data;

/*! user data from the event sender */

void *event_user_data;

/*! unique key */

unsigned long key;

struct switch_event *next;

int flags;

};

struct switch_event_node {

/*! the id of the node */

char *id;

/*! the event id enumeration to bind to */

switch_event_types_t event_id;

/*! the event subclass to bind to for custom events */

char *subclass_name;

/*! a callback function to execute when the event is triggered */

switch_event_callback_t callback;

/*! private data */

void *user_data;

struct switch_event_node *next;

};

struct switch_event_subclass {

/*! the owner of the subclass */

char *owner;

/*! the subclass name */

char *name;

/*! the subclass was reserved by a listener so it's ok for a module to reserve it still */

int bind;

};

总图

常用接口

src\include\switch_event.h 文件中,常用的接口列表

//事件引擎初始化接口

switch_event_init

switch_event_shutdown

//事件发布者接口

switch_event_create_subclass

switch_event_add_header

switch_event_destroy

switch_event_fire

//事件订阅者接口

switch_event_bind

switch_event_get_header

事件引擎是一个典型的PUB/SUB模型,发布者负责发布事件消息,事件引擎提供消息通道和转发,订阅者注册消息回调函数,由事件引擎根据事件消息调用回调函数,处理业务逻辑。

事件引擎模型图

事件引擎初始化switch_event_init

函数原型

SWITCH_DECLARE(switch_status_t) switch_event_init(switch_memory_pool_t *pool)

函数逻辑

1, 全局变量初始化。MAX_DISPATCH的大小范围是(2,(cpu核数/2)+1)。

2, 初始化事件分发的消息队列EVENT_DISPATCH_QUEUE。

3, 启动1个事件分发线程,执行线程函数“switch_event_dispatch_thread”。线程函数中监听EVENT_DISPATCH_QUEUE消息队列,并根据消息类型执行注册的回调函数。

4, 设置全局变量SYSTEM_RUNNING = 1。

事件引擎初始化后的内存模型图

事件引擎关闭switch_event_shutdown

函数原型

SWITCH_DECLARE(switch_status_t) switch_event_shutdown(void)

函数逻辑:

1, 设置全局变量SYSTEM_RUNNING = 0。

2, 向EVENT_CHANNEL_DISPATCH_QUEUE发送NULL包,通知channel分发线程结束处理。

3, 向EVENT_DISPATCH_QUEUE发送n个NULL包,n的数量由dispatch分发线程数目决定,通知dispatch分发线程结束处理。

4, 等待所有的EVENT_DISPATCH_QUEUE_THREADS线程结束退出。

5, 清空EVENT_DISPATCH_QUEUE队列,销毁所有未处理完的event。

6, 遍历CUSTOM_HASH,清理所有subclass注册。

7, 如果支持事件回收,清理事件回收队列的内存。

8, 处理结束。

创建事件switch_event_create_subclass

函数原型

SWITCH_DECLARE(switch_status_t) switch_event_create_subclass_detailed(const char *file, const char *func, int line,

switch_event_t **event, switch_event_types_t event_id, const char *subclass_name);

#define switch_event_create_subclass(_e, _eid, _sn) switch_event_create_subclass_detailed(__FILE__, (const char * )__SWITCH_FUNC__, __LINE__, _e, _eid, _sn)

函数逻辑:

1, 如果支持事件回收,从回收队列获取一个事件。不支持则重新分配一个新的事件。

2, 事件预处理,添加固定头域格式。

3, 处理“subclass_name”对应头域。

新创建的事件的内存模型如图

事件增加头域switch_event_add_header

函数原型

SWITCH_DECLARE(switch_status_t) switch_event_add_header(switch_event_t *event, switch_stack_t stack, const char *header_name, const char *fmt, ...)

函数逻辑:

1, 获取参数列表。

2, 获取一个头域结构体header。

3, header结构体赋值。

4, 将header添加到“event->headers”中。

增加头域后的事件的内存模型如图

事件销毁switch_event_destroy

函数原型

SWITCH_DECLARE(void) switch_event_destroy(switch_event_t **event)

函数逻辑:

1, 遍历”hp = event->headers”,如果“hp->array”不为空,先循环释放“hp->array[i]”内存,然后释放“hp->array”内存,再释放“hp->name”和“hp->value”和“hp”,“hp”的释放需要判断事件循环使用标识。

2, 释放“event->body”和“event->subclass_name”。

3, 根据事件循环使用标识,判断是否释放“event”。事件循环使用则把“event”发送到队列“EVENT_RECYCLE_QUEUE”。

4, 处理结束。

事件发布switch_event_fire

函数原型

SWITCH_DECLARE(switch_status_t) switch_event_fire_detailed(const char *file, const char *func, int line, switch_event_t **event, void *user_data);

#define switch_event_fire(event) switch_event_fire_detailed(__FILE__, (const char * )__SWITCH_FUNC__, __LINE__, event, NULL)

函数逻辑:

1, 参数校验

2, 检查EVENT_DISPATCH_QUEUE队列大小,如果队列满了,则对当前dispatch线程数和MAX_DISPATCH比较,并增加新的dispatch分发线程。

3, 将事件event推送到EVENT_DISPATCH_QUEUE中。

4, 处理结束。

事件较多时,事件引擎的线程模型如图

事件绑定switch_event_bind

函数原型

SWITCH_DECLARE(switch_status_t) switch_event_bind(const char *id, switch_event_types_t event, const char *subclass_name,

switch_event_callback_t callback, void *user_data)

函数逻辑:

1, 参数校验。

2, 检查subclass_name,针对不同的subclass owner,添加一个新节点到CUSTOM_HASH。

3, 分配新内存块event_node,对event_node初始化,绑定事件回调函数。

4, 将event_node插入EVENT_NODES[event]节点下的链表头部。

5, 处理结束。

事件绑定后的内存模型如图

事件获取头域switch_event_get_header

函数原型

_Ret_opt_z_ SWITCH_DECLARE(char *) switch_event_get_header_idx(switch_event_t *event, const char *header_name, int idx);

#define switch_event_get_header(_e, _h) switch_event_get_header_idx(_e, _h, -1)

函数逻辑:

1, 对header_name执行默认HASH函数(TIME33算法),得到hash值。

2, 遍历hp = event->headers,查找到满足条件“((!hp->hash || hash == hp->hash) && !strcasecmp(hp->name, header_name))”的头域,则返回”hp->value”。

3, 如果header_name的值为“_body”,则返回“event->body”。

4, 匹配失败,返回NULL。

总结

freeswitch可以通过设置全局变量“events-use-dispatch”的值,来控制事件分发的模式。

默认情况下“events-use-dispatch=1”,使用dispatch模式分发事件,dispatch线程数量大小范围为(2,(cpu/2)+1)。

当“events-use-dispatch=0”时,使用线程池模式分发事件。

fs的事件可以设置为循环使用,处理会有小的区别,主要在回收事件时会将事件的内存保留在循环队列中,方便循环使用,提高内存使用效率。

空空如常

求真得真

freeswitch的事件引擎实现分析的更多相关文章

  1. freeswitch的任务引擎实现分析

    概述 freeswitch核心框架中有一个定时任务系统,在开发过程中用来做一些延时操作和异步操作很方便. 我们在VOIP的呼叫流程中,经常会有一些对实时性要求没那么高的操作,或者会有阻塞流程的操作,我 ...

  2. SQL Server 扩展事件(Extented Events)从入门到进阶(4)——扩展事件引擎——基本概念

    本文属于 SQL Server 扩展事件(Extented Events)从入门到进阶 系列 在第一二节中,我们创建了一些简单的.类似典型SQL Trace的扩展事件会话.在此过程中,介绍了很多扩展事 ...

  3. (转载)Flash Loader加载完成不发送COMPLETE和ERROR事件的问题分析

    (转载)http://blog.dou.li/flash-loader%E5%8A%A0%E8%BD%BD%E5%AE%8C%E6%88%90%E4%B8%8D%E5%8F%91%E9%80%81co ...

  4. Python建立时间事件引擎原理剖析

    作为python小白,学习量化交易的曲线是非常陡峭的,唯一好的办法就是一点点啃代码.以下代码案例来自vnpy的引擎代码. # encoding: UTF-8 #定义时间事件 EVENT_TIMER = ...

  5. jquery get ($.get) 事件用法与分析

    jquery get ($.get) 事件用法与分析 get() 方法通过远程 HTTP GET 请求载入信息.这是一个简单的 GET 请求功能以取代复杂 $.ajax .请求成功时可调用回调函数.如 ...

  6. PHP实现事件机制实例分析

    PHP实现事件机制实例分析 内置了事件机制的语言不多,php也没有提供这种功能.事件(Event)说简单了就是一个Observer模式.实现起来非常easy.可是有所不同的是,事件的监听者谁都能够加, ...

  7. R数据分析:生存分析与有竞争事件的生存分析的做法和解释

    今天被粉丝发的文章给难住了,又偷偷去学习了一下竞争风险模型,想起之前写的关于竞争风险模型的做法,真的都是皮毛哟,大家见笑了.想着就顺便把所有的生存分析的知识和R语言的做法和论文报告方法都给大家梳理一遍 ...

  8. JQuery Sizzle引擎源代码分析

    最近在拜读艾伦在慕课网上写的JQuery课程,感觉在国内对JQuery代码分析透彻的人没几个能比得过艾伦.有没有吹牛?是不是我说大话了? 什么是Sizzle引擎? 我们经常使用JQuery的选择器查询 ...

  9. Nodejs事件引擎libuv源码剖析之:句柄(handle)结构的设计剖析

    声明:本文为原创博文,转载请注明出处. 句柄(handle)代表一种对持有资源的索引,句柄的叫法在window上较多,在unix/linux等系统上大多称之为描述符,为了抽象不同平台的差异,libuv ...

  10. Java三大主流开源工作流引擎技术分析

    首先,这个评论是我从网上,书中,搜索和整理出来的,也许有技术点上的错误点,也许理解没那么深入.但是我是秉着学习的态度加以评论,学习,希望对大家有用,进入正题! 三大主流工作流引擎:Shark,oswo ...

随机推荐

  1. VScode怎么实现c的运行,这里只讲述一些细节

    第一下载的Vscode要设置信任模式,否则你后面搞什么都没有用 第二下载minGw还是gcc 都行 第三安装插件,c,c++. 然后编译就行了,我搞了一天,主要弹出的是未找到exe文件,但是我告诉大家 ...

  2. [ARC156C] Tree and LCS

    Problem Statement We have a tree $T$ with vertices numbered $1$ to $N$. The $i$-th edge of $T$ conne ...

  3. Bugku CTF web题

    web2 查看网页源码,发现flag

  4. 【内核】kernel 热升级-1:kexec 机制

    内核热升级是指,预先准备好需要升级的内核镜像文件,在秒级时间内,完成内核切换,追求用户服务进程无感知. 欧拉操作系统提供了一套比较成熟的解决方案,该解决方案提供了用户态程序和内核态程序两部分: kex ...

  5. MinIO客户端之mv

    MinIO提供了一个命令行程序mc用于协助用户完成日常的维护.管理类工作. 官方资料 mc mv 将对象在桶之间移动. 在桶内准备好待移动的文件,检查对象,命令如下: ./mc ls local1/b ...

  6. Huggy Lingo: 利用机器学习改进 Hugging Face Hub 上的语言元数据

    太长不看版: Hub 上有不少数据集没有语言元数据,我们用机器学习来检测其语言,并使用 librarian-bots 自动向这些数据集提 PR 以添加其语言元数据. Hugging Face Hub ...

  7. 如何构建一个 NodeJS 影院微服务并使用 Docker 部署

    如何构建一个 NodeJS 影院微服务并使用 Docker 部署 前言 如何构建一个 NodeJS 影院微服务并使用 Docker 部署.在这个系列中,将构建一个 NodeJS 微服务,并使用 Doc ...

  8. 文心一言 VS 讯飞星火 VS chatgpt (58)-- 算法导论6.4 2题

    文心一言 VS 讯飞星火 VS chatgpt (58)-- 算法导论6.4 2题 二.试分析在使用下列循环不变量时,HEAPSORT 的正确性:在算法的第 2~5行 for 循环每次迭代开始时,子数 ...

  9. maven系列:POM文件总体配置说明

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  10. spring-mvc 系列:HttpMessageConverter(@RequestBody、RequestEntity、@ResponseBody、@RestController、ResponseEntity、文件上传下载)

    目录 一.@RequestBody 二.RequestEntity 三.@ResponseBody 四.SpringMVC处理json 五.@RestController 六.ResponseEnti ...