powerman / perl-IO-Stream

Perl module: IO::Stream - ease non-blocking I/O streams based on EV
https://metacpan.org/release/IO-Stream
Other
0 stars 1 forks source link

100% CPU if not call close after get EOF #3

Open wangvisual opened 1 week ago

wangvisual commented 1 week ago

One of my program has a bug, it forget to call close() after got EOF, then the program use 100% CPU, strace shows it continue to call read():

clock_gettime(CLOCK_MONOTONIC, {tv_sec=2453951, tv_nsec=921150570}) = 0 epoll_wait(4, [{EPOLLIN, {u32=17, u64=21474836497}}], 64, 3416) = 1 clock_gettime(CLOCK_MONOTONIC, {tv_sec=2453951, tv_nsec=921167046}) = 0 read(17, "", 8192) = 0 clock_gettime(CLOCK_MONOTONIC, {tv_sec=2453951, tv_nsec=921183697}) = 0 epoll_wait(4, [{EPOLLIN, {u32=17, u64=21474836497}}], 64, 3416) = 1 clock_gettime(CLOCK_MONOTONIC, {tv_sec=2453951, tv_nsec=921215171}) = 0 read(17, "", 8192) = 0 clock_gettime(CLOCK_MONOTONIC, {tv_sec=2453951, tv_nsec=921232568}) = 0 epoll_wait(4, [{EPOLLIN, {u32=17, u64=21474836497}}], 64, 3416) = 1 clock_gettime(CLOCK_MONOTONIC, {tv_sec=2453951, tv_nsec=921249128}) = 0 read(17, "", 8192) = 0 clock_gettime(CLOCK_MONOTONIC, {tv_sec=2453951, tv_nsec=921265710}) = 0 epoll_wait(4, [{EPOLLIN, {u32=17, u64=21474836497}}], 64, 3416) = 1 clock_gettime(CLOCK_MONOTONIC, {tv_sec=2453951, tv_nsec=921282208}) = 0

undef $self->{_r} can solve this issue: elsif (!$m->{is_eof}) { # EOF delivered only once $m->{is_eof} = 1; $m->EVENT(EOF); $self->{_r} = undef; # add this line }

powerman commented 1 week ago

Well… This looks like a valid fix, but it's unclear is it good idea to fix this at all - after all current behaviour helps you to find a bug (forgotten close() call).

I do not remember is Perl supports half-closed file handles. If yes, and you'll provide a test case which shows this issue in a real use-case then I agree this issue must be fixed. Such test might work this way:

wangvisual commented 1 week ago

agree, maybe just put a notice in the doc, that one have to close the stream once got EOF.

powerman commented 1 week ago

Well, it looks like Perl does support half-closed sockets: shutdown($socket, 0);. This means it's valid to continue using socket after EOF, but probably you should somehow react on EOF - either with close or with shutdown.

In any case to make any changes (even doc fix) I need a code example which reproduces this issue. It let me test is proposed solutions (including shutdown()) actually works. Doc fix sounds trivial, but we need to consider other possible use cases and consequences: e.g. how this will work with a chain of a plugins (which has their own sockets and thus shutdown for a top one might not fix CPU issue in a plugin, etc.).