Swoole中参数持久化以及给闭包对象引用加一的作用?

发布于 2022-09-11 20:55:43 字数 1744 浏览 25 评论 0

在阅读Swoole定时器源码的时候,php_swoole_timer_add里面:
发现如果是调用了timer::after接口的话,那么话进行参数持久化的操作:

sw_zend_fci_params_persist(&fci->fci);

如果是调用了timer::tick的话,就不需要进行参数持久化的操作。
并且,最后还调用了sw_zend_fci_cache_persist来对闭包进行引用计数加一的操作。
我想知道为什么需要做这两个操作?如果不做这两个操作,会触发什么Bug呢?能否用一段完整的PHP代码来触发一下这个Bug呢?并且解释一下为什么会触发Bug。我想看看差异在哪,以及什么时候需要调用这两个函数。
目前,我写了一段简单的脚本:

<?php

namespace Swoole;

$str = "test";

Timer::after(1000, function() use ($str){
    echo "timeout, $str\n";
});

当我注释掉sw_zend_fci_cache_persist(&fci->fci_cache);的时候,会在PHP协程入口函数里面进入ZEND_INTERNAL_FUNCTION这个分支:

else /* ZEND_INTERNAL_FUNCTION */
{
    ZVAL_NULL(retval);
    call->prev_execute_data = NULL;
    call->return_value = NULL; /* this is not a constructor call */
    execute_internal(call, retval);
    zend_vm_stack_free_args(call);
}

然后报Segmentation fault错误。如果不注释掉sw_zend_fci_cache_persist(&fci->fci_cache);,那么就可以顺利的进入ZEND_USER_FUNCTION分支:

if (EXPECTED(func->type == ZEND_USER_FUNCTION))
{
    ZVAL_UNDEF(retval);
    // TODO: enhancement it, separate execute data is necessary, but we lose the backtrace
    EG(current_execute_data) = NULL;
#if PHP_VERSION_ID >= 70200
    zend_init_func_execute_data(call, &func->op_array, retval);
#else
    zend_init_execute_data(call, &func->op_array, retval);
#endif
    zend_execute_ex(EG(current_execute_data));
}

但是我不知道其中的原因。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文