Skip to content

Instantly share code, notes, and snippets.

@jjergus
Created July 18, 2020 02:57
Show Gist options
  • Save jjergus/ff131a33772486d2b011faf56baf33c6 to your computer and use it in GitHub Desktop.
Save jjergus/ff131a33772486d2b011faf56baf33c6 to your computer and use it in GitHub Desktop.
PoC fix for asyncpoll blocked forever after close
diff --git a/hphp/runtime/base/file-await.cpp b/hphp/runtime/base/file-await.cpp
index 6414eac085..78a3cdb366 100644
--- a/hphp/runtime/base/file-await.cpp
+++ b/hphp/runtime/base/file-await.cpp
@@ -21,6 +21,12 @@ void FileEventHandler::handlerReady(uint16_t events) noexcept {
/////////////////////////////////////////////////////////////////////////////
+void FileAwait::jj_cancel() {
+ if (m_file) {
+ m_file->unregisterHandler();
+ }
+}
+
FileAwait::FileAwait(
int fd,
uint16_t events,
diff --git a/hphp/runtime/base/file-await.h b/hphp/runtime/base/file-await.h
index 972ea43a53..a543904f6a 100644
--- a/hphp/runtime/base/file-await.h
+++ b/hphp/runtime/base/file-await.h
@@ -46,6 +46,8 @@ struct FileAwait : AsioExternalThreadEvent {
CLOSED,
};
+ void jj_cancel();
+
FileAwait(int fd, uint16_t events, std::chrono::nanoseconds timeout);
~FileAwait();
void unserialize(TypedValue& c) override;
diff --git a/hphp/runtime/ext/asio/ext_external-thread-event-wait-handle.h b/hphp/runtime/ext/asio/ext_external-thread-event-wait-handle.h
index 9c62636952..d6b24595c9 100644
--- a/hphp/runtime/ext/asio/ext_external-thread-event-wait-handle.h
+++ b/hphp/runtime/ext/asio/ext_external-thread-event-wait-handle.h
@@ -55,6 +55,10 @@ struct c_ExternalThreadEventWaitHandle final : c_WaitableWaitHandle {
}
ObjectData* getPrivData() { return m_privData.get(); }
+ // Yes I know, there's probably a good reason why this wasn't here, but this
+ // is just a PoC so bear with me.
+ AsioExternalThreadEvent* getEvent() { return m_event; }
+
void abandon(bool sweeping);
bool cancel(const Object& exception);
void process();
diff --git a/hphp/runtime/ext/hsl/ext_hsl_os.cpp b/hphp/runtime/ext/hsl/ext_hsl_os.cpp
index 9a20a4f1a2..af4842ffa7 100644
--- a/hphp/runtime/ext/hsl/ext_hsl_os.cpp
+++ b/hphp/runtime/ext/hsl/ext_hsl_os.cpp
@@ -586,6 +586,18 @@ void HHVM_FUNCTION(HSL_os_close, const Object& obj) {
HSLFileDescriptor::get(obj)->close();
}
+void HHVM_FUNCTION(HSL_os_cancel_async_poll, const Object& obj) {
+ if (!obj->instanceof(c_ExternalThreadEventWaitHandle::classof())) {
+ SystemLib::throwInvalidArgumentExceptionObject(
+ "Argument must be ExternalThreadEventWaitHandle");
+ }
+ c_ExternalThreadEventWaitHandle* handle =
+ wait_handle<c_ExternalThreadEventWaitHandle>(obj.get());
+ AsioExternalThreadEvent* event = handle->getEvent();
+ FileAwait* file_await = static_cast<FileAwait*>(event);
+ file_await->jj_cancel();
+}
+
Array HHVM_FUNCTION(HSL_os_pipe) {
int fds[2];
throw_errno_if_minus_one(retry_on_eintr(-1, ::pipe, fds));
@@ -1202,6 +1214,7 @@ struct OSExtension final : Extension {
HHVM_FALIAS(HH\\Lib\\_Private\\_OS\\read, HSL_os_read);
HHVM_FALIAS(HH\\Lib\\_Private\\_OS\\write, HSL_os_write);
HHVM_FALIAS(HH\\Lib\\_Private\\_OS\\close, HSL_os_close);
+ HHVM_FALIAS(HH\\Lib\\_Private\\_OS\\cancel_async_poll, HSL_os_cancel_async_poll);
HHVM_FALIAS(HH\\Lib\\_Private\\_OS\\request_stdio_fd, HSL_os_request_stdio_fd);
HHVM_RC_INT(HH\\Lib\\_Private\\_OS\\STDIN_FILENO, STDIN_FILENO);
diff --git a/hphp/runtime/ext/hsl/ext_hsl_os.php b/hphp/runtime/ext/hsl/ext_hsl_os.php
index 506465508e..01978f80f1 100644
--- a/hphp/runtime/ext/hsl/ext_hsl_os.php
+++ b/hphp/runtime/ext/hsl/ext_hsl_os.php
@@ -55,6 +55,9 @@ function write(FileDescriptor $fd, string $data): int;
<<__Native>>
function close(FileDescriptor $fd): void;
+<<__Native>>
+function cancel_async_poll(WaitHandle $wait_handle): void;
+
<<__Native>>
function pipe(): varray<FileDescriptor>;
diff --git a/src/network/_Private/CancelablePoller.php b/src/network/_Private/CancelablePoller.php
index 9cc13c8..5cb382a 100644
--- a/src/network/_Private/CancelablePoller.php
+++ b/src/network/_Private/CancelablePoller.php
@@ -39,6 +39,7 @@ final class CancelablePoller {
public function cancelAll(int $result): void {
$ex = new PollCancelledException($result);
foreach ($this->polls as $poll) {
+ _OS\cancel_async_poll($poll);
\HH\Asio\cancel($poll, $ex);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment