Skip to content

Commit 7bc0172

Browse files
authored
Merge pull request #123 from clue-labs/refcount
Fix ExtEventLoop to keep track of stream resources (refcount)
2 parents 61e3e65 + 4dd1532 commit 7bc0172

2 files changed

Lines changed: 42 additions & 1 deletion

File tree

src/ExtEventLoop.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class ExtEventLoop implements LoopInterface
2222
private $streamCallback;
2323
private $streamEvents = [];
2424
private $streamFlags = [];
25+
private $streamRefs = [];
2526
private $readListeners = [];
2627
private $writeListeners = [];
2728
private $running;
@@ -110,7 +111,8 @@ private function removeStream($stream)
110111
$this->streamFlags[$key],
111112
$this->streamEvents[$key],
112113
$this->readListeners[$key],
113-
$this->writeListeners[$key]
114+
$this->writeListeners[$key],
115+
$this->streamRefs[$key]
114116
);
115117
}
116118
}
@@ -224,6 +226,12 @@ private function subscribeStreamEvent($stream, $flag)
224226

225227
$this->streamEvents[$key] = $event;
226228
$this->streamFlags[$key] = $flag;
229+
230+
// ext-event does not increase refcount on stream resources for PHP 7+
231+
// manually keep track of stream resource to prevent premature garbage collection
232+
if (PHP_VERSION_ID >= 70000) {
233+
$this->streamRefs[$key] = $stream;
234+
}
227235
}
228236

229237
$event->add();

tests/AbstractLoopTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,39 @@ public function testAddReadStreamIgnoresSecondCallable()
6161
$this->tickLoop($this->loop);
6262
}
6363

64+
public function testAddReadStreamReceivesDataFromStreamReference()
65+
{
66+
$this->received = '';
67+
$this->subAddReadStreamReceivesDataFromStreamReference();
68+
$this->assertEquals('', $this->received);
69+
70+
$this->assertRunFasterThan($this->tickTimeout * 2);
71+
$this->assertEquals('[hello]X', $this->received);
72+
}
73+
74+
/**
75+
* Telper for above test. This happens in another helper method to verify
76+
* the loop keep track of assigned stream resources (refcount).
77+
*/
78+
private function subAddReadStreamReceivesDataFromStreamReference()
79+
{
80+
list ($input, $output) = $this->createSocketPair();
81+
82+
fwrite($input, 'hello');
83+
fclose($input);
84+
85+
$this->loop->addReadStream($output, function ($output) {
86+
$chunk = fread($output, 1024);
87+
if ($chunk === '') {
88+
$this->received .= 'X';
89+
$this->loop->removeReadStream($output);
90+
fclose($output);
91+
} else {
92+
$this->received .= '[' . $chunk . ']';
93+
}
94+
});
95+
}
96+
6497
public function testAddWriteStream()
6598
{
6699
list ($input) = $this->createSocketPair();

0 commit comments

Comments
 (0)