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连接 ...
随机推荐
- Educational Codeforces Round 54
这套题不难,但是场上数据水,导致有很多叉点 A. 因为是让求删掉一个后字典序最小,那么当a[i]>a[i+1]的时候,删掉a[i]一定最优!这个题有个叉点,当扫完一遍如果没有满足条件的,就删去最 ...
- 关于html与body的高度问题
转自https://blog.csdn.net/javaloveiphone/article/details/51098972 一.html,body{height:100%} 今天看到一个CSS样式 ...
- spring boot 2
服务端验证: // 1.修改实体 @Min(value = 18,message = "必须大于18岁") private int age; // 2.修改add方法 @PostM ...
- Emacs中编辑保存makefile文件时会错误地将TAB转成空格的解决方法
问题描述 我的Emacs使用了Purcell的配置,在其配置中使用了whitespace-cleanup,且通过在.emacs.d/lisp/init-edit-utils.el中设定: (requi ...
- 最小子串覆盖 · Minimum Window Substring
[抄题]: 给定一个字符串source和一个目标字符串target,在字符串source中找到包括所有目标字符串字母的子串. 在答案的子串中的字母在目标字符串中是否需要具有相同的顺序? ——不需要. ...
- 链接ftp,把文件或图片上传到ftp指定的文件夹中
/******************************************************************** * * * Filename : .java * Auth ...
- 如何计算服务器能够承受多大的pv?
你想建设一个能承受500万PV/每天的网站吗? 500万PV是什么概念?服务器每秒要处理多少个请求才能应对?如果计算呢? PV是什么: PV是page view的简写.PV是指页面的访问次数,每打开或 ...
- handsontable-cell features
数据验证:在columns中设置validator,进行同步或异步验证,还可添加beforeValidate, afterValidate函数,allowInvalid:true可以不用验证 var ...
- [label][IDE] Develop Node.js Project With WebStorm
WebStorm 是一个支持 Node.js,CoffeeScript, TypeScript, Dart, Jade, Sass, LESS and Stylus 这些最新 web 开发技术的集成开 ...
- Hook ptrace 调试加入了ptrace函数的程序
Hook ptrace 调试加入了ptrace函数的程序 #import <substrate.h> #if !defined(PT_DENY_ATTACH)#define PT_DENY ...