swoole_process源码分析之进程start过程

前一篇文章我们分析了进程的构造过程,这篇我们开始分析其start过程,start通过执行底层fork系统调用,启动进程,在PHP侧的执行原型如下:

$pid = $process->start();

函数执行成功,则返回子进程的PID,执行失败返回false。可以通过$process->pid和$process->pipe分别获取子进程的PID和管道的文件描述符,而在start过程中子进程会继承父进程的内存和文件句柄,同时会清除从父进程继承的EventLoopSignalTimer。

下面我们开始分析代码。

static PHP_METHOD(swoole_process, start)
{
    swWorker *process = swoole_get_object(getThis());//获取内部对象swWorker信息

    if (process->pid > 0 && kill(process->pid, 0) == 0)//进程已经在运行中
    {
        swoole_php_fatal_error(E_WARNING, "process has already been started.");
        RETURN_FALSE;
    }

    pid_t pid = fork();//调用fork系统调用创建进程
    if (pid < 0)//fork失败,fork一般在内存不足等情况会出现失败的情况
    {
        swoole_php_fatal_error(E_WARNING, "fork() failed. Error: %s[%d]", strerror(errno), errno);
        RETURN_FALSE;
    }
    else if (pid > 0) //父进程逻辑
    {
        process->pid = pid;//赋值进程号信息
        process->child_process = 0;//标记为不是子进程
        zend_update_property_long(swoole_server_class_entry_ptr, getThis(), ZEND_STRL("pid"), process->pid TSRMLS_CC);//设置swoole_process的pid属性信息
        RETURN_LONG(pid);//父进程返回子进程的进程ID信息
    }
    else //pid=0的情况,也就是子进程的逻辑
    {
        process->child_process = 1;//标记为子进程
        //执行子进程的逻辑
        SW_CHECK_RETURN(php_swoole_process_start(process, getThis() TSRMLS_CC));
    }
    RETURN_TRUE;
}
int php_swoole_process_start(swWorker *process, zval *object TSRMLS_DC)
{
    process->pipe = process->pipe_worker;//进程管道信息
    process->pid = getpid();//进程号信息

    if (process->redirect_stdin)//如果PHP端设置了标准输入的重定向属性
    {
        if (dup2(process->pipe, STDIN_FILENO) < 0)//将进程的标准输入重定向到管道中
        {
            swoole_php_fatal_error(E_WARNING, "dup2() failed. Error: %s[%d]", strerror(errno), errno);
        }
    }

    if (process->redirect_stdout)//如果PHP端设置了标准输出的重定向属性
    {
        if (dup2(process->pipe, STDOUT_FILENO) < 0)//将进程的标准输出重定向到管道中
        {
            swoole_php_fatal_error(E_WARNING, "dup2() failed. Error: %s[%d]", strerror(errno), errno);
        }
    }

    if (process->redirect_stderr)//如果PHP端设置了标准错误的重定向属性
    {
        if (dup2(process->pipe, STDERR_FILENO) < 0)//将进程的标准错误重定向到管道中
        {
            swoole_php_fatal_error(E_WARNING, "dup2() failed. Error: %s[%d]", strerror(errno), errno);
        }
    }

    //注销进程的主事件管理器
    if (SwooleG.main_reactor)
    {
        SwooleG.main_reactor->free(SwooleG.main_reactor);
        SwooleG.main_reactor = NULL;
        swTraceLog(SW_TRACE_PHP, "destroy reactor");
    }

#ifdef SW_COROUTINE
    swLinkedList *coro_timeout_list = SwooleWG.coro_timeout_list;
#endif

    bzero(&SwooleWG, sizeof(SwooleWG));
    SwooleG.pid = process->pid;//设置SwooleG的pid信息,SwooleG抽象的是主进程信息
    if (SwooleG.process_type != SW_PROCESS_USERWORKER)
    {
        SwooleG.process_type = 0;//进程类型信息
    }

    SwooleWG.id = process->id;//SwooleWG抽象的是用户端worker的信息,这里设置SwooleWG的id属性

#ifdef SW_COROUTINE
    SwooleWG.coro_timeout_list = coro_timeout_list;
#endif

    if (SwooleG.timer.fd)//清理所有定时器信息
    {
        swTimer_free(&SwooleG.timer);
        bzero(&SwooleG.timer, sizeof(SwooleG.timer));
    }

    swSignal_clear();//清理所有的信号处理器

    zend_update_property_long(swoole_process_class_entry_ptr, object, ZEND_STRL("pid"), process->pid TSRMLS_CC);//设置swoole_process对象的pid属性,设置为当前进程ID,也就是子进程的进程ID
    zend_update_property_long(swoole_process_class_entry_ptr, object, ZEND_STRL("pipe"), process->pipe_worker TSRMLS_CC);//设置swoole_process对象的pipe属性

    zval *zcallback = sw_zend_read_property(swoole_process_class_entry_ptr, object, ZEND_STRL("callback"), 0 TSRMLS_CC);//读取PHP业务端设置的callback函数信息
    zval **args[1];

    if (zcallback == NULL || ZVAL_IS_NULL(zcallback))//读取异常
    {
        swoole_php_fatal_error(E_ERROR, "no callback.");
        return SW_ERR;
    }

    zval *retval = NULL;
    args[0] = &object;
    sw_zval_add_ref(&object);

    if (sw_call_user_function_ex(EG(function_table), NULL, zcallback, &retval, 1, args, 0, NULL TSRMLS_CC) == FAILURE)//执行业务端的callback函数
    {
        swoole_php_fatal_error(E_ERROR, "callback function error");
        return SW_ERR;
    }
    if (EG(exception))//出现异常信息
    {
        zend_exception_error(EG(exception), E_ERROR TSRMLS_CC);//调用PHP底层函数处理异常信息
    }

    if (retval)
    {
        sw_zval_ptr_dtor(&retval);
    }

    if (SwooleG.main_reactor)//这一步显得多余,上面已经把SwooleG.main_reactor设置为null了。
    {
        php_swoole_event_wait();
    }

    SwooleG.running = 0;//标记SwooleG为未运行状态

    zend_bailout();
    return SW_OK;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值