提交 4563e0fb 编写于 作者: C codinghuang

update the code

上级 5534930f
......@@ -28,3 +28,4 @@ PHP版本:7.3.5
[11、协程创建(六)](./docs/《PHP扩展开发》-协程-协程创建(六).md)
[12、协程创建(七)](./docs/《PHP扩展开发》-协程-协程创建(七).md)
\ No newline at end of file
......@@ -51,6 +51,7 @@ if test "$PHP_STUDY" != "no"; then
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}
"
......
# 协程创建(七)
我们在上篇文章,成功的保存了主协程的上下文信息,现在,我们就需要为我们的任务函数创建协程了。
我们在`PHPCoroutine::create`中写入:
```cpp
long PHPCoroutine::create(zend_fcall_info_cache *fci_cache, uint32_t argc, zval *argv)
{
php_coro_args php_coro_args;
php_coro_args.fci_cache = fci_cache;
php_coro_args.argv = argv;
php_coro_args.argc = argc;
save_task(get_task());
return Coroutine::create(create_func, (void*) &php_coro_args);
}
```
其中,`PHPCoroutine::create_func`是用来创建协程任务函数的。它是:
```cpp
typedef void(* coroutine_func_t)(void *)
```
类型的函数指针。
`php_coro_args`则是传递给`create_func`的参数。
OK,我们现在来实现一下`PHPCoroutine::create_func`。我们先在`Study::PHPCoroutine`类中声明一下这个方法:
```cpp
protected:
static void create_func(void *arg);
```
然后,我们在文件`study_coroutine.cc`中来实现这个函数:
```cpp
```
......@@ -104,4 +104,7 @@ protected:
void *task = nullptr;
```
这样,我们就实现了保存`PHP`协程栈的功能。
\ No newline at end of file
这样,我们就实现了保存`PHP`协程栈的功能。
[下一篇:协程创建(七)](./《PHP扩展开发》-协程-协程创建(七).md)
#ifndef ASM_CONTEXT_H
#define ASM_CONTEXT_H
#include "study.h"
typedef void* fcontext_t;
intptr_t jump_fcontext(fcontext_t *ofc, fcontext_t nfc, intptr_t vp, bool preserve_fpu = false);
fcontext_t make_fcontext(void *sp, size_t size, void (*fn)(intptr_t));
#endif /* ASM_CONTEXT_H */
\ No newline at end of file
#ifndef CONTEXT_H
#define CONTEXT_H
#include "asm_context.h"
typedef fcontext_t coroutine_context_t;
typedef void (*coroutine_func_t)(void*);
namespace Study
{
class Context
{
public:
Context(size_t stack_size, coroutine_func_t fn, void* private_data);
~Context();
bool swap_in();
bool swap_out();
static void context_func(void* arg); // coroutine entry function
protected:
coroutine_context_t ctx_;
coroutine_context_t swap_ctx_;
coroutine_func_t fn_;
char* stack_;
uint32_t stack_size_;
void *private_data_;
bool end_;
};
}
#endif /* CONTEXT_H */
......@@ -2,19 +2,45 @@
#define COROUTINE_H
#include "context.h"
#include <unordered_map>
namespace Study
{
class Coroutine
{
public:
static std::unordered_map<long, Coroutine*> coroutines;
static void* get_current_task();
static long create(coroutine_func_t fn, void* args = nullptr);
void* get_task();
static Coroutine* get_current();
void set_task(void *_task);
protected:
Coroutine *origin;
static Coroutine* current;
void *task = nullptr;
static size_t stack_size;
Context ctx;
long cid;
static long last_cid;
Coroutine(coroutine_func_t fn, void *private_data) :
ctx(stack_size, fn, private_data)
{
cid = ++last_cid;
coroutines[cid] = this;
}
inline long run()
{
long cid = this->cid;
origin = current;
current = this;
ctx.swap_in();
return cid;
}
};
}
......
#include "context.h"
#include "study.h"
using Study::Context;
Context::Context(size_t stack_size, coroutine_func_t fn, void* private_data) :
fn_(fn), stack_size_(stack_size), private_data_(private_data)
{
#ifdef SW_CONTEXT_PROTECT_STACK_PAGE
protect_page_ = 0;
#endif
end_ = false;
swap_ctx_ = nullptr;
stack_ = (char*) malloc(stack_size_);
void* sp = (void*) ((char*) stack_ + stack_size_);
ctx_ = make_fcontext(sp, stack_size_, (void (*)(intptr_t))&context_func);
}
bool Context::swap_in()
{
jump_fcontext(&swap_ctx_, ctx_, (intptr_t) this, true);
return true;
}
bool Context::swap_out()
{
jump_fcontext(&ctx_, swap_ctx_, (intptr_t) this, true);
return true;
}
void Context::context_func(void *arg)
{
Context *_this = (Context *) arg;
_this->fn_(_this->private_data_);
_this->end_ = true;
_this->swap_out();
}
\ No newline at end of file
......@@ -3,6 +3,8 @@
using Study::Coroutine;
Coroutine* Coroutine::current = nullptr;
long Coroutine::last_cid = 0;
std::unordered_map<long, Coroutine*> Coroutine::coroutines;
void* Coroutine::get_current_task()
{
......@@ -12,4 +14,19 @@ void* Coroutine::get_current_task()
void* Coroutine::get_task()
{
return task;
}
Coroutine* Coroutine::get_current()
{
return current;
}
void Coroutine::set_task(void *_task)
{
task = _task;
}
long Coroutine::create(coroutine_func_t fn, void* args)
{
return (new Coroutine(fn, args))->run();
}
\ No newline at end of file
......@@ -12,7 +12,8 @@ long PHPCoroutine::create(zend_fcall_info_cache *fci_cache, uint32_t argc, zval
php_coro_args.argv = argv;
php_coro_args.argc = argc;
save_task(get_task());
return 0;
return Coroutine::create(create_func, (void*) &php_coro_args);
}
php_coro_task* PHPCoroutine::get_task()
......@@ -34,3 +35,69 @@ void PHPCoroutine::save_vm_stack(php_coro_task *task)
task->vm_stack_page_size = EG(vm_stack_page_size);
task->execute_data = EG(current_execute_data);
}
void PHPCoroutine::create_func(void *arg)
{
int i;
php_coro_args *php_arg = (php_coro_args *) arg;
zend_fcall_info_cache fci_cache = *php_arg->fci_cache;
zend_function *func = fci_cache.function_handler;
zval *argv = php_arg->argv;
int argc = php_arg->argc;
php_coro_task *task;
zend_execute_data *call;
zval _retval, *retval = &_retval;
vm_stack_init(); // get a new php stack
call = (zend_execute_data *) (EG(vm_stack_top));
task = (php_coro_task *) EG(vm_stack_top);
EG(vm_stack_top) = (zval *) ((char *) call + PHP_CORO_TASK_SLOT * sizeof(zval));
call = zend_vm_stack_push_call_frame(
ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED,
func, argc, fci_cache.called_scope, fci_cache.object
);
for (i = 0; i < argc; ++i)
{
zval *param;
zval *arg = &argv[i];
param = ZEND_CALL_ARG(call, i + 1);
ZVAL_COPY(param, arg);
}
call->symbol_table = NULL;
EG(current_execute_data) = call;
save_vm_stack(task);
task->co = Coroutine::get_current();
task->co->set_task((void *) task);
if (func->type == ZEND_USER_FUNCTION)
{
ZVAL_UNDEF(retval);
EG(current_execute_data) = NULL;
zend_init_func_execute_data(call, &func->op_array, retval);
zend_execute_ex(EG(current_execute_data));
}
zval_ptr_dtor(retval);
}
void PHPCoroutine::vm_stack_init(void)
{
uint32_t size = DEFAULT_PHP_STACK_PAGE_SIZE;
zend_vm_stack page = (zend_vm_stack) emalloc(size);
page->top = ZEND_VM_STACK_ELEMENTS(page);
page->end = (zval*) ((char*) page + size);
page->prev = NULL;
EG(vm_stack) = page;
EG(vm_stack)->top++;
EG(vm_stack_top) = EG(vm_stack)->top;
EG(vm_stack_end) = EG(vm_stack)->end;
EG(vm_stack_page_size) = size;
}
......@@ -4,6 +4,9 @@
#include "php_study.h"
#include "coroutine.h"
#define DEFAULT_PHP_STACK_PAGE_SIZE 8192
#define PHP_CORO_TASK_SLOT ((int)((ZEND_MM_ALIGNED_SIZE(sizeof(php_coro_task)) + ZEND_MM_ALIGNED_SIZE(sizeof(zval)) - 1) / ZEND_MM_ALIGNED_SIZE(sizeof(zval))))
struct php_coro_args
{
zend_fcall_info_cache *fci_cache;
......@@ -19,6 +22,7 @@ struct php_coro_task
zend_vm_stack vm_stack; // current coroutine stack pointer
size_t vm_stack_page_size;
zend_execute_data *execute_data; // current coroutine stack frame
Study::Coroutine *co;
};
namespace Study
......@@ -34,6 +38,8 @@ protected:
static void save_task(php_coro_task *task);
static void save_vm_stack(php_coro_task *task);
static php_coro_task* get_task();
static void create_func(void *arg);
static void vm_stack_init(void);
};
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册