Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14033788
D7775.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
5 KB
Referenced Files
None
Subscribers
None
D7775.diff
View Options
Index: src/channel/PhutilChannel.php
===================================================================
--- src/channel/PhutilChannel.php
+++ src/channel/PhutilChannel.php
@@ -86,8 +86,23 @@
/**
- * Wait (using select()) for activity on any channel. This method blocks until
- * some channel is ready to be updated.
+ * Wait for any activity on a list of channels. Convenience wrapper around
+ * @{method:waitForActivity}.
+ *
+ * @param list<PhutilChannel> A list of channels to wait for.
+ * @param dict Options, see above.
+ * @return void
+ *
+ * @task wait
+ */
+ public static function waitForAny(array $channels, array $options = array()) {
+ return self::waitForActivity($channels, $channels, $options);
+ }
+
+
+ /**
+ * Wait (using select()) for channels to become ready for reads or writes.
+ * This method blocks until some channel is ready to be updated.
*
* It does not provide a way to determine which channels are ready to be
* updated. The expectation is that you'll just update every channel. This
@@ -103,51 +118,66 @@
* NOTE: Extra streams must be //streams//, not //sockets//, because this
* method uses `stream_select()`, not `socket_select()`.
*
- * @param list<PhutilChannel> A list of channels to wait for.
- * @param dict Options, see above.
- * @return void
+ * @param list<PhutilChannel> List of channels to wait for reads on.
+ * @param list<PhutilChannel> List of channels to wait for writes on.
+ * @return void
*
* @task wait
*/
- public static function waitForAny(array $channels, array $options = array()) {
- assert_instances_of($channels, 'PhutilChannel');
+ public static function waitForActivity(
+ array $reads,
+ array $writes,
+ array $options = array()) {
+
+ assert_instances_of($reads, 'PhutilChannel');
+ assert_instances_of($writes, 'PhutilChannel');
$read = idx($options, 'read', array());
$write = idx($options, 'write', array());
$except = idx($options, 'except', array());
$wait = idx($options, 'timeout', 1);
- foreach ($channels as $channel) {
+ // TODO: It would be nice to just be able to categorically reject these as
+ // unselectable.
+ foreach (array($reads, $writes) as $channels) {
+ foreach ($channels as $channel) {
+ $r_sockets = $channel->getReadSockets();
+ $w_sockets = $channel->getWriteSockets();
+
+ // If any channel has no read sockets and no write sockets, assume it
+ // isn't selectable and return immediately (effectively degrading to a
+ // busy wait).
+
+ if (!$r_sockets && !$w_sockets) {
+ return false;
+ }
+ }
+ }
- // If any of the channels have data in read buffers, return immediately.
- // If we don't, we risk running select() on a bunch of sockets which won't
- // become readable because the data the application expects is already
- // in a read buffer.
+ foreach ($reads as $channel) {
+ // If any of the read channels have data in read buffers, return
+ // immediately. If we don't, we risk running select() on a bunch of
+ // sockets which won't become readable because the data the application
+ // expects is already in a read buffer.
if (!$channel->isReadBufferEmpty()) {
return;
}
$r_sockets = $channel->getReadSockets();
- $w_sockets = $channel->getWriteSockets();
-
- // If any channel has no read sockets and no write sockets, assume it
- // isn't selectable and return immediately (effectively degrading to a
- // busy wait).
-
- if (!$r_sockets && !$w_sockets) {
- return false;
+ foreach ($r_sockets as $socket) {
+ $read[] = $socket;
+ $except[] = $socket;
}
+ }
+ foreach ($writes as $channel) {
if ($channel->isWriteBufferEmpty()) {
// If the channel's write buffer is empty, don't select the write
// sockets, since they're writable immediately.
$w_sockets = array();
- }
-
- foreach ($r_sockets as $socket) {
- $read[] = $socket;
- $except[] = $socket;
+ } else {
+ $w_sockets = $channel->getWriteSockets();
}
foreach ($w_sockets as $socket) {
Index: src/channel/PhutilExecChannel.php
===================================================================
--- src/channel/PhutilExecChannel.php
+++ src/channel/PhutilExecChannel.php
@@ -126,6 +126,12 @@
return $this->future->getWriteSockets();
}
+ public function isReadBufferEmpty() {
+ // Check both the channel and future read buffers, since either could have
+ // data.
+ return parent::isReadBufferEmpty() && $this->future->isReadBufferEmpty();
+ }
+
public function setReadBufferSize($size) {
// NOTE: We may end up using 2x the buffer size here, one inside
// ExecFuture and one inside the Channel. We could tune this eventually, but
Index: src/future/exec/ExecFuture.php
===================================================================
--- src/future/exec/ExecFuture.php
+++ src/future/exec/ExecFuture.php
@@ -507,6 +507,17 @@
/**
+ * Determine if the read buffer is empty.
+ *
+ * @return bool True if the read buffer is empty.
+ * @task internal
+ */
+ public function isReadBufferEmpty() {
+ return !strlen($this->stdout);
+ }
+
+
+ /**
* Determine if the write buffer is empty.
*
* @return bool True if the write buffer is empty.
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 10, 8:09 PM (4 d, 44 m ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6742764
Default Alt Text
D7775.diff (5 KB)
Attached To
Mode
D7775: Allow PhutilChannel to select only write sockets, and expose read buffer status
Attached
Detach File
Event Timeline
Log In to Comment