现在,我们进入一个全新的主题,讲解如何替换掉PHP原来那些阻塞的函数。已达到不修改历史代码,就可以直接协程化我们的代码。

我们这篇文章需要实现的方法如下:

StudyRuntimeenableCoroutine()

首先,我们创建两个文件study_runtime.hstudy_runtime.cc

其中,study_runtime.h文件的内容如下:

#ifndef STUDY_RUNTIME_H
#define STUDY_RUNTIME_H#include "php_study.h"#endif /* STUDY_RUNTIME_H */

其中,study_runtime.cc文件的内容如下:

#include "study_runtime.h"

然后修改我们的config.m4文件,增加study_runtime.cc为需要编译的源文件:

study_source_file="study.cc study_coroutine.cc study_coroutine_util.cc src/coroutine/coroutine.cc src/coroutine/context.cc ${STUDY_ASM_DIR}make_${STUDY_CONTEXT_ASM_FILE} ${STUDY_ASM_DIR}jump_${STUDY_CONTEXT_ASM_FILE} src/socket.cc src/log.cc src/error.cc src/core/base.cc src/coroutine/socket.cc src/timer.cc study_coroutine_channel.cc src/coroutine/channel.cc study_coroutine_socket.cc study_coroutine_server.cc study_runtime.cc
"

然后和往常一样,我们需要先实现PHPStudyRuntime

在文件study_runtime.cc里面,我们实现我们的enableCoroutine方法。首先,定义一下这个方法的参数。目前我们不需要传递参数:

ZEND_BEGIN_ARG_INFO_EX(arginfo_study_runtime_void, 0, 0, 0)
ZEND_END_ARG_INFO()

然后是enableCoroutine方法的大体框架:

extern PHP_METHOD(study_coroutine_util, sleep);
static void hook_func(const char *name, size_t name_len, zif_handler handler);static PHP_METHOD(study_runtime, enableCoroutine)
{hook_func(ZEND_STRL("sleep"), zim_study_coroutine_util_sleep);
}

(后面我们会去实现hook_func这个函数)

这里,我们的意图是把PHP原来的sleep函数替换成StudyCoroutine::sleep这个方法。zim_study_coroutine_util_sleep实际上就是我们在文件study_coroutine_util.cc中定义的PHP_METHOD(study_coroutine_util, sleep)展开后的结果。

然后,收集enableCoroutine到结构体zend_function_entry里面:

static const zend_function_entry study_runtime_methods[] =
{PHP_ME(study_runtime, enableCoroutine, arginfo_study_runtime_void, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)PHP_FE_END
};

然后创建一个模块初始化函数来注册PHPStudyRuntime

/*** Define zend class entry*/
zend_class_entry study_runtime_ce;
zend_class_entry *study_runtime_ce_ptr;void study_runtime_init()
{INIT_NS_CLASS_ENTRY(study_runtime_ce, "Study", "Runtime", study_runtime_methods);study_runtime_ce_ptr = zend_register_internal_class(&study_runtime_ce TSRMLS_CC); // Registered in the Zend Engine
}

然后,我们在study.cc文件的PHP_MINIT_FUNCTION(study)函数里面调用study_runtime_init

PHP_MINIT_FUNCTION(study)
{study_coroutine_util_init();study_coro_server_init(module_number);study_coro_channel_init();study_coro_socket_init(module_number);study_runtime_init(); // 新增的代码return SUCCESS;
}

我们需要在php_study.h里面对study_runtime_init函数进行声明:

void study_coroutine_util_init();
void study_coro_server_init(int module_number);
void study_coro_channel_init();
void study_coro_socket_init(int module_number);
void study_runtime_init(); // 新增的代码

OK,我们完成了StudyRuntime类的注册。

最后,我们需要实现hook_func

static void hook_func(const char *name, size_t name_len, zif_handler new_handler)
{zend_function *ori_f = (zend_function *) zend_hash_str_find_ptr(EG(function_table), name, name_len);ori_f->internal_function.handler = new_handler;
}

代码其实比较简单,就是先去全局的EG(function_table)里面查找sleep名字对应的zend_function,然后把它的handler换成我们新的new_handler即可。也就是说,PHP内核实现的C函数实际上是会以函数指针的形式保存在zend_function.internal_function.handler里面。

然后,我们重新编译、安装扩展:

phpize --clean && phpize && ./configure && make && make install
----------------------------------------------------------------------Build complete.
Don't forget to run 'make test'.Installing shared extensions:     /usr/local/lib/php/extensions/no-debug-non-zts-20180731/
Installing header files:          /usr/local/include/php/

OK,编译、安装扩展成功。

我们来编写测试脚本:

<?phpstudy_event_init();Sgo(function ()
{var_dump(StudyCoroutine::getCid());sleep(1);var_dump(StudyCoroutine::getCid());
});Sgo(function ()
{var_dump(StudyCoroutine::getCid());
});study_event_wait();

这个脚本没有开启hook,执行结果如下:

~/codeDir/cppCode/study # php test.php
int(1)
int(1)
int(2)

符合预期。进程因为第一个协程调用了阻塞的sleep函数,所以导致整个进程阻塞了起来,所以打印是顺序的。

我们现在来开启一下hook功能:

<?phpstudy_event_init();StudyRuntime::enableCoroutine();Sgo(function ()
{var_dump(StudyCoroutine::getCid());sleep(1);var_dump(StudyCoroutine::getCid());
});Sgo(function ()
{var_dump(StudyCoroutine::getCid());
});study_event_wait();

结果如下:

~/codeDir/cppCode/study # php test.php
int(1)
int(2)
int(1)

因为我们已经把PHP原先的sleep函数替换成了StudyCoroutine::sleep方法,所以,进程不会阻塞起来,会在调用sleep之后立马切换到第二个协程。

c++ sleep函数_《PHP扩展开发》-hook-(hook原来的sleep)相关推荐

  1. mysql geo 函数_【后端开发】地理位置geo处理之mysql函数的详细介绍(附代码)

    本篇文章给大家带来的内容是关于地理位置geo处理之mysql函数的详细介绍(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 目前越来越多的业务都会基于LBS,附近的人,外卖位 ...

  2. java中的fun函数_使用Kotlin开发Android--常见的fun函数定义

    上一篇具体讲了在Android Studio中怎么搭建Kotlin环境的搭建,以及简单的写了一个Hello World的DEMO. 那么今天我们一起来学习一下常见的fun函数定义.我大概定义了11个比 ...

  3. php7 有ext skel吗,PHP扩展开发系列02 - 老司机起步之函数

    上一篇扩展开发引导文章中.创建了编写扩展的三个基本文件.或许你会有个疑问 PHP没有类似的自动生成项目框架的工具吗? 当然有. 这篇文章就开始介绍使用 "php-ext-cli" ...

  4. react hook + stamen store + pug实现纯函数无痛版react开发体验

    基于最新的react 16.7.0-alpha.2,结合react hook + stamen store + pug,实现纯函数无痛版react开发体验,畅快度直逼clojurescript + r ...

  5. mysql for循环_基于Swoole扩展开发异步高性能的MySQL代理服务器

    MySQL数据库对每个客户端连接都会分配一个线程,所以连接非常宝贵.开发一个异步的MySQL代理服务器,PHP应用服务器可以长连接到这台Server,既减轻MYSQL的连接压力,又使PHP保持长连接减 ...

  6. mysql异步扩展_基于Swoole扩展开发异步高性能的MySQL代理服务器

    MySQL数据库对每个客户端连接都会分配一个线程,所以连接非常宝贵.开发一个异步的MySQL代理服务器,PHP应用服务器可以长连接到这台Server,既减轻MYSQL的连接压力,又使PHP保持长连接减 ...

  7. mysql扩展中如何处理结果集_请写出PHP处理结果集的5个函数(使用mysql扩展)_学小易找答案...

    [单选题]在MySQL中,选择数据库的命令是( ) [单选题]开启mysqli扩展的配置语句是( ). [单选题]19世纪美国杰出的浪漫主义小说家麦尔维尔的代表作是 [单选题]卤素灯检漏时,发现管子大 ...

  8. 【php7扩展开发一】注册一个内部函数hello world

    通过扩展可以将C语言实现的函数提供给PHP脚本使用,如同大量PHP内置函数一样,这些函数统称为内部函数(internal function),与PHP脚本中定义的用户函数不同,它们无需精力用户函数的编 ...

  9. SuperMap iDesktop Cross 8C 开源桌面GIS下载与扩展开发

    2019独角兽企业重金招聘Python工程师标准>>> SuperMap iDesktop Cross 8C 扩展开发的环境配置

 工程源码:http://git.oschina. ...

  10. 基于Mozilla Thunderbird的扩展开发(四)---修改Thunderbird源代码实现自动保存附件...

    <?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /><?xml:namespace ...

最新文章

  1. html根据字段制作曲线图,canvas制作简单的HTML图表,折线或者矩形统计(原创)
  2. AStyle - SourceInsight
  3. Flowable 数据库表结构 ACT_GE_PROPERTY
  4. JAVA中的那些名词解释
  5. python爬取数据生成词云_Python 爬取生成中文词云以爬取知乎用户属性为例
  6. DeepSpeaker_RawNet_GE2E 声纹识别对比
  7. mac 设置环境变量path的几种方法
  8. Conda集成arcpy2.7
  9. opencv 之 颜色通道提取
  10. 8cm等于多少像素_厘米与像素一张图片,要打印尺寸为10.8厘米*17厘米,图片要编 爱问知识人...
  11. 实用且堪称神器的 Chrome 插件推荐(值得收藏)
  12. 3dmax2022兼容疯狂模渲大师最新版|疯狂模渲大师3.6.0.4下载安装步骤教程怎么激活素材库和装机3dmax超一流辅助客户端的?
  13. 数据挖掘学习路线【转知乎某人的观点】
  14. Wordnet的一些简单使用
  15. lazada卖家如何正确做好产品定价?
  16. 申宝股票-抱团股继续杀跌
  17. 音速启动 便携 csdn_在安全模式下启动便携式Firefox
  18. 问题:windows---笔记本外接显示器,在系统更新后,外接显示器没有反应,右键打开显示设置,点击检测后提示未检测到其他显示器
  19. hibernnate 使用Oracle的sequence为对象生成主键 自增50的问题
  20. SQL学习之数据操作,基于Oracle下的HR用户(五)

热门文章

  1. Struts2 访问上下问对象
  2. android 侧滑效果,android 侧滑效果
  3. android中json插件,【Android原生插件】package.json中关于第三方aar的配置
  4. android d弹框顶部突出,TextView + Tablayout实现顶部菜单栏效果
  5. python打代码运行图形_利用aardio给python编写图形界面
  6. python的pip_同时装了Python3和Python2,怎么用pip?
  7. java创建子类对象的步骤_一通Spring骚操作:我敢说没人比我更懂Java对象创建
  8. (王道408考研操作系统)第四章文件管理-第一节5:文件存储空间管理
  9. HookProc 和 CallNextHookEx
  10. windows服务编写原理(上)