>  기사  >  php教程  >  PHP 커널 분석(2)

PHP 커널 분석(2)

黄舟
黄舟원래의
2016-12-19 11:06:111138검색

요약: 여기서 읽은 PHP 버전은 PHP-7.1.0 RC3이고, 코드를 읽는 플랫폼은 linuxZTS입니다. 기사에 여러 부분이 있음을 알 수 있습니다. #ifdef ZTS # 정의 CG(v) ZEND_TSRMG (compiler_globals_id, zend_compiler_globals * , v) #else # 정의 CG(v) (compi...

여기서 읽는 PHP 버전은 PHP-7.1.0 RC3이고, 코드를 읽는 플랫폼은 linux

ZTS

기사에 여러 군데가 있는 것을 볼 수 있습니다.

1    #ifdef ZTS    
2    # define CG(v) ZEND_TSRMG(compiler_globals_id, zend_compiler_globals *, v)    
3    #else    
4    # define CG(v) (compiler_globals.v)    
5    extern ZEND_API struct _zend_compiler_globals compiler_globals;    
6    #endif

여기서 ZTS의 개념은 무엇입니까? 우리가 자주 사용하는 PHP는 단일에서 실행됩니다. -cgi와 같은 단일 스레드 환경에서는 요청이 들어오면 하나의 프로세스만 이를 처리합니다. 따라서 예를 들어 PHP 커널은 여러 스레드가 있을 때 스레드 안전 문제를 고려하지 않습니다. 동시에 단일 프로세스 다중 스레드 서버로 발전하고 있으며, 이때 스레드 안전 문제를 구체적으로 처리할 레이어가 필요합니다. 관리), 그러나 PHP는 기본적으로 꺼져 있습니다. 컴파일할 때 스레드로부터 안전한 버전의 PHP를 컴파일할 수 있도록 매개변수를 지정할 수 있습니다(--enable-maintainer-zts 옵션, Windows 플랫폼은 --enable-zts). ) 이것이 ZTS의 유래입니다. 예를 들어 위의 예에서 CG(V)는 non-thread safety 하에서 전역 구조compiler_globals 구조체의 v 속성을 얻고, 이를 ZEND_TSREMG 메서드를 통해 얻습니다.

zend_try_catch와 관련된 코드는 다음과 같습니다.

매크로를 확장하면 다음과 같은 대략적인 코드를 볼 수 있습니다.

이게 무슨 뜻인가요? 먼저 setjmp와 longjmp를 이해해야 합니다. 이 두 함수는 Linux에서 제공하는 방법으로 코루틴의 기능을 구현하는 데 사용됩니다.

1    zend_try {    
2          ...exec_try    
3      } zend_catch {    
4          ...exec_catch    
5      } zend_end_try();
#include < ;stdio.h>

#include 141642a285ad26cf7e55efeead7f8373
01    {                                                            \    
02            JMP_BUF *__orig_bailout = EG(bailout);                    \    
03            JMP_BUF __bailout;                                        \    
04                                                                    \    
05            EG(bailout) = &__bailout;                                \    
06            if (SETJMP(__bailout)==0) {    
07              {    
08                   ...exec_try    
09              }    
10            } else {                                                \    
11                EG(bailout) = __orig_bailout;    
12               {    
13                   ...exec_catch    
14               }    
15           }                                                        \    
16           EG(bailout) = __orig_bailout;                            \    
17    }

jmp_buf env;

void foo() {

printf ("jmpn 이전");

int ret = setjmp(env)

if(ret == 0) {

return;

} else {

printf("return %dn", ret);

}

printf("jmpn 이후");

}

int main(int argc, char* argv[]) {

foo();

longjmp(env, 999);

return 0;

}// 출력:

/* jmp 이전

jmp 이후 999를 반환

*/

위의 예에서 setjmp는 프로그램 조각 1이 이니셔티브를 넘겨준 다음, longjmp를 만날 때까지 아래 프로그램을 실행하고 조각 1을 반환하는 것과 같습니다. 가 검색되고 jmp_buf가 999로 설정됩니다. 조각 1이 계속 실행되고 ret!=0이 발견되고 return 999가 출력됩니다.

좋아, 이 프로그램으로 돌아갑니다:

이 프로그램의 exec_try 코드 세그먼트에서 오류가 발생하여 반환해야 할 경우 longjmp 함수에 대한 호출이 포함되어 있습니다. 이러한 방식으로 try...catch...finnal을 호출하는 일반적인 기능이 형성됩니다.

1 먼저 전역 변수에 구제금융을 저장합니다.

2 setjmp를 사용하여 점프하고 다음 프로그램을 실행합니다.

3 exec_try

4 실행 exec_try 코드 세그먼트에 longjmp가 있고 longjmp가 0이 아닌 값을 반환하는 경우(일반적으로 실제로는 0이 아님) exec_catch
01    {                                                            \    
02            JMP_BUF *__orig_bailout = EG(bailout);                    \    
03            JMP_BUF __bailout;                                        \    
04                                                                    \    
05            EG(bailout) = &__bailout;                                \    
06            if (SETJMP(__bailout)==0) {    
07              {    
08                   ...exec_try    
09              }    
10            } else {                                                \    
11                EG(bailout) = __orig_bailout;    
12               {    
13                   ...exec_catch    
14               }    
15           }                                                        \    
16           EG(bailout) = __orig_bailout;                            \    
17    }
5를 실행합니다. 마지막으로 전역 변수에서 bailout을 복원합니다


여기서 두 가지 의문점이 있을 수 있습니다. exec_try에 longjmp가 없다면 어떻게 될까요? 그럼 그냥 exec_try를 직접 실행하고 exec_catch를 건너뛰세요. 이는 또한 try catch를 구현하기 위해 setjmp 및 longjmp를 사용하는 표준 방법이기도 합니다.

이 두 가지를 구현하면 goto 키워드가 함수 내부로만 이동할 수 있다는 제한 사항이 보완됩니다. 이것을 "멀리뛰기"라고 합니다.

따라서 PHP 코드에서 실행하는 함수가 예외를 발생시킬 수 있습니다. 이 방법을 사용하여 실행하려는 프로그램을 내부에 넣을 수도 있습니다.

위 내용은 PHP 커널 분석(2) 내용입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
이전 기사:PHP 커널 분석(1)다음 기사:PHP 커널 분석(1)