Recover from C++ exceptions

Recover from C++ exceptions so that PSP does not think ASIO is running. Fixes a segfault when ASIO fails on internal invariant violation in runUntil() with m_current == nullptr.
Esse commit está contido em:
Jan Oravec
2013-06-13 12:40:52 -07:00
commit de Sara Golemon
commit 3ac5f621cd
5 arquivos alterados com 38 adições e 16 exclusões
+9 -2
Ver Arquivo
@@ -96,6 +96,10 @@ void AsioContext::runUntil(c_WaitableWaitHandle* wait_handle) {
auto session = AsioSession::Get();
uint8_t check_ete_counter = 0;
if (!session->hasAbruptInterruptException()) {
session->initAbruptInterruptException();
}
while (!wait_handle->isFinished()) {
// process ready external thread events once per 256 other events
// (when 8-bit check_ete_counter overflows)
@@ -113,9 +117,12 @@ void AsioContext::runUntil(c_WaitableWaitHandle* wait_handle) {
auto current = m_runnableQueue.front();
m_runnableQueue.pop();
m_current = current;
auto exit_guard = folly::makeGuard([&] {
m_current = nullptr;
decRefObj(current);
});
m_current->run();
m_current = nullptr;
decRefObj(current);
continue;
}
+6
Ver Arquivo
@@ -118,6 +118,12 @@ void AsioSession::enqueueExternalThreadEvent(c_ExternalThreadEventWaitHandle* wa
}
}
void AsioSession::initAbruptInterruptException() {
assert(!hasAbruptInterruptException());
m_abruptInterruptException = SystemLib::AllocInvalidOperationExceptionObject(
"The request was abruptly interrupted.");
}
void AsioSession::onFailed(CObjRef exception) {
if (m_onFailedCallback.get()) {
try {
+13
Ver Arquivo
@@ -83,6 +83,17 @@ class AsioSession {
c_ExternalThreadEventWaitHandle* waitForExternalThreadEvents();
void enqueueExternalThreadEvent(c_ExternalThreadEventWaitHandle* wait_handle);
// abrupt interrupt exception
CObjRef getAbruptInterruptException() {
return m_abruptInterruptException;
}
bool hasAbruptInterruptException() {
return m_abruptInterruptException.get();
}
void initAbruptInterruptException();
// callback: on failed
void setOnFailedCallback(ObjectData* on_failed_callback) {
assert(!on_failed_callback || on_failed_callback->instanceof(c_Closure::s_cls));
@@ -162,6 +173,8 @@ class AsioSession {
std::mutex m_readyExternalThreadEventsMutex;
std::condition_variable m_readyExternalThreadEventsCondition;
Object m_abruptInterruptException;
Object m_onContinuationCreateCallback;
Object m_onContinuationYieldCallback;
Object m_onContinuationSuccessCallback;
@@ -192,6 +192,10 @@ void c_ContinuationWaitHandle::run() {
} catch (const Object& exception) {
// process exception thrown by generator or blockOn cycle detection
markAsFailed(exception);
} catch (...) {
// process C++ exception
markAsFailed(AsioSession::Get()->getAbruptInterruptException());
throw;
}
}
+6 -14
Ver Arquivo
@@ -140,25 +140,17 @@ void c_WaitableWaitHandle::join() {
// enter new asio context and set up guard that will exit once we are done
session->enterContext();
auto exit_guard = folly::makeGuard([&] { session->exitContext(); });
assert(session->isInContext());
assert(!session->getCurrentContext()->isRunning());
try {
// import this wait handle to the newly created context
// throws if cross-context cycle found
enterContext(session->getCurrentContextIdx());
// run queues until we are finished
session->getCurrentContext()->runUntil(this);
} catch (const Object& exception) {
// recover from PHP exceptions; HPHP internal exceptions are deliberately
// ignored as there is no easy way to recover from them
session->exitContext();
throw;
}
session->exitContext();
// import this wait handle to the newly created context
// throws if cross-context cycle found
enterContext(session->getCurrentContextIdx());
// run queues until we are finished
session->getCurrentContext()->runUntil(this);
assert(isFinished());
}