1. 程式人生 > >swoole_process原始碼分析之alarm操作

swoole_process原始碼分析之alarm操作

swoole_process提供的alarm是個高精度定時器,是作業系統setitimer系統呼叫的封裝,可以設定微秒級別的定時器。定時器會觸發訊號,需要與swoole_process::signalpcntl_signal配合使用。

function swoole_process::alarm(int $interval_usec, int $type = ITIMER_REAL) : bool
  • $interval_usec 定時器間隔時間,單位為微秒。如果為負數表示清除定時器
  • $type 定時器型別,0 表示為真實時間,觸發SIGALAM訊號,1 表示使用者態CPU時間,觸發SIGVTALAM
    訊號,2 表示使用者態+核心態時間,觸發SIGPROF訊號
  • 設定成功返回true,失敗返回false,可以使用swoole_errno得到錯誤碼

下面我們分析下其流程。

static PHP_METHOD(swoole_process, alarm)
{
    long usec = 0;
    long type = ITIMER_REAL;
    
    //解析輸入引數,其中usec表示定時器時間,單位為微秒;type表示定時器型別,具體參考上述php介面
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &usec, &type) == FAILURE)
    {
        return;
    }

    if (!SWOOLE_G(cli))
    {
        swoole_php_fatal_error(E_ERROR, "cannot use swoole_process::alarm here.");
        RETURN_FALSE;
    }

    if (SwooleG.timer.fd != 0)//如果已經設定了其他定時事件,則不允許重複設定
    {
        swoole_php_fatal_error(E_WARNING, "cannot use both 'timer' and 'alarm' at the same time.");
        RETURN_FALSE;
    }

    struct timeval now;
    if (gettimeofday(&now, NULL) < 0)//獲取當前時間
    {
        swoole_php_error(E_WARNING, "gettimeofday() failed. Error: %s[%d]", strerror(errno), errno);
        RETURN_FALSE;
    }

    struct itimerval timer_set;//定義時間變數,這個主要用於後續的其他系統呼叫
    bzero(&timer_set, sizeof(timer_set));//初始化

    if (usec > 0)
    {
        long _sec = usec / 1000000;
        long _usec = usec - (_sec * 1000000);

        timer_set.it_interval.tv_sec = _sec;
        timer_set.it_interval.tv_usec = _usec;

        timer_set.it_value.tv_sec = _sec;
        timer_set.it_value.tv_usec = _usec;

        if (timer_set.it_value.tv_usec > 1e6)
        {
            timer_set.it_value.tv_usec = timer_set.it_value.tv_usec - 1e6;
            timer_set.it_value.tv_sec += 1;
        }
    }

    if (setitimer(type, &timer_set, NULL) < 0)
    {
        swoole_php_error(E_WARNING, "setitimer() failed. Error: %s[%d]", strerror(errno), errno);
        RETURN_FALSE;
    }

    RETURN_TRUE;
}