php-fpm epoll封装
参考 http://www.jianshu.com/p/dac223d7d9ad
事件对象结构
//fpm_event.h
struct fpm_event_s {
int fd; /* IO 文件句柄*/
struct timeval timeout;
struct timeval frequency;
void (*callback)(struct fpm_event_s *, short, void *); /* 回调函数 */
void *arg; /* 回调函数的参数 */
int flags;
int index;
short which;
};
//队列,多个事件对象的容器
typedef struct fpm_event_queue_s {
struct fpm_event_queue_s *prev;
struct fpm_event_queue_s *next;
struct fpm_event_s *ev;
} fpm_event_queue;
事件模块封装结构
struct fpm_event_module_s {
const char *name;
int support_edge_trigger;
int (*init)(int max_fd);
int (*clean)(void);
//等待多个事件
int (*wait)(struct fpm_event_queue_s *queue, unsigned long int timeout);
int (*add)(struct fpm_event_s *ev);
int (*remove)(struct fpm_event_s *ev);
};
//events/epoll.c
//环境变量,在编译时确定是否纳入.
#if HAVE_EPOLL #include <sys/epoll.h>
#include <errno.h> static int fpm_event_epoll_init(int max);
static int fpm_event_epoll_clean();
static int fpm_event_epoll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout);
static int fpm_event_epoll_add(struct fpm_event_s *ev);
static int fpm_event_epoll_remove(struct fpm_event_s *ev); static struct fpm_event_module_s epoll_module = {
.name = "epoll",
.support_edge_trigger = ,
.init = fpm_event_epoll_init,
.clean = fpm_event_epoll_clean,
.wait = fpm_event_epoll_wait,
.add = fpm_event_epoll_add,
.remove = fpm_event_epoll_remove,
}; //全局变量
static struct epoll_event *epollfds = NULL;
static int nepollfds = ;
static int epollfd = -; #endif /* HAVE_EPOLL */ //这是使用时,获取模块对象的函数
//系统不支持返回NULL,这个函数总是编入二进制文件里.
struct fpm_event_module_s *fpm_event_epoll_module() /* {{{ */
{
#if HAVE_EPOLL
return &epoll_module;
#else
return NULL;
#endif /* HAVE_EPOLL */
}
/* }}} */ #if HAVE_EPOLL /*
* Init the module
*/
static int fpm_event_epoll_init(int max) /* {{{ */
{
if (max < ) {
return ;
} /* init epoll */
epollfd = epoll_create(max + );
if (epollfd < ) {
zlog(ZLOG_ERROR, "epoll: unable to initialize");
return -;
} /* allocate fds */
epollfds = malloc(sizeof(struct epoll_event) * max);
if (!epollfds) {
zlog(ZLOG_ERROR, "epoll: unable to allocate %d events", max);
return -;
}
memset(epollfds, , sizeof(struct epoll_event) * max); /* save max */
nepollfds = max; return ;
}
/* }}} */ /*
* Clean the module
*/
static int fpm_event_epoll_clean() /* {{{ */
{
/* free epollfds */
if (epollfds) {
free(epollfds);
epollfds = NULL;
}
if (epollfd != -) {
close(epollfd);
epollfd = -;
} nepollfds = ; return ;
}
/* }}} */ /*
* wait for events or timeout
*/
static int fpm_event_epoll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */
{
int ret, i; /* ensure we have a clean epoolfds before calling epoll_wait() */
memset(epollfds, , sizeof(struct epoll_event) * nepollfds); /* wait for inconming event or timeout */
ret = epoll_wait(epollfd, epollfds, nepollfds, timeout);
if (ret == -) { /* trigger error unless signal interrupt */
if (errno != EINTR) {
zlog(ZLOG_WARNING, "epoll_wait() returns %d", errno);
return -;
}
} /* events have been triggered, let's fire them */
for (i = ; i < ret; i++) { /* do we have a valid ev ptr ? */
if (!epollfds[i].data.ptr) {
continue;
} /* fire the event */
fpm_event_fire((struct fpm_event_s *)epollfds[i].data.ptr); /* sanity check */
if (fpm_globals.parent_pid != getpid()) {
return -;
}
} return ret;
}
/* }}} */ /*
* Add a FD to the fd set
*/
static int fpm_event_epoll_add(struct fpm_event_s *ev) /* {{{ */
{
struct epoll_event e; /* fill epoll struct */
e.events = EPOLLIN;
e.data.fd = ev->fd; //data.ptr 设为自定义对象, 事件触发时,以此获取自定义对象
e.data.ptr = (void *)ev; if (ev->flags & FPM_EV_EDGE) {
e.events = e.events | EPOLLET;
} /* add the event to epoll internal queue */
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ev->fd, &e) == -) {
zlog(ZLOG_ERROR, "epoll: unable to add fd %d", ev->fd);
return -;
} /* mark the event as registered */
ev->index = ev->fd;
return ;
}
/* }}} */ /*
* Remove a FD from the fd set
*/
static int fpm_event_epoll_remove(struct fpm_event_s *ev) /* {{{ */
{
struct epoll_event e; /* fill epoll struct the same way we did in fpm_event_epoll_add() */
e.events = EPOLLIN;
e.data.fd = ev->fd;
e.data.ptr = (void *)ev; if (ev->flags & FPM_EV_EDGE) {
e.events = e.events | EPOLLET;
} /* remove the event from epoll internal queue */
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, ev->fd, &e) == -) {
zlog(ZLOG_ERROR, "epoll: unable to remove fd %d", ev->fd);
return -;
} /* mark the event as not registered */
ev->index = -;
return ;
}
/* }}} */ #endif /* HAVE_EPOLL */
fpm_event_set(&signal_fd_event, fpm_signals_get_fd(), FPM_EV_READ, &fpm_got_signal, NULL);
初始化变量 ev
int fpm_event_set(struct fpm_event_s *ev, int fd, int flags, void (*callback)(struct fpm_event_s *, short, void *), void *arg) /* {{{ */
{
if (!ev || !callback || fd < -) {
return -;
}
memset(ev, , sizeof(struct fpm_event_s));
ev->fd = fd;
ev->callback = callback;
ev->arg = arg;
ev->flags = flags;
return ;
}
fpm_event_add(&signal_fd_event, );
如果是io事件 则放到epoll_ctl,如果是定时器,则放到定时器队列里
int fpm_event_add(struct fpm_event_s *ev, unsigned long int frequency) /* {{{ */
{
struct timeval now;
struct timeval tmp;
if (!ev) {
return -;
}
ev->index = -;
/* it's a triggered event on incoming data */
if (ev->flags & FPM_EV_READ) {
ev->which = FPM_EV_READ;
if (fpm_event_queue_add(&fpm_event_queue_fd, ev) != ) {
return -;
}
return ;
}
/* it's a timer event */
ev->which = FPM_EV_TIMEOUT;
fpm_clock_get(&now);
if (frequency >= ) {
tmp.tv_sec = frequency / ;
tmp.tv_usec = (frequency % ) * ;
} else {
tmp.tv_sec = ;
tmp.tv_usec = frequency * ;
}
ev->frequency = tmp;
fpm_event_set_timeout(ev, now);
if (fpm_event_queue_add(&fpm_event_queue_timer, ev) != ) {
return -;
}
return ;
}
如果是io事件,则放到epoll_ctl里
static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */
{
struct fpm_event_queue_s *elt;
if (!queue || !ev) {
return -;
}
if (fpm_event_queue_isset(*queue, ev)) {
return ;
}
if (!(elt = malloc(sizeof(struct fpm_event_queue_s)))) {
zlog(ZLOG_SYSERROR, "Unable to add the event to queue: malloc() failed");
return -;
}
elt->prev = NULL;
elt->next = NULL;
elt->ev = ev;
if (*queue) {
(*queue)->prev = elt;
elt->next = *queue;
}
*queue = elt;
/* ask the event module to add the fd from its own queue */
if (*queue == fpm_event_queue_fd && module->add) {
module->add(ev);
}
return ;
}
执行事件
void fpm_event_fire(struct fpm_event_s *ev) /* {{{ */
{
if (!ev || !ev->callback) {
return;
}
(*ev->callback)( (struct fpm_event_s *) ev, ev->which, ev->arg);
}
php-fpm epoll封装的更多相关文章
- 基于epoll封装的事件回调miniserver
epoll技术前两节已经阐述过了,目前主要做一下封装,很多epoll的服务器都是采用事件回调方式处理, 其实并没有什么复杂的,我慢慢给大家阐述下原理. 在networking.h和networking ...
- RBL开发笔记二
17:13:55 2014-08-25 有以下几个点: 第一 :怎么在预处理阶段能够做到识别某个宏是否给定义了 这里就定义了一个SystemConfig.h 专门做这个事情 当然是需要make ...
- Python 中的进程、线程、协程、同步、异步、回调
进程和线程究竟是什么东西?传统网络服务模型是如何工作的?协程和线程的关系和区别有哪些?IO过程在什么时间发生? 一.上下文切换技术 简述 在进一步之前,让我们先回顾一下各种上下文切换技术. 不过首先说 ...
- 协程,greenlet,gevent
""" 协程 """ ''' 协程: 类似于一个可以暂停的函数,可以多次传入数据,可以多次返回数据 协程是可交互的 耗资源大小:进程 --& ...
- libevent学习笔记(参考libevent深度剖析)
最近自学libevent事件驱动库,参考的资料为libevent2.2版本以及张亮提供的<Libevent源码深度剖析>, 参考资料: http://blog.csdn.net/spark ...
- Go netpoll I/O 多路复用构建原生网络模型之源码深度解析
导言 Go 基于 I/O multiplexing 和 goroutine 构建了一个简洁而高性能的原生网络模型(基于 Go 的I/O 多路复用 netpoll),提供了 goroutine-per- ...
- Java nio 空轮询bug到底是什么
编者注:Java nio 空轮询bug也就是Java nio在Linux系统下的epoll空轮询问题. epoll机制是Linux下一种高效的IO复用方式,相较于select和poll机制来说.其高效 ...
- 使用Cadence绘制PCB流程
转载:https://blog.csdn.net/hailin0716/article/details/47169799 之前使用过cadence画过几块板子,一直没有做过整理.每次画图遇到问题时,都 ...
- 框架篇:见识一下linux高性能网络IO+Reactor模型
前言 网络I/O,可以理解为网络上的数据流.通常我们会基于socket与远端建立一条TCP或者UDP通道,然后进行读写.单个socket时,使用一个线程即可高效处理:然而如果是10K个socket连接 ...
随机推荐
- jsp滚动框(非滚动条)
<marquee scrollAmount=4 width=300>需要滚动的字</marquee> scrollAmount表示运动速度,值是正整数,默认为6,越大滚动越快 ...
- 格式化程序尝试对消息反序列化时引发异常: 尝试对参数 http://tempuri.org/ 进行反序列化时出错: GetLzdtArticleResult。InnerException 消息是“反序列化对象 属于类型 lzdt.DTO.Dtolzdt[] 时出现错误。读取 XML 数据时,超出最大
当遇到这个错误的时候郁闷了好长时间报错是字符串长度过大可是修改了MaxStringContentLength”属性的值却不起作用最后才发现还是因为配置文件配置的问题在服务端 格式化程序尝试对消息反序列 ...
- git查看远程仓库地址
git remote -v
- MySQL 系列(三)事务
MySQL 系列(三)事务 一组要么同时执行成功,要么同时执行失败的 SQL 语句.是数据库操作的一个执行单元! 事务开始于: 连接到数据库上,并执行条 DML 语句(INSERT. UPDATE 或 ...
- Djanjo 的app 模板路径 静态文件 完整版登录 新手三件套 以及orm
一: django中app的概念: 一个项目可以包含多个应用(app,类似于模块,主页打开多个模块就是多个app) 创建了app,要在配置文件中注册 二:模板路径配置: 1 templates文件夹 ...
- 排序:快速排序Quick Sort
原理,通过一趟扫描将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序 ...
- SpringMVC源码解读 - HandlerMapping
SpringMVC在请求到handler处理器的分发这步是通过HandlerMapping模块解决的.handlerMapping 还处理拦截器. 先看看HandlerMapping的继承树吧 可以大 ...
- 从Objective-C到Swift,你必须会的(四)DLog
调试的时候打断点太慢,所以输出log就是一个很好的选择了.断点,一行一行的按,太麻烦了.从log里一条一条的看,很快就可以找到到哪个函数的哪个地方这个代码就没执行了.这里不详细讨论调试技巧的事.不过大 ...
- 数据集和JSON相互转换
使用DELPHI原生类实现数据集和JSON相互转换 JSON二要素:数组和对象.对象可以包含数组,数组可以包含对象.无层数限制.OLEVARIANT也类似,OLEVARIANT的一个元素又可以是OL ...
- 查看JVM内存使用情况
Runtime run = Runtime.getRuntime(); long max = run.maxMemory()/(1024*1024); long total = run.totalMe ...