def asio_stacktrace(wh, limit=None): """Produce a list of async frames by following a WaitHandle's parent chain. The stacktrace ends at the WaitHandle::join(). The whole chain is walked even if `limit' is provided---the return stacktrace will have `limit' or fewer entries if there were `limit' or fewer frames, and `limit' + 1 frames otherwise, where the last frame is the WaitHandle::join(). """ stacktrace = [] count = 0 for wh in WaitHandle(wh).chain(): resumable = wh.resumable() if resumable is None: continue if limit is None or count < limit: stacktrace.append(frame.create_resumable(count, resumable)) count += 1 ar = asio_context(wh['m_contextIdx'])['m_savedFP'] if ar != nullptr(): stacktrace.append(frame.create_php(idx=count, ar=ar)) return stacktrace