提交 1b0a85c4 编写于 作者: C codinghuang

Add: 增加《协程创建(一)》

上级 0d9e155c
# 协程创建(一)
## 协程相关结构定义
首先,我们需要一个`PHP`可用的协程,根据[梳理一下架构](./《PHP扩展开发》-协程-梳理一下架构.md)这篇文章的内容,我们需要在`study_coroutine.h`里面来定义:
```c++
#include "php_study.h"
namespace Study
{
class PHPCoroutine
{
static long create(zend_fcall_info_cache *fci_cache, uint32_t argc, zval *argv);
};
}
```
然后,我们还需要一个与`PHP`无关的协程数据结构,我们定义在`include/coroutine.h`下面:
```c++
#ifndef COROUTINE_H
#define COROUTINE_H
namespace Study
{
class Coroutine
{
static long create(coroutine_func_t fn, void* args = nullptr);
};
}
#endif /* COROUTINE_H */
```
`coroutine_func_t`是协程需要跑的函数,我们可以定义在`include/context.h`下面:
```c++
#ifndef CONTEXT_H
#define CONTEXT_H
typedef void (*coroutine_func_t)(void*);
#endif /* CONTEXT_H */
```
它定义了一个指向函数的指针类型,返回值是`void`,参数是一个`void *`指针。
然后,我们在`include/coroutine.h`中引入这个`context.h`文件:
```c++
#include "context.h"
```
## 协程接口参数声明
OK,此时,我们需要为`PHP`脚本提供一个创建协程的接口,我们在文件`study_coroutine_util.cc`里面来完成。首先,我们需要确定一下这个接口的参数是什么,很显然,是一个`PHP`函数:
```c++
#include "study_coroutine.h"
ZEND_BEGIN_ARG_INFO_EX(arginfo_study_coroutine_create, 0, 0, 1)
ZEND_ARG_CALLABLE_INFO(0, func, 0)
ZEND_END_ARG_INFO()
```
其中`ZEND_BEGIN_ARG_INFO_EX``ZEND_END_ARG_INFO`是一对宏,用来声明函数接受的参数。其中`ZEND_BEGIN_ARG_INFO_EX`展开如下:
```c++
#define ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args) \
static const zend_internal_arg_info name[] = { \
{ (const char*)(zend_uintptr_t)(required_num_args), 0, return_reference, 0 },
```
`name`是参数的的名字。
`_unused`我们不用管,因为`ZEND_BEGIN_ARG_INFO_EX`展开之后,并没有用到`_unused`
`return_reference`表示是否返回引用。
`required_num_args`表示这个函数最少需要传递的参数个数。
`ZEND_ARG_CALLABLE_INFO`用来显式声明参数为`callable`,将检查函数、成员方法是否可调用。
`ZEND_END_ARG_INFO`展开如下:
```c++
#define ZEND_END_ARG_INFO() };
```
因此,我们对这个参数声明展开后,会得到如下内容:
```c++
ZEND_BEGIN_ARG_INFO_EX(arginfo_study_coroutine_create, 0, 0, 1)
ZEND_ARG_CALLABLE_INFO(0, func, 0)
ZEND_END_ARG_INFO()
static const zend_internal_arg_info arginfo_study_coroutine_create[] = { \
{ (const char*)(zend_uintptr_t)(1), 0, 0, 0 },
ZEND_ARG_CALLABLE_INFO(0, func, 0)
};
```
所以,虽然我在
```c++
ZEND_BEGIN_ARG_INFO_EX(arginfo_study_coroutine_create, 0, 0, 1)
```
中写下了单词`arginfo``study_coroutine_create`,似乎一定是要这样写,但是,我们把`ZEND_BEGIN_ARG_INFO_EX`宏展开之后会发现,`arginfo_study_coroutine_create`只是一个变量名而已。因此,我这里这样组合这个变量是为了可读性更好,并不是一定要这样声明这个参数,这一点大家需要去注意。
## 协程接口方法声明
然后,我们需要在文件`study_coroutine_util.cc`里面去声明这个方法:
```c++
static PHP_METHOD(study_coroutine_util, create);
```
`PHP_METHOD`展开之后的内容如下:
```
#define PHP_METHOD ZEND_METHOD
#define ZEND_METHOD(classname, name) ZEND_NAMED_FUNCTION(ZEND_MN(classname##_##name))
#define ZEND_MN(name) zim_##name
#define ZEND_NAMED_FUNCTION(name) void ZEND_FASTCALL name(INTERNAL_FUNCTION_PARAMETERS)#define INTERNAL_FUNCTION_PARAMETERS zend_execute_data *execute_data, zval *return_value
```
所以,接口方法展开的内容如下:
```c++
PHP_METHOD(study_coroutine_util, create);
ZEND_METHOD(study_coroutine_util, create);
ZEND_NAMED_FUNCTION(ZEND_MN(study_coroutine_util##_##create));
ZEND_NAMED_FUNCTION(zim_##study_coroutine_util##_##create);
void ZEND_FASTCALL zim_##study_coroutine_util##_##create(INTERNAL_FUNCTION_PARAMETERS);
void ZEND_FASTCALL zim_##study_coroutine_util##_##create(zend_execute_data *execute_data, zval *return_value);
```
`static PHP_METHOD(study_coroutine_util, create);`相当于声明了如下函数:
```c++
void zim_study_coroutine_util_create(zend_execute_data *execute_data, zval *return_value);
```
通过对接口方法的展开,我们发现,虽然接口命名是单词`study_coroutine_util``create`,似乎必须得是真正的类名加上方法名。其实不然,这里也只是为了可读性更好。
我们还可以对比一下`PHP_FUNCTION`这个宏,实际上,它和`PHP_METHOD`的一个区别就是少拼接了`classname`
## 协程接口实现
我们在`study_coroutine_util.cc`文件里面写下:
```c++
PHP_METHOD(study_coroutine_util, create)
{
php_printf("success!\n");
}
```
因为文章篇幅的原因,我们这里简单实现。
## 协程接口收集
接着,我们需要对这个方法进行收集,放在变量`study_coroutine_util_methods`里面。在`study_coroutine_util.cc`写下:
```c++
const zend_function_entry study_coroutine_util_methods[] =
{
PHP_ME(study_coroutine_util, create, arginfo_study_coroutine_create, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_FE_END
};
```
这里我们使用到一个数据结构:
```c++
typedef struct _zend_function_entry {
const char *fname;
zif_handler handler;
const struct _zend_internal_arg_info *arg_info;
uint32_t num_args;
uint32_t flags;
} zend_function_entry;
```
`fname`是函数的名字。
`handler`是一个函数指针,也就是该函数的主体。那么是什么样的函数指针呢?我们得看看前面的`zif_handler`
```c++
/* zend_internal_function_handler */
typedef void (ZEND_FASTCALL *zif_handler)(INTERNAL_FUNCTION_PARAMETERS);
```
可以发现,这是一个没有返回值,参数是`INTERNAL_FUNCTION_PARAMETERS`的函数。这个其实和`PHP_METHOD`这个宏展开得到的函数声明类型是一致的。
`arg_info`是这个接口方法对应的参数。可以发现,它实际上就是我们上面的那个参数展开后的类型。所以这里很明显,我们必须填写`arginfo_study_coroutine_create`,也就是我们参数展开后定义的那个变量。
`num_args`是接口方法的参数个数。可以发现,我们这里并没有填写参数的个数,实际上,这个参数的个数会通过宏`ZEND_FENTRY`来计算出来:
```c++
#define ZEND_FENTRY(zend_name, name, arg_info, flags) { #zend_name, name, arg_info, (uint32_t) (sizeof(arg_info)/sizeof(struct _zend_internal_arg_info)-1), flags },
```
`flags`是标志。例如这个接口方法是`public``static`的。
## 协程类注册
然后,我们需要去注册我们的`Study\Coroutine`这个类。我们在`MINIT`这个阶段进行注册,代码如下:
```c++
zend_class_entry study_coroutine_ce;
zend_class_entry *study_coroutine_ce_ptr;
PHP_MINIT_FUNCTION(study)
{
INIT_NS_CLASS_ENTRY(study_coroutine_ce, "Study", "Coroutine", study_coroutine_util_methods);
return SUCCESS;
}
```
但是,考虑到以后我们会有许多的类,我们不在`MINIT`里面直接写注册的代码,而是让`study_coroutine_util.cc`提供一个函数,我们在这个函数里面实现注册功能:
```c++
/**
* Define zend class entry
*/
zend_class_entry study_coroutine_ce;
zend_class_entry *study_coroutine_ce_ptr;
void study_coroutine_util_init()
{
INIT_NS_CLASS_ENTRY(study_coroutine_ce, "Study", "Coroutine", study_coroutine_util_methods);
study_coroutine_ce_ptr = zend_register_internal_class(&study_coroutine_ce TSRMLS_CC); // Registered in the Zend Engine
}
```
然后,我们在`php_study.h`里面来进行声明:
```c++
void study_coroutine_util_init();
```
然后,我们在`MINIT`中对这个函数进行调用,完成类的注册:
```c++
PHP_MINIT_FUNCTION(study)
{
study_coroutine_util_init();
return SUCCESS;
}
```
## 编译测试
```shell
~/codeDir/cppCode/study # ./make.sh
```
编写测试脚本:
```php
<?php
Study\Coroutine::create();
```
```php
~/codeDir/cppCode/study # php test.php
success!
~/codeDir/cppCode/study #
```
OK,到这里,我们算是完成了协程创建接口的前期工作。
......@@ -25,3 +25,17 @@ study_coroutine_util.cc(文件)
#endif /* STUDY_COROUTINE_H */
```
同时,我们需要修改我们的`config.m4`文件:
```shell
study_source_file="\
study.cc \
study_coroutine.cc \
study_coroutine_util.cc \
${STUDY_ASM_DIR}make_${STUDY_CONTEXT_ASM_FILE} \
${STUDY_ASM_DIR}jump_${STUDY_CONTEXT_ASM_FILE}
"
```
[下一篇:协程创建(一)](《PHP扩展开发》-协程-协程创建(一).md)
#ifndef CONTEXT_H
#define CONTEXT_H
typedef void (*coroutine_func_t)(void*);
#endif /* CONTEXT_H */
#ifndef COROUTINE_H
#define COROUTINE_H
#include "context.h"
namespace Study
{
class Coroutine
{
static long create(coroutine_func_t fn, void* args = nullptr);
};
}
#endif /* COROUTINE_H */
\ No newline at end of file
......@@ -49,4 +49,6 @@ ZEND_BEGIN_MODULE_GLOBALS(study)
ZEND_END_MODULE_GLOBALS(study)
void study_coroutine_util_init();
#endif /* PHP_STUDY_H */
\ No newline at end of file
/bin/sh /root/codeDir/cppCode/study/libtool --mode=compile g++ -I. -I/root/codeDir/cppCode/study -DPHP_ATOM_INC -I/root/codeDir/cppCode/study/include -I/root/codeDir/cppCode/study/main -I/root/codeDir/cppCode/study -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -I/root/codeDir/cppCode/study -I/root/codeDir/cppCode/study/include -DHAVE_CONFIG_H -g -O2 -Wall -Wno-unused-function -Wno-deprecated -Wno-deprecated-declarations -std=c++11 -c /root/codeDir/cppCode/study/study.cc -o study.lo
mkdir .libs
g++ -I. -I/root/codeDir/cppCode/study -DPHP_ATOM_INC -I/root/codeDir/cppCode/study/include -I/root/codeDir/cppCode/study/main -I/root/codeDir/cppCode/study -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -I/root/codeDir/cppCode/study -I/root/codeDir/cppCode/study/include -DHAVE_CONFIG_H -g -O2 -Wall -Wno-unused-function -Wno-deprecated -Wno-deprecated-declarations -std=c++11 -c /root/codeDir/cppCode/study/study.cc -fPIC -DPIC -o .libs/study.o
/bin/sh /root/codeDir/cppCode/study/libtool --mode=compile g++ -I. -I/root/codeDir/cppCode/study -DPHP_ATOM_INC -I/root/codeDir/cppCode/study/include -I/root/codeDir/cppCode/study/main -I/root/codeDir/cppCode/study -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -I/root/codeDir/cppCode/study -I/root/codeDir/cppCode/study/include -DHAVE_CONFIG_H -g -O2 -Wall -Wno-unused-function -Wno-deprecated -Wno-deprecated-declarations -std=c++11 -c /root/codeDir/cppCode/study/study_coroutine.cc -o study_coroutine.lo
g++ -I. -I/root/codeDir/cppCode/study -DPHP_ATOM_INC -I/root/codeDir/cppCode/study/include -I/root/codeDir/cppCode/study/main -I/root/codeDir/cppCode/study -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -I/root/codeDir/cppCode/study -I/root/codeDir/cppCode/study/include -DHAVE_CONFIG_H -g -O2 -Wall -Wno-unused-function -Wno-deprecated -Wno-deprecated-declarations -std=c++11 -c /root/codeDir/cppCode/study/study_coroutine.cc -fPIC -DPIC -o .libs/study_coroutine.o
/bin/sh /root/codeDir/cppCode/study/libtool --mode=compile g++ -I. -I/root/codeDir/cppCode/study -DPHP_ATOM_INC -I/root/codeDir/cppCode/study/include -I/root/codeDir/cppCode/study/main -I/root/codeDir/cppCode/study -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -I/root/codeDir/cppCode/study -I/root/codeDir/cppCode/study/include -DHAVE_CONFIG_H -g -O2 -Wall -Wno-unused-function -Wno-deprecated -Wno-deprecated-declarations -std=c++11 -c /root/codeDir/cppCode/study/study_coroutine_util.cc -o study_coroutine_util.lo
g++ -I. -I/root/codeDir/cppCode/study -DPHP_ATOM_INC -I/root/codeDir/cppCode/study/include -I/root/codeDir/cppCode/study/main -I/root/codeDir/cppCode/study -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -I/root/codeDir/cppCode/study -I/root/codeDir/cppCode/study/include -DHAVE_CONFIG_H -g -O2 -Wall -Wno-unused-function -Wno-deprecated -Wno-deprecated-declarations -std=c++11 -c /root/codeDir/cppCode/study/study_coroutine_util.cc -fPIC -DPIC -o .libs/study_coroutine_util.o
/bin/sh /root/codeDir/cppCode/study/libtool --mode=compile cc -I. -I/root/codeDir/cppCode/study -DPHP_ATOM_INC -I/root/codeDir/cppCode/study/include -I/root/codeDir/cppCode/study/main -I/root/codeDir/cppCode/study -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -I/root/codeDir/cppCode/study -I/root/codeDir/cppCode/study/include -DHAVE_CONFIG_H -Wall -pthread -g -O2 -c /root/codeDir/cppCode/study/thirdparty/boost/asm/make_x86_64_sysv_elf_gas.S -o thirdparty/boost/asm/make_x86_64_sysv_elf_gas.lo
mkdir thirdparty/boost/asm/.libs
cc -I. -I/root/codeDir/cppCode/study -DPHP_ATOM_INC -I/root/codeDir/cppCode/study/include -I/root/codeDir/cppCode/study/main -I/root/codeDir/cppCode/study -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -I/root/codeDir/cppCode/study -I/root/codeDir/cppCode/study/include -DHAVE_CONFIG_H -Wall -pthread -g -O2 -c /root/codeDir/cppCode/study/thirdparty/boost/asm/make_x86_64_sysv_elf_gas.S -fPIC -DPIC -o thirdparty/boost/asm/.libs/make_x86_64_sysv_elf_gas.o
/bin/sh /root/codeDir/cppCode/study/libtool --mode=compile cc -I. -I/root/codeDir/cppCode/study -DPHP_ATOM_INC -I/root/codeDir/cppCode/study/include -I/root/codeDir/cppCode/study/main -I/root/codeDir/cppCode/study -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -I/root/codeDir/cppCode/study -I/root/codeDir/cppCode/study/include -DHAVE_CONFIG_H -Wall -pthread -g -O2 -c /root/codeDir/cppCode/study/thirdparty/boost/asm/jump_x86_64_sysv_elf_gas.S -o thirdparty/boost/asm/jump_x86_64_sysv_elf_gas.lo
cc -I. -I/root/codeDir/cppCode/study -DPHP_ATOM_INC -I/root/codeDir/cppCode/study/include -I/root/codeDir/cppCode/study/main -I/root/codeDir/cppCode/study -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -I/root/codeDir/cppCode/study -I/root/codeDir/cppCode/study/include -DHAVE_CONFIG_H -Wall -pthread -g -O2 -c /root/codeDir/cppCode/study/thirdparty/boost/asm/jump_x86_64_sysv_elf_gas.S -fPIC -DPIC -o thirdparty/boost/asm/.libs/jump_x86_64_sysv_elf_gas.o
/bin/sh /root/codeDir/cppCode/study/libtool --mode=link g++ -DPHP_ATOM_INC -I/root/codeDir/cppCode/study/include -I/root/codeDir/cppCode/study/main -I/root/codeDir/cppCode/study -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib -I/root/codeDir/cppCode/study -I/root/codeDir/cppCode/study/include -DHAVE_CONFIG_H -Wall -pthread -g -O2 -o study.la -export-dynamic -avoid-version -prefer-pic -module -rpath /root/codeDir/cppCode/study/modules study.lo study_coroutine.lo study_coroutine_util.lo thirdparty/boost/asm/make_x86_64_sysv_elf_gas.lo thirdparty/boost/asm/jump_x86_64_sysv_elf_gas.lo
g++ -shared -nostdlib /usr/lib/gcc/x86_64-alpine-linux-musl/8.3.0/../../../../lib/crti.o /usr/lib/gcc/x86_64-alpine-linux-musl/8.3.0/crtbeginS.o .libs/study.o .libs/study_coroutine.o .libs/study_coroutine_util.o thirdparty/boost/asm/.libs/make_x86_64_sysv_elf_gas.o thirdparty/boost/asm/.libs/jump_x86_64_sysv_elf_gas.o -L/usr/lib/gcc/x86_64-alpine-linux-musl/8.3.0 -L/usr/lib/gcc/x86_64-alpine-linux-musl/8.3.0/../../../../x86_64-alpine-linux-musl/lib/../lib -L/usr/lib/gcc/x86_64-alpine-linux-musl/8.3.0/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-alpine-linux-musl/8.3.0/../../../../x86_64-alpine-linux-musl/lib -L/usr/lib/gcc/x86_64-alpine-linux-musl/8.3.0/../../.. -lstdc++ -lm -lssp_nonshared -lpthread -lc -lgcc_s /usr/lib/gcc/x86_64-alpine-linux-musl/8.3.0/crtendS.o /usr/lib/gcc/x86_64-alpine-linux-musl/8.3.0/../../../../lib/crtn.o -pthread -Wl,-soname -Wl,study.so -o .libs/study.so
creating study.la
(cd .libs && rm -f study.la && ln -s ../study.la study.la)
/bin/sh /root/codeDir/cppCode/study/libtool --mode=install cp ./study.la /root/codeDir/cppCode/study/modules
cp ./.libs/study.so /root/codeDir/cppCode/study/modules/study.so
cp ./.libs/study.lai /root/codeDir/cppCode/study/modules/study.la
PATH="$PATH:/sbin" ldconfig -n /root/codeDir/cppCode/study/modules
----------------------------------------------------------------------
Libraries have been installed in:
/root/codeDir/cppCode/study/modules
If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
- add LIBDIR to the `LD_LIBRARY_PATH' environment variable
during execution
- add LIBDIR to the `LD_RUN_PATH' environment variable
during linking
- use the `-Wl,--rpath -Wl,LIBDIR' linker flag
See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
Build complete.
Don't forget to run 'make test'.
......@@ -20,6 +20,7 @@
PHP_MINIT_FUNCTION(study)
{
study_coroutine_util_init();
return SUCCESS;
}
......
#ifndef STUDY_COROUTINE_H
#define STUDY_COROUTINE_H
#include "php_study.h"
namespace Study
{
class PHPCoroutine
{
static long create(zend_fcall_info_cache *fci_cache, uint32_t argc, zval *argv);
};
}
#endif /* STUDY_COROUTINE_H */
\ No newline at end of file
#include "study_coroutine.h"
ZEND_BEGIN_ARG_INFO_EX(arginfo_study_coroutine_create, 0, 0, 1)
ZEND_ARG_CALLABLE_INFO(0, func, 0)
ZEND_END_ARG_INFO()
static PHP_METHOD(study_coroutine_util, create);
PHP_METHOD(study_coroutine_util, create)
{
php_printf("success!\n");
}
static const zend_function_entry study_coroutine_util_methods[] =
{
PHP_ME(study_coroutine_util, create, arginfo_study_coroutine_create, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
PHP_FE_END
};
/**
* Define zend class entry
*/
zend_class_entry study_coroutine_ce;
zend_class_entry *study_coroutine_ce_ptr;
void study_coroutine_util_init()
{
INIT_NS_CLASS_ENTRY(study_coroutine_ce, "Study", "Coroutine", study_coroutine_util_methods);
study_coroutine_ce_ptr = zend_register_internal_class(&study_coroutine_ce TSRMLS_CC); // Registered in the Zend Engine
}
\ No newline at end of file
<?php
echo "execute the script\n";
\ No newline at end of file
Study\Coroutine::create();
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册