// Form a trace of the async stack starting with the currently running // generator, if any. For now we just toss in the function name and // id, as well as the pseudo-frames for context breaks at explicit // joins. Later we'll add more, like file and line, hopefully function // args, wait handle status, etc. static Array createAsyncStacktrace() { Array trace; auto currentWaitHandle = HHVM_FN(asio_get_running)(); if (currentWaitHandle.isNull()) return trace; Array depStack = objToWaitableWaitHandle(currentWaitHandle)->t_getdependencystack(); for (ArrayIter iter(depStack); iter; ++iter) { if (iter.secondRef().isNull()) { trace.append(Array(staticEmptyArray())); } else { auto wh = objToWaitableWaitHandle(iter.secondRef().toObject()); auto parents = wh->t_getparents(); Array ancestors; for (ArrayIter piter(parents); piter; ++piter) { // Note: the parent list contains no nulls. auto parent = objToWaitableWaitHandle(piter.secondRef().toObject()); ancestors.append(parent->t_getname()); } Array frameData; frameData.set(s_function, wh->t_getname(), true); frameData.set(s_id, wh->t_getid(), true); frameData.set(s_ancestors, ancestors, true); // Async function wait handles may have a source location to add. if (wh->getKind() == c_WaitHandle::Kind::AsyncFunction) { auto afwh = static_cast<c_AsyncFunctionWaitHandle*>(wh); addAsyncFunctionLocation(frameData, *afwh); } trace.append(frameData); } } return trace; }
// Form a trace of the async stack starting with the currently running // generator, if any. For now we just toss in the function name and // id, as well as the pseudo-frames for context breaks at explicit // joins. Later we'll add more, like file and line, hopefully function // args, wait handle status, etc. Array createAsyncStacktrace() { Array trace; auto currentWaitHandle = f_asio_get_running(); if (currentWaitHandle.isNull()) return trace; Array depStack = objToWaitableWaitHandle(currentWaitHandle)->t_getdependencystack(); for (ArrayIter iter(depStack); iter; ++iter) { if (iter.secondRef().isNull()) { trace.append(ArrayInit(0).toVariant()); } else { auto wh = objToWaitableWaitHandle(iter.secondRef().toObject()); auto parents = wh->t_getparents(); Array ancestors; for (ArrayIter piter(parents); piter; ++piter) { // Note: the parent list contains no nulls. auto parent = objToWaitableWaitHandle(piter.secondRef().toObject()); ancestors.append(parent->t_getname()); } Array frameData; frameData.set(s_function, wh->t_getname(), true); frameData.set(s_id, wh->t_getid(), true); frameData.set(s_ancestors, ancestors, true); // Continuation wait handles may have a source location to add. auto contWh = dynamic_cast<c_AsyncFunctionWaitHandle*>(wh); if (contWh != nullptr) addContinuationLocation(frameData, *contWh); trace.append(frameData); } } return trace; }
Array XenonRequestLocalData::logAsyncStack() { VMRegAnchor _; Array bt; auto currentWaitHandle = c_ResumableWaitHandle::getRunning(vmfp()); if (currentWaitHandle == nullptr) { // if we have a nullptr, then we have no async stack to store for this log return bt; } Array depStack = currentWaitHandle->t_getdependencystack(); for (ArrayIter iter(depStack); iter; ++iter) { Array frameData; if (iter.secondRef().isNull()) { frameData.set(s_function, "<prep>", true); } else { auto wh = objToWaitableWaitHandle(iter.secondRef().toObject()); frameData.set(s_function, wh->t_getname(), true); // Async function wait handles may have a source location to add. if (wh->getKind() == c_WaitHandle::Kind::AsyncFunction) { auto afwh = static_cast<c_AsyncFunctionWaitHandle*>(wh); if (!afwh->isRunning()) { frameData.set(s_file, afwh->getFileName(), true); frameData.set(s_line, afwh->getLineNumber(), true); } } } bt.append(frameData); } return bt; }
static c_AsyncFunctionWaitHandle *getWaitHandleAtAsyncStackPosition(int position) { auto top = f_asio_get_running(); if (top.isNull()) { return nullptr; } if (position == 0) { return objToContinuationWaitHandle(top); } Array depStack = objToWaitableWaitHandle(top)->t_getdependencystack(); return objToContinuationWaitHandle(depStack[position].toObject()); }