cgdb php GNU gdb (GDB) 8.0.1 Copyright (C) 2017 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-alpine-linux-musl". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from php...(no debugging symbols found)...done. (gdb)
分别在上面的两个函数打断点:
1 2 3 4 5 6 7 8 9 10 11 12
(gdb) b zif_swoole_coroutine_create Function "zif_swoole_coroutine_create" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (zif_swoole_coroutine_create) pending. (gdb) b swoole::PHPCoroutine::create Function "swoole::PHPCoroutine::create" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 2 (swoole::PHPCoroutine::create) pending. (gdb) b swoole::Coroutine::create Function "swoole::Coroutine::create" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 3 (swoole::Coroutine::create) pending.
然后运行测试脚本:
1 2 3 4 5 6
(gdb) r test.php Starting program: /usr/local/bin/php test.php
Breakpoint 1, zif_swoole_coroutine_create (execute_data=0x7ffff681c0d0, return_value=0x7fffffffb090) at /root/codeDir/cCode/swoole-src/swoole_coroutine_util.cc:416 warning: Source file is more recent than executable. (gdb)
(gdb) u 420 zif_swoole_coroutine_create (execute_data=0x7ffff681c0d0, return_value=0x7fffffffb090) at /root/codeDir/cCode/swoole-src/swoole_coroutine_util.cc:420 (gdb)
(gdb) u 425 zif_swoole_coroutine_create (execute_data=0x7ffff681c0d0, return_value=0x7fffffffb090) at /root/codeDir/cCode/swoole-src/swoole_coroutine_util.cc:425 (gdb)
(gdb) p fci.params $9 = (zval *) 0x0 (gdb) p fci.param_count $10 = 0 (gdb)
因为我们这里只给go()函数传递了一个协程函数,所以参数为空。
OK,我们继续往下走:
1 2 3 4 5 6 7 8 9 10 11
(gdb) c Continuing.
Breakpoint 2, 0x00007ffff485ad00 in swoole::PHPCoroutine::create(_zend_fcall_info_cache*, unsigned int, _zval_struct*)@plt () from /usr/local/lib/php/extensions/no-debug-non-zts-20170718/swoole.so (gdb) n Single stepping until exit from function _ZN6swoole12PHPCoroutine6createEP22_zend_fcall_info_cachejP12_zval_struct@plt, which has no line number information.
Breakpoint 2, swoole::PHPCoroutine::create (fci_cache=fci_cache@entry=0x7fffffffafa0, argc=0, argv=0x0) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:418 warning: Source file is more recent than executable. (gdb)
1 2 3 4 5 6 7 8 9 10 11 12
417│ longPHPCoroutine::create(zend_fcall_info_cache *fci_cache, uint32_t argc, zval *argv) 418├>{ 419│ if (unlikely(!active)) 420│ { 421│ if (zend_hash_str_find_ptr(&module_registry, ZEND_STRL("xdebug"))) 422│ { 423│ swoole_php_fatal_error(E_WARNING, "Using Xdebug in coroutines is extremely dangerous, please notice that it may lead to coredump!"); 424│ } 425│ php_swoole_check_reactor(); 426│ // PHPCoroutine::enable_hook(SW_HOOK_ALL); // TODO: enable it in version 4.3.0 427│ active = true; 428│ }
此时就进入了swoole::PHPCoroutine::create这个函数。
421行是查找是否安装了xdebug这个扩展,因为这个扩展可能会导致coredump。
然后我们继续运行到425行之前:
1 2
(gdb) u 425 (gdb)
1 2 3
425├─555555> php_swoole_check_reactor(); 426│ // PHPCoroutine::enable_hook(SW_HOOK_ALL); // TODO: enable it in version 4.3.0 427│ active = true;
(gdb) b php_swoole_reactor_init Breakpoint 3 at 0x7ffff4825eb6: file /root/codeDir/cCode/swoole-src/swoole_event.c, line 190. (gdb) c Continuing.
Breakpoint 3, php_swoole_reactor_init () at /root/codeDir/cCode/swoole-src/swoole_event.c:190 (gdb)
1 2 3 4 5
190├───> if (!SWOOLE_G(cli)) 191│ { 192│ swoole_php_fatal_error(E_ERROR, "async-io must be used in PHP CLI mode"); 193│ return; 194│ }
190到194是用来判断当前的环境是否是cli模式。因为异步IO必须被使用在cli模式。
继续往下走:
1 2 3
(gdb) u 196 php_swoole_reactor_init () at /root/codeDir/cCode/swoole-src/swoole_event.c:196 (gdb)
1 2 3 4 5 6 7 8 9 10 11 12 13
196├───> if (SwooleG.serv) 197│ { 198│ if (swIsTaskWorker() && !SwooleG.serv->task_enable_coroutine) 199│ { 200│ swoole_php_fatal_error(E_ERROR, "Unable to use async-io in task processes, please set `task_enable_coroutine` to true"); 201│ return; 202│ } 203│ if (swIsManager()) 204│ { 205│ swoole_php_fatal_error(E_ERROR, "Unable to use async-io in manager process"); 206│ return; 207│ } 208│ }
(gdb) finish Run till exit from #0 php_swoole_reactor_init () at /root/codeDir/cCode/swoole-src/swoole_event.c:236 swoole::PHPCoroutine::create (fci_cache=0x7fffffffafc0, argc=0, argv=0x0) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:427 (gdb)
1
427├─777777> active = true;
赋值active为true代表协程可以使用了。
OK,继续执行:
1 2
(gdb) n (gdb)
1 2 3 4 5
429├───> if (unlikely(Coroutine::count() >= max_num)) 430│ { 431│ swoole_php_fatal_error(E_WARNING, "exceed max number of coroutine %zu", (uintmax_t) Coroutine::count()); 432│ return SW_CORO_ERR_LIMIT; 433│ }
(gdb) u 450 swoole::PHPCoroutine::create (fci_cache=0x7fffffffafc0, argc=0, argv=0x0) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:450 (gdb)
1
450├───> save_task(get_task());
其中get_task的作用是获取当前正在执行的协程。我们进入这个函数看看:
1 2 3 4
(gdb) s swoole::PHPCoroutine::get_task () at /root/codeDir/cCode/swoole-src/swoole_coroutine.h:113 warning: Source file is more recent than executable. (gdb)
(gdb) finish Run till exit from #0 swoole::PHPCoroutine::get_task () at /root/codeDir/cCode/swoole-src/swoole_coroutine.h:115 0x00007ffff481721f in swoole::PHPCoroutine::create (fci_cache=0x7fffffffafc0, argc=0, argv=0x0) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:450 Value returned is $7 = (php_coro_task *) 0x7ffff4b82620 <swoole::PHPCoroutine::main_task> (gdb)
(gdb) s swoole::PHPCoroutine::save_task (task=0x7ffff4b82620 <swoole::PHPCoroutine::main_task>) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:200 (gdb)
(gdb) s swoole::PHPCoroutine::save_vm_stack (task=0x7ffff4b82620 <swoole::PHPCoroutine::main_task>) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:135 (gdb)
(gdb) finish Run till exit from #0 swoole::PHPCoroutine::save_vm_stack (task=0x7ffff4b82620 <swoole::PHPCoroutine::main_task>) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:135 swoole::PHPCoroutine::save_task (task=0x7ffff4b82620 <swoole::PHPCoroutine::main_task>) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:201 (gdb)
(gdb) s swoole::PHPCoroutine::save_og (task=0x7ffff4b82620 <swoole::PHPCoroutine::main_task>) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:176 (gdb)
(gdb) finish Run till exit from #0 swoole::PHPCoroutine::save_og (task=0x7ffff4b82620 <swoole::PHPCoroutine::main_task>) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:186 swoole::PHPCoroutine::save_task (task=0x7ffff4b82620 <swoole::PHPCoroutine::main_task>) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:202 (gdb) finish Run till exit from #0 swoole::PHPCoroutine::save_task (task=0x7ffff4b82620 <swoole::PHPCoroutine::main_task>) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:202 swoole::PHPCoroutine::create (fci_cache=0x7fffffffafc0, argc=0, argv=0x0) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:452 (gdb)
Breakpoint 8, 0x00007ffff4767120 in swoole::Coroutine::create(void (*)(void*), void*)@plt () from /usr/local/lib/php/extensions/no-debug-non-zts-20170718/swoole.so (gdb) n Single stepping until exit from function _ZN6swoole9Coroutine6createEPFvPvES1_@plt, which has no line number information. swoole::Coroutine::create (fn=0x7ffff4817ab6 <swoole::PHPCoroutine::save_task(php_coro_task*)+36>, args=0x7fffffffaea0) at /root/codeDir/cCode/swoole-src/include/coroutine.h:133 (gdb)
(gdb) finish Run till exit from #0 swoole::Coroutine::Coroutine (this=0x5555566de6c0, fn=0x7ffff481633e <swoole::PHPCoroutine::create_func(void*)>, private_data=0x7fffffffaf00) at /root/codeDir/cCode/swoole-src/inclu de/coroutine.h:215 0x00007ffff481752e in swoole::Coroutine::create (fn=0x7ffff481633e <swoole::PHPCoroutine::create_func(void*)>, args=0x7fffffffaf00) at /root/codeDir/cCode/swoole-src/include/coroutine.h:135 (gdb)
(gdb) b swoole::Context::context_func(void*) Breakpoint 9 at 0x7ffff477e6d6: file /root/codeDir/cCode/swoole-src/src/coroutine/context.cc, line 124. (gdb) c Continuing.
Breakpoint 9, swoole::Context::context_func (arg=0x5555566de6d8) at /root/codeDir/cCode/swoole-src/src/coroutine/context.cc:124 (gdb)
(gdb) finish Run till exit from #0 swoole::Coroutine::run (this=0x5555566de6c0) at /root/codeDir/cCode/swoole-src/include/coroutine.h:236 0x00007ffff4817536 in swoole::Coroutine::create (fn=0x7ffff481633e <swoole::PHPCoroutine::create_func(void*)>, args=0x7fffffffaf00) at /root/codeDir/cCode/swoole-src/include/coroutine.h:135 Value returned is $18 = 1 (gdb)
(gdb) finish Run till exit from #0 swoole::Coroutine::create (fn=0x7ffff481633e <swoole::PHPCoroutine::create_func(void*)>, args=0x7fffffffaf00) at /root/codeDir/cCode/swoole-src/include/coroutine.h:136 swoole::PHPCoroutine::create (fci_cache=0x7fffffffafc0, argc=0, argv=0x0) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:453 Value returned is $19 = 1 (gdb)
(gdb) finish Run till exit from #0 swoole::PHPCoroutine::create (fci_cache=0x7fffffffafc0, argc=0, argv=0x0) at /root/codeDir/cCode/swoole-src/swoole_coroutine.cc:453 0x00007ffff481d033 in zif_swoole_coroutine_create (execute_data=0x7ffff681c0c0, return_value=0x7fffffffb090) at /root/codeDir/cCode/swoole-src/swoole_coroutine_util.cc:435 Value returned is $20 = 1 (gdb)