Swoole-src: Pop on empty channel does not blocking main coroutine

Created on 10 May 2020  ·  2Comments  ·  Source: swoole/swoole-src

  1. What did you do? If possible, provide a simple script for reproducing the error.
<?php

\Co\run(function () {
    var_dump('coro run');

    $chan = new \Co\Channel(1);

    $res = $chan->pop();
    var_dump("pop", $res);
});

var_dump("after coro");
  1. What did you expect to see?
    The "After coro" message should never be printed, because of $chan->pop() on empty channel should lead to an infinite waiting.

  2. What did you see instead?
    Channel gets automatically closed because coroutine scheduler has switched execution flow outside of the coroutine.

[2020-05-10 13:20:48 @20086.0]  TRACE   php_swoole_reactor_init(:254): init reactor
[2020-05-10 13:20:48 @20086.0]  TRACE   Context(:42): alloc stack: size=2097152, ptr=0x7fa38cc88010
[2020-05-10 13:20:48 @20086.0]  TRACE   main_func(:685): Create coro id: 1, origin cid: -1, coro total count: 1, heap size: 1285832
string(8) "coro run"
[2020-05-10 13:20:48 @20086.0]  TRACE   yield(:52): consumer cid=1
[2020-05-10 13:20:48 @20086.0]  TRACE   on_yield(:544): php_coro_yield from cid=1 to cid=-1
string(10) "after coro"
[2020-05-10 13:20:48 @20086.0]  TRACE   close(:159): channel closed
[2020-05-10 13:20:48 @20086.0]  TRACE   pop_coroutine(:146): resume consumer cid=1
[2020-05-10 13:20:48 @20086.0]  TRACE   on_resume(:556): php_coro_resume from cid=-1 to cid=1
string(3) "pop"
bool(false)
[2020-05-10 13:20:48 @20086.0]  TRACE   on_close(:589): coro close cid=1 and resume to -1, 0 remained. usage size: 1276688. malloc size: 2097152
[2020-05-10 13:20:48 @20086.0]  TRACE   close(:94): coroutine#1 stack memory use less than 65536 bytes
[2020-05-10 13:20:48 @20086.0]  TRACE   ~Context(:74): free stack: ptr=0x7fa38cc88010
  1. What version of Swoole are you using (show your php --ri swoole)?
swoole

Swoole => enabled
Author => Swoole Team <[email protected]>
Version => 4.5.0
Built => May 10 2020 06:50:53
coroutine => enabled
debug => enabled
trace_log => enabled
epoll => enabled
eventfd => enabled
signalfd => enabled
cpu_affinity => enabled
spinlock => enabled
rwlock => enabled
openssl => OpenSSL 1.1.1f  31 Mar 2020
http2 => enabled
pcre => enabled
zlib => 1.2.11
brotli => E16777223/D16777223
mutex_timedlock => enabled
pthread_barrier => enabled
futex => enabled
async_redis => enabled

Directive => Local Value => Master Value
swoole.enable_coroutine => On => On
swoole.enable_library => On => On
swoole.enable_preemptive_scheduler => Off => Off
swoole.display_errors => On => On
swoole.use_shortname => On => On
swoole.unixsock_buffer_size => 8388608 => 8388608
  1. What is your machine environment used (including version of kernel & php & gcc) ?
    WSL 2 (Ubuntu 20.04), PHP 7.4.3, gcc v9.3.0
good question

Most helpful comment

@codercms

It's one of Swoole's designs. The Swoole kernel does not make the state of the channel an exit condition for the event scheduler. in Swoole 4.5, you can customize the exit condition for the event scheduler:

<?php

use Swoole\Coroutine;
use Swoole\Coroutine\Channel;

use function Swoole\Coroutine\run;

run(function () {
    var_dump('coro run');

    $chan = new Channel(1);

    Coroutine::set([
        'exit_condition' => function () use ($chan) {
            return $chan->stats()['consumer_num'] === 0;
        }
    ]);

    $res = $chan->pop();
    var_dump("pop", $res);
});

var_dump("after coro");

All 2 comments

@codercms

It's one of Swoole's designs. The Swoole kernel does not make the state of the channel an exit condition for the event scheduler. in Swoole 4.5, you can customize the exit condition for the event scheduler:

<?php

use Swoole\Coroutine;
use Swoole\Coroutine\Channel;

use function Swoole\Coroutine\run;

run(function () {
    var_dump('coro run');

    $chan = new Channel(1);

    Coroutine::set([
        'exit_condition' => function () use ($chan) {
            return $chan->stats()['consumer_num'] === 0;
        }
    ]);

    $res = $chan->pop();
    var_dump("pop", $res);
});

var_dump("after coro");

@huanghantao got it, thanks for your note

Was this page helpful?
0 / 5 - 0 ratings