/* * Once dication has happened this fires, for better or worse */ static void voice_callback(DictationSession *session, DictationSessionStatus status, char *transcription, void *context) { // If for worse then this is where we go if (status != DictationSessionStatusSuccess) { LOG_WARN("dictation failed"); dictation_session_stop(session); voice_system_active = false; respond_with_vibe(false); show_notice(status == DictationSessionStatusFailureTranscriptionRejected ? RESOURCE_ID_NOTICE_VOICE_STOPPED : RESOURCE_ID_NOTICE_VOICE_FAILED); return; } // If we were lucky then we try to match the transcription to a menu item dictation_session_stop(session); LOG_INFO("dictation got %s", transcription); bool vibe; VoiceSelectAction action = determine_action(transcription, &vibe); // Allow comms and notices voice_system_active = false; if (action != NULL) { // If we get a match then fire the action if (vibe) respond_with_vibe(true); action(); } else { // Feedback we didn't find anything respond_with_vibe(false); show_notice_with_message(RESOURCE_ID_VOICE_DIDNT_UNDERSTAND, transcription); } }
// The stack-unwinding loop. static inline void unwind_loop(ExcInfo* exc_data) { // NB. https://monoinfinito.wordpress.com/series/exception-handling-in-c/ is a very useful resource // as are http://www.airs.com/blog/archives/460 and http://www.airs.com/blog/archives/464 unw_cursor_t cursor; unw_context_t uc; // exists only to initialize cursor #ifndef NDEBUG // poison stack memory. have had problems with these structures being insufficiently initialized. memset(&uc, 0xef, sizeof uc); memset(&cursor, 0xef, sizeof cursor); #endif unw_getcontext(&uc); unw_init_local(&cursor, &uc); auto unwind_session = getActivePythonUnwindSession(); while (unw_step(&cursor) > 0) { unw_proc_info_t pip; static StatCounter frames_unwound("num_frames_unwound_cxx"); frames_unwound.log(); // NB. unw_get_proc_info is slow; a significant chunk of all time spent unwinding is spent here. check(unw_get_proc_info(&cursor, &pip)); assert((pip.lsda == 0) == (pip.handler == 0)); assert(pip.flags == 0); if (VERBOSITY("cxx_unwind") >= 4) { print_frame(&cursor, &pip); } // let the PythonUnwindSession know that we're in a new frame, // giving it a chance to possibly add a traceback entry for // it. unwindingThroughFrame(unwind_session, &cursor); // Skip frames without handlers if (pip.handler == 0) { continue; } RELEASE_ASSERT(pip.handler == (uintptr_t)__gxx_personality_v0, "personality function other than __gxx_personality_v0; " "don't know how to unwind through non-C++ functions"); // Don't call __gxx_personality_v0; we perform dispatch ourselves. // 1. parse LSDA header lsda_info_t info; parse_lsda_header(&pip, &info); call_site_entry_t entry; { // 2. Find our current IP in the call site table. unw_word_t ip; unw_get_reg(&cursor, UNW_REG_IP, &ip); // ip points to the instruction *after* the instruction that caused the error - which is generally (always?) // a call instruction - UNLESS we're in a signal frame, in which case it points at the instruction that // caused the error. For now, we assume we're never in a signal frame. So, we decrement it by one. // // TODO: double-check that we never hit a signal frame. --ip; bool found = find_call_site_entry(&info, (const uint8_t*)ip, &entry); // If we didn't find an entry, an exception happened somewhere exceptions should never happen; terminate // immediately. if (!found) { panic(); } } // 3. Figure out what to do based on the call site entry. if (!entry.landing_pad) { // No landing pad means no exception handling or cleanup; keep unwinding! continue; } // After this point we are guaranteed to resume something rather than unwinding further. if (VERBOSITY("cxx_unwind") >= 4) { print_lsda(&info); } int64_t switch_value = determine_action(&info, &entry); if (switch_value != CLEANUP_ACTION) { // we're transfering control to a non-cleanup landing pad. // i.e. a catch block. thus ends our unwind session. endPythonUnwindSession(unwind_session); #if STAT_TIMERS pyston::StatTimer::finishOverride(); #endif } static_assert(THREADING_USE_GIL, "have to make the unwind session usage in this file thread safe!"); // there is a python unwinding implementation detail leaked // here - that the unwind session can be ended but its // exception storage is still around. // // this manifests itself as this short window here where we've // (possibly) ended the unwind session above but we still need // to pass exc_data (which is the exceptionStorage for this // unwind session) to resume(). // // the only way this could bite us is if we somehow clobber // the PythonUnwindSession's storage, or cause a GC to occur, before // transfering control to the landing pad in resume(). // resume(&cursor, entry.landing_pad, switch_value, exc_data); } // Hit end of stack! return & let unwindException determine what to do. }