Enable Ctrl-C while looping only in translated code

The debugger relies on hooks into the interpreter to gain control of threads. If a thread is looping in translated code, though, it will never enter the interpreter. Take advantage of the existing surprise checks emitted on back-branches to pop out of translated code back to the interpreter when trying to interrupt threads due to a Ctrl-C from the client.

Also modified TestDebuggerJit to ensure that the thread executing the infinite loop has time to settle into looping in TC's. The signal to interrupt the server is historically fast enough to get there before one of the translations is made. Added a reasonable delay which caused the test to fail deterministically on my machine before the fix.
Esse commit está contido em:
Mike Magruder
2013-07-01 13:00:04 -07:00
commit de Sara Golemon
commit cb8d51fd2a
5 arquivos alterados com 29 adições e 6 exclusões
+5
Ver Arquivo
@@ -188,6 +188,11 @@ void RequestInjectionData::clearInterceptFlag() {
~RequestInjectionData::InterceptFlag);
}
void RequestInjectionData::setDebuggerSignalFlag() {
__sync_fetch_and_or(getConditionFlags(),
RequestInjectionData::DebuggerSignalFlag);
}
ssize_t RequestInjectionData::fetchAndClearFlags() {
return __sync_fetch_and_and(getConditionFlags(),
(RequestInjectionData::EventHookFlag |
+4 -1
Ver Arquivo
@@ -200,7 +200,9 @@ public:
static const ssize_t EventHookFlag = 1 << 3;
static const ssize_t PendingExceptionFlag = 1 << 4;
static const ssize_t InterceptFlag = 1 << 5;
static const ssize_t LastFlag = InterceptFlag;
// Set by the debugger to break out of loops in translated code.
static const ssize_t DebuggerSignalFlag = 1 << 6;
static const ssize_t LastFlag = DebuggerSignalFlag;
RequestInjectionData()
: cflagsPtr(nullptr), surprisePage(nullptr), started(0), timeoutSeconds(-1),
@@ -265,6 +267,7 @@ public:
void clearPendingExceptionFlag();
void setInterceptFlag();
void clearInterceptFlag();
void setDebuggerSignalFlag();
ssize_t fetchAndClearFlags();
void onSessionInit();
+9 -4
Ver Arquivo
@@ -405,20 +405,25 @@ void Debugger::unregisterSandbox(const StringData* sandboxId) {
#define FOREACH_SANDBOX_THREAD_END() } } } \
// Ask every thread in this proxy's sandbox and the dummy sandbox to "stop".
// Gaining control of these threads is the intention... the mechanism is to
// force them all to start interpreting all of their code in an effort to gain
// control in phpDebuggerOpcodeHook().
// Ask every thread in this proxy's sandbox and the dummy sandbox to
// "stop". Gaining control of these threads is the intention... the
// mechanism is to force them all to start interpreting all of their
// code in an effort to gain control in phpDebuggerOpcodeHook(). We
// set the "debugger interrupt" flag to ensure we interpret code
// rather than entering translated code, and we set the "debugger
// signal" surprise flag to pop out of loops in translated code.
void Debugger::requestInterrupt(DebuggerProxyPtr proxy) {
TRACE(2, "Debugger::requestInterrupt\n");
const StringData* sid = StringData::GetStaticString(proxy->getSandboxId());
FOREACH_SANDBOX_THREAD_BEGIN(sid, ti)
ti->m_reqInjectionData.setDebuggerIntr(true);
ti->m_reqInjectionData.setDebuggerSignalFlag();
FOREACH_SANDBOX_THREAD_END()
sid = StringData::GetStaticString(proxy->getDummyInfo().id());
FOREACH_SANDBOX_THREAD_BEGIN(sid, ti)
ti->m_reqInjectionData.setDebuggerIntr(true);
ti->m_reqInjectionData.setDebuggerSignalFlag();
FOREACH_SANDBOX_THREAD_END()
}
@@ -15,7 +15,13 @@ function signal1($c) {
$o = $c->processCmd('continue', null);
VS($o['output_type'], 'code_loc');
VS(substr($o['file'],-17), 'web_request_t.php');
VS($o['line_no'], 20);
// The interrupt could stop the loop on either the 'sleep' or the
// 'while'. In practice it seems to always hit the 'while', but
// either is valid so be safe and allow both.
$line_no = $o['line_no'];
if (($line_no != 19) && ($line_no != 20)) {
throw new TestFailure($line_no, '19 or 20');
}
$o = $c->processCmd('print', array('$a'));
VS($o['values']['value'], 1);
// Break the endless loop in web_request_t.php.
+4
Ver Arquivo
@@ -324,6 +324,10 @@ void TestDebugger::testWebRequestHelperPhase1() {
// let the original request for web_request_t.php run, and it should now be
// spinning in an infinite loop in test_sleep(). This will issue a ctrl-c
// which will break within that loop.
//
// NB: sleep a bit first to give the request thread time to settle
// into the infinite loop.
sleep(2);
if (!getResponse("web_request_interrupt.php", result) ||
result != "interrupt done") {
printf("failed on web_request_interrupt.php\n");