diff options
author | 2020-08-03 14:33:06 +0000 | |
---|---|---|
committer | 2020-08-03 14:33:06 +0000 | |
commit | 061da546b983eb767bad15e67af1174fb0bcf31c (patch) | |
tree | 83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp | |
parent | Import LLVM 10.0.0 release including clang, lld and lldb. (diff) | |
download | wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip |
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom
tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp')
-rw-r--r-- | gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp | 673 |
1 files changed, 673 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp new file mode 100644 index 00000000000..8fd16f420c0 --- /dev/null +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp @@ -0,0 +1,673 @@ +//===-- BreakpointOptions.cpp -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Breakpoint/BreakpointOptions.h" + +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Core/Value.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadSpec.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StringList.h" + +#include "llvm/ADT/STLExtras.h" + +using namespace lldb; +using namespace lldb_private; + +const char + *BreakpointOptions::CommandData::g_option_names[static_cast<uint32_t>( + BreakpointOptions::CommandData::OptionNames::LastOptionName)]{ + "UserSource", "ScriptSource", "StopOnError"}; + +StructuredData::ObjectSP +BreakpointOptions::CommandData::SerializeToStructuredData() { + size_t num_strings = user_source.GetSize(); + if (num_strings == 0 && script_source.empty()) { + // We shouldn't serialize commands if there aren't any, return an empty sp + // to indicate this. + return StructuredData::ObjectSP(); + } + + StructuredData::DictionarySP options_dict_sp( + new StructuredData::Dictionary()); + options_dict_sp->AddBooleanItem(GetKey(OptionNames::StopOnError), + stop_on_error); + + StructuredData::ArraySP user_source_sp(new StructuredData::Array()); + for (size_t i = 0; i < num_strings; i++) { + StructuredData::StringSP item_sp( + new StructuredData::String(user_source[i])); + user_source_sp->AddItem(item_sp); + options_dict_sp->AddItem(GetKey(OptionNames::UserSource), user_source_sp); + } + + options_dict_sp->AddStringItem( + GetKey(OptionNames::Interpreter), + ScriptInterpreter::LanguageToString(interpreter)); + return options_dict_sp; +} + +std::unique_ptr<BreakpointOptions::CommandData> +BreakpointOptions::CommandData::CreateFromStructuredData( + const StructuredData::Dictionary &options_dict, Status &error) { + std::unique_ptr<CommandData> data_up(new CommandData()); + bool found_something = false; + + bool success = options_dict.GetValueForKeyAsBoolean( + GetKey(OptionNames::StopOnError), data_up->stop_on_error); + + if (success) + found_something = true; + + llvm::StringRef interpreter_str; + ScriptLanguage interp_language; + success = options_dict.GetValueForKeyAsString( + GetKey(OptionNames::Interpreter), interpreter_str); + + if (!success) { + error.SetErrorString("Missing command language value."); + return data_up; + } + + found_something = true; + interp_language = ScriptInterpreter::StringToLanguage(interpreter_str); + if (interp_language == eScriptLanguageUnknown) { + error.SetErrorStringWithFormatv("Unknown breakpoint command language: {0}.", + interpreter_str); + return data_up; + } + data_up->interpreter = interp_language; + + StructuredData::Array *user_source; + success = options_dict.GetValueForKeyAsArray(GetKey(OptionNames::UserSource), + user_source); + if (success) { + found_something = true; + size_t num_elems = user_source->GetSize(); + for (size_t i = 0; i < num_elems; i++) { + llvm::StringRef elem_string; + success = user_source->GetItemAtIndexAsString(i, elem_string); + if (success) + data_up->user_source.AppendString(elem_string); + } + } + + if (found_something) + return data_up; + else + return std::unique_ptr<BreakpointOptions::CommandData>(); +} + +const char *BreakpointOptions::g_option_names[( + size_t)BreakpointOptions::OptionNames::LastOptionName]{ + "ConditionText", "IgnoreCount", + "EnabledState", "OneShotState", "AutoContinue"}; + +bool BreakpointOptions::NullCallback(void *baton, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) { + return true; +} + +// BreakpointOptions constructor +BreakpointOptions::BreakpointOptions(bool all_flags_set) + : m_callback(BreakpointOptions::NullCallback), m_callback_baton_sp(), + m_baton_is_command_baton(false), m_callback_is_synchronous(false), + m_enabled(true), m_one_shot(false), m_ignore_count(0), m_thread_spec_up(), + m_condition_text(), m_condition_text_hash(0), m_auto_continue(false), + m_set_flags(0) { + if (all_flags_set) + m_set_flags.Set(~((Flags::ValueType)0)); +} + +BreakpointOptions::BreakpointOptions(const char *condition, bool enabled, + int32_t ignore, bool one_shot, + bool auto_continue) + : m_callback(nullptr), m_baton_is_command_baton(false), + m_callback_is_synchronous(false), m_enabled(enabled), + m_one_shot(one_shot), m_ignore_count(ignore), + m_condition_text_hash(0), m_auto_continue(auto_continue) +{ + m_set_flags.Set(eEnabled | eIgnoreCount | eOneShot + | eAutoContinue); + if (condition && *condition != '\0') { + SetCondition(condition); + } +} + +// BreakpointOptions copy constructor +BreakpointOptions::BreakpointOptions(const BreakpointOptions &rhs) + : m_callback(rhs.m_callback), m_callback_baton_sp(rhs.m_callback_baton_sp), + m_baton_is_command_baton(rhs.m_baton_is_command_baton), + m_callback_is_synchronous(rhs.m_callback_is_synchronous), + m_enabled(rhs.m_enabled), m_one_shot(rhs.m_one_shot), + m_ignore_count(rhs.m_ignore_count), m_thread_spec_up(), + m_auto_continue(rhs.m_auto_continue), m_set_flags(rhs.m_set_flags) { + if (rhs.m_thread_spec_up != nullptr) + m_thread_spec_up.reset(new ThreadSpec(*rhs.m_thread_spec_up)); + m_condition_text = rhs.m_condition_text; + m_condition_text_hash = rhs.m_condition_text_hash; +} + +// BreakpointOptions assignment operator +const BreakpointOptions &BreakpointOptions:: +operator=(const BreakpointOptions &rhs) { + m_callback = rhs.m_callback; + m_callback_baton_sp = rhs.m_callback_baton_sp; + m_baton_is_command_baton = rhs.m_baton_is_command_baton; + m_callback_is_synchronous = rhs.m_callback_is_synchronous; + m_enabled = rhs.m_enabled; + m_one_shot = rhs.m_one_shot; + m_ignore_count = rhs.m_ignore_count; + if (rhs.m_thread_spec_up != nullptr) + m_thread_spec_up.reset(new ThreadSpec(*rhs.m_thread_spec_up)); + m_condition_text = rhs.m_condition_text; + m_condition_text_hash = rhs.m_condition_text_hash; + m_auto_continue = rhs.m_auto_continue; + m_set_flags = rhs.m_set_flags; + return *this; +} + +void BreakpointOptions::CopyOverSetOptions(const BreakpointOptions &incoming) +{ + if (incoming.m_set_flags.Test(eEnabled)) + { + m_enabled = incoming.m_enabled; + m_set_flags.Set(eEnabled); + } + if (incoming.m_set_flags.Test(eOneShot)) + { + m_one_shot = incoming.m_one_shot; + m_set_flags.Set(eOneShot); + } + if (incoming.m_set_flags.Test(eCallback)) + { + m_callback = incoming.m_callback; + m_callback_baton_sp = incoming.m_callback_baton_sp; + m_callback_is_synchronous = incoming.m_callback_is_synchronous; + m_baton_is_command_baton = incoming.m_baton_is_command_baton; + m_set_flags.Set(eCallback); + } + if (incoming.m_set_flags.Test(eIgnoreCount)) + { + m_ignore_count = incoming.m_ignore_count; + m_set_flags.Set(eIgnoreCount); + } + if (incoming.m_set_flags.Test(eCondition)) + { + // If we're copying over an empty condition, mark it as unset. + if (incoming.m_condition_text.empty()) { + m_condition_text.clear(); + m_condition_text_hash = 0; + m_set_flags.Clear(eCondition); + } else { + m_condition_text = incoming.m_condition_text; + m_condition_text_hash = incoming.m_condition_text_hash; + m_set_flags.Set(eCondition); + } + } + if (incoming.m_set_flags.Test(eAutoContinue)) + { + m_auto_continue = incoming.m_auto_continue; + m_set_flags.Set(eAutoContinue); + } + if (incoming.m_set_flags.Test(eThreadSpec) && incoming.m_thread_spec_up) { + if (!m_thread_spec_up) + m_thread_spec_up.reset(new ThreadSpec(*incoming.m_thread_spec_up)); + else + *m_thread_spec_up = *incoming.m_thread_spec_up; + m_set_flags.Set(eThreadSpec); + } +} + +// Destructor +BreakpointOptions::~BreakpointOptions() = default; + +std::unique_ptr<BreakpointOptions> BreakpointOptions::CreateFromStructuredData( + Target &target, const StructuredData::Dictionary &options_dict, + Status &error) { + bool enabled = true; + bool one_shot = false; + bool auto_continue = false; + int32_t ignore_count = 0; + llvm::StringRef condition_ref(""); + Flags set_options; + + const char *key = GetKey(OptionNames::EnabledState); + bool success; + if (key && options_dict.HasKey(key)) { + success = options_dict.GetValueForKeyAsBoolean(key, enabled); + if (!success) { + error.SetErrorStringWithFormat("%s key is not a boolean.", key); + return nullptr; + } + set_options.Set(eEnabled); + } + + key = GetKey(OptionNames::OneShotState); + if (key && options_dict.HasKey(key)) { + success = options_dict.GetValueForKeyAsBoolean(key, one_shot); + if (!success) { + error.SetErrorStringWithFormat("%s key is not a boolean.", key); + return nullptr; + } + set_options.Set(eOneShot); + } + + key = GetKey(OptionNames::AutoContinue); + if (key && options_dict.HasKey(key)) { + success = options_dict.GetValueForKeyAsBoolean(key, auto_continue); + if (!success) { + error.SetErrorStringWithFormat("%s key is not a boolean.", key); + return nullptr; + } + set_options.Set(eAutoContinue); + } + + key = GetKey(OptionNames::IgnoreCount); + if (key && options_dict.HasKey(key)) { + success = options_dict.GetValueForKeyAsInteger(key, ignore_count); + if (!success) { + error.SetErrorStringWithFormat("%s key is not an integer.", key); + return nullptr; + } + set_options.Set(eIgnoreCount); + } + + key = GetKey(OptionNames::ConditionText); + if (key && options_dict.HasKey(key)) { + success = options_dict.GetValueForKeyAsString(key, condition_ref); + if (!success) { + error.SetErrorStringWithFormat("%s key is not an string.", key); + return nullptr; + } + set_options.Set(eCondition); + } + + std::unique_ptr<CommandData> cmd_data_up; + StructuredData::Dictionary *cmds_dict; + success = options_dict.GetValueForKeyAsDictionary( + CommandData::GetSerializationKey(), cmds_dict); + if (success && cmds_dict) { + Status cmds_error; + cmd_data_up = CommandData::CreateFromStructuredData(*cmds_dict, cmds_error); + if (cmds_error.Fail()) { + error.SetErrorStringWithFormat( + "Failed to deserialize breakpoint command options: %s.", + cmds_error.AsCString()); + return nullptr; + } + } + + auto bp_options = std::make_unique<BreakpointOptions>( + condition_ref.str().c_str(), enabled, + ignore_count, one_shot, auto_continue); + if (cmd_data_up) { + if (cmd_data_up->interpreter == eScriptLanguageNone) + bp_options->SetCommandDataCallback(cmd_data_up); + else { + ScriptInterpreter *interp = target.GetDebugger().GetScriptInterpreter(); + if (!interp) { + error.SetErrorStringWithFormat( + "Can't set script commands - no script interpreter"); + return nullptr; + } + if (interp->GetLanguage() != cmd_data_up->interpreter) { + error.SetErrorStringWithFormat( + "Current script language doesn't match breakpoint's language: %s", + ScriptInterpreter::LanguageToString(cmd_data_up->interpreter) + .c_str()); + return nullptr; + } + Status script_error; + script_error = + interp->SetBreakpointCommandCallback(bp_options.get(), cmd_data_up); + if (script_error.Fail()) { + error.SetErrorStringWithFormat("Error generating script callback: %s.", + error.AsCString()); + return nullptr; + } + } + } + + StructuredData::Dictionary *thread_spec_dict; + success = options_dict.GetValueForKeyAsDictionary( + ThreadSpec::GetSerializationKey(), thread_spec_dict); + if (success) { + Status thread_spec_error; + std::unique_ptr<ThreadSpec> thread_spec_up = + ThreadSpec::CreateFromStructuredData(*thread_spec_dict, + thread_spec_error); + if (thread_spec_error.Fail()) { + error.SetErrorStringWithFormat( + "Failed to deserialize breakpoint thread spec options: %s.", + thread_spec_error.AsCString()); + return nullptr; + } + bp_options->SetThreadSpec(thread_spec_up); + } + return bp_options; +} + +StructuredData::ObjectSP BreakpointOptions::SerializeToStructuredData() { + StructuredData::DictionarySP options_dict_sp( + new StructuredData::Dictionary()); + if (m_set_flags.Test(eEnabled)) + options_dict_sp->AddBooleanItem(GetKey(OptionNames::EnabledState), + m_enabled); + if (m_set_flags.Test(eOneShot)) + options_dict_sp->AddBooleanItem(GetKey(OptionNames::OneShotState), + m_one_shot); + if (m_set_flags.Test(eAutoContinue)) + options_dict_sp->AddBooleanItem(GetKey(OptionNames::AutoContinue), + m_auto_continue); + if (m_set_flags.Test(eIgnoreCount)) + options_dict_sp->AddIntegerItem(GetKey(OptionNames::IgnoreCount), + m_ignore_count); + if (m_set_flags.Test(eCondition)) + options_dict_sp->AddStringItem(GetKey(OptionNames::ConditionText), + m_condition_text); + + if (m_set_flags.Test(eCallback) && m_baton_is_command_baton) { + auto cmd_baton = + std::static_pointer_cast<CommandBaton>(m_callback_baton_sp); + StructuredData::ObjectSP commands_sp = + cmd_baton->getItem()->SerializeToStructuredData(); + if (commands_sp) { + options_dict_sp->AddItem( + BreakpointOptions::CommandData::GetSerializationKey(), commands_sp); + } + } + if (m_set_flags.Test(eThreadSpec) && m_thread_spec_up) { + StructuredData::ObjectSP thread_spec_sp = + m_thread_spec_up->SerializeToStructuredData(); + options_dict_sp->AddItem(ThreadSpec::GetSerializationKey(), thread_spec_sp); + } + + return options_dict_sp; +} + +// Callbacks +void BreakpointOptions::SetCallback(BreakpointHitCallback callback, + const lldb::BatonSP &callback_baton_sp, + bool callback_is_synchronous) { + // FIXME: This seems unsafe. If BatonSP actually *is* a CommandBaton, but + // in a shared_ptr<Baton> instead of a shared_ptr<CommandBaton>, then we will + // set m_baton_is_command_baton to false, which is incorrect. One possible + // solution is to make the base Baton class provide a method such as: + // virtual StringRef getBatonId() const { return ""; } + // and have CommandBaton override this to return something unique, and then + // check for it here. Another option might be to make Baton using the llvm + // casting infrastructure, so that we could write something like: + // if (llvm::isa<CommandBaton>(callback_baton_sp)) + // at relevant callsites instead of storing a boolean. + m_callback_is_synchronous = callback_is_synchronous; + m_callback = callback; + m_callback_baton_sp = callback_baton_sp; + m_baton_is_command_baton = false; + m_set_flags.Set(eCallback); +} + +void BreakpointOptions::SetCallback( + BreakpointHitCallback callback, + const BreakpointOptions::CommandBatonSP &callback_baton_sp, + bool callback_is_synchronous) { + m_callback_is_synchronous = callback_is_synchronous; + m_callback = callback; + m_callback_baton_sp = callback_baton_sp; + m_baton_is_command_baton = true; + m_set_flags.Set(eCallback); +} + +void BreakpointOptions::ClearCallback() { + m_callback = BreakpointOptions::NullCallback; + m_callback_is_synchronous = false; + m_callback_baton_sp.reset(); + m_baton_is_command_baton = false; + m_set_flags.Clear(eCallback); +} + +Baton *BreakpointOptions::GetBaton() { return m_callback_baton_sp.get(); } + +const Baton *BreakpointOptions::GetBaton() const { + return m_callback_baton_sp.get(); +} + +bool BreakpointOptions::InvokeCallback(StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) { + if (m_callback) { + if (context->is_synchronous == IsCallbackSynchronous()) { + return m_callback(m_callback_baton_sp ? m_callback_baton_sp->data() + : nullptr, + context, break_id, break_loc_id); + } else if (IsCallbackSynchronous()) { + // If a synchronous callback is called at async time, it should not say + // to stop. + return false; + } + } + return true; +} + +bool BreakpointOptions::HasCallback() const { + return m_callback != BreakpointOptions::NullCallback; +} + +bool BreakpointOptions::GetCommandLineCallbacks(StringList &command_list) { + if (!HasCallback()) + return false; + if (!m_baton_is_command_baton) + return false; + + auto cmd_baton = std::static_pointer_cast<CommandBaton>(m_callback_baton_sp); + CommandData *data = cmd_baton->getItem(); + if (!data) + return false; + command_list = data->user_source; + return true; +} + +void BreakpointOptions::SetCondition(const char *condition) { + if (!condition || condition[0] == '\0') { + condition = ""; + m_set_flags.Clear(eCondition); + } + else + m_set_flags.Set(eCondition); + + m_condition_text.assign(condition); + std::hash<std::string> hasher; + m_condition_text_hash = hasher(m_condition_text); +} + +const char *BreakpointOptions::GetConditionText(size_t *hash) const { + if (!m_condition_text.empty()) { + if (hash) + *hash = m_condition_text_hash; + + return m_condition_text.c_str(); + } else { + return nullptr; + } +} + +const ThreadSpec *BreakpointOptions::GetThreadSpecNoCreate() const { + return m_thread_spec_up.get(); +} + +ThreadSpec *BreakpointOptions::GetThreadSpec() { + if (m_thread_spec_up == nullptr) { + m_set_flags.Set(eThreadSpec); + m_thread_spec_up.reset(new ThreadSpec()); + } + + return m_thread_spec_up.get(); +} + +void BreakpointOptions::SetThreadID(lldb::tid_t thread_id) { + GetThreadSpec()->SetTID(thread_id); + m_set_flags.Set(eThreadSpec); +} + +void BreakpointOptions::SetThreadSpec( + std::unique_ptr<ThreadSpec> &thread_spec_up) { + m_thread_spec_up = std::move(thread_spec_up); + m_set_flags.Set(eThreadSpec); +} + +void BreakpointOptions::GetDescription(Stream *s, + lldb::DescriptionLevel level) const { + // Figure out if there are any options not at their default value, and only + // print anything if there are: + + if (m_ignore_count != 0 || !m_enabled || m_one_shot || m_auto_continue || + (GetThreadSpecNoCreate() != nullptr && + GetThreadSpecNoCreate()->HasSpecification())) { + if (level == lldb::eDescriptionLevelVerbose) { + s->EOL(); + s->IndentMore(); + s->Indent(); + s->PutCString("Breakpoint Options:\n"); + s->IndentMore(); + s->Indent(); + } else + s->PutCString(" Options: "); + + if (m_ignore_count > 0) + s->Printf("ignore: %d ", m_ignore_count); + s->Printf("%sabled ", m_enabled ? "en" : "dis"); + + if (m_one_shot) + s->Printf("one-shot "); + + if (m_auto_continue) + s->Printf("auto-continue "); + + if (m_thread_spec_up) + m_thread_spec_up->GetDescription(s, level); + + if (level == lldb::eDescriptionLevelFull) { + s->IndentLess(); + s->IndentMore(); + } + } + + if (m_callback_baton_sp.get()) { + if (level != eDescriptionLevelBrief) { + s->EOL(); + m_callback_baton_sp->GetDescription(s->AsRawOstream(), level, + s->GetIndentLevel()); + } + } + if (!m_condition_text.empty()) { + if (level != eDescriptionLevelBrief) { + s->EOL(); + s->Printf("Condition: %s\n", m_condition_text.c_str()); + } + } +} + +void BreakpointOptions::CommandBaton::GetDescription( + llvm::raw_ostream &s, lldb::DescriptionLevel level, + unsigned indentation) const { + const CommandData *data = getItem(); + + if (level == eDescriptionLevelBrief) { + s << ", commands = " + << ((data && data->user_source.GetSize() > 0) ? "yes" : "no"); + return; + } + + indentation += 2; + s.indent(indentation); + s << "Breakpoint commands"; + if (data->interpreter != eScriptLanguageNone) + s << llvm::formatv(" ({0}):\n", + ScriptInterpreter::LanguageToString(data->interpreter)); + else + s << ":\n"; + + indentation += 2; + if (data && data->user_source.GetSize() > 0) { + for (llvm::StringRef str : data->user_source) { + s.indent(indentation); + s << str << "\n"; + } + } else + s << "No commands.\n"; +} + +void BreakpointOptions::SetCommandDataCallback( + std::unique_ptr<CommandData> &cmd_data) { + cmd_data->interpreter = eScriptLanguageNone; + auto baton_sp = std::make_shared<CommandBaton>(std::move(cmd_data)); + SetCallback(BreakpointOptions::BreakpointOptionsCallbackFunction, baton_sp); + m_set_flags.Set(eCallback); +} + +bool BreakpointOptions::BreakpointOptionsCallbackFunction( + void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) { + bool ret_value = true; + if (baton == nullptr) + return true; + + CommandData *data = (CommandData *)baton; + StringList &commands = data->user_source; + + if (commands.GetSize() > 0) { + ExecutionContext exe_ctx(context->exe_ctx_ref); + Target *target = exe_ctx.GetTargetPtr(); + if (target) { + CommandReturnObject result; + Debugger &debugger = target->GetDebugger(); + // Rig up the results secondary output stream to the debugger's, so the + // output will come out synchronously if the debugger is set up that way. + + StreamSP output_stream(debugger.GetAsyncOutputStream()); + StreamSP error_stream(debugger.GetAsyncErrorStream()); + result.SetImmediateOutputStream(output_stream); + result.SetImmediateErrorStream(error_stream); + + CommandInterpreterRunOptions options; + options.SetStopOnContinue(true); + options.SetStopOnError(data->stop_on_error); + options.SetEchoCommands(true); + options.SetPrintResults(true); + options.SetPrintErrors(true); + options.SetAddToHistory(false); + + debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx, + options, result); + result.GetImmediateOutputStream()->Flush(); + result.GetImmediateErrorStream()->Flush(); + } + } + return ret_value; +} + +void BreakpointOptions::Clear() +{ + m_set_flags.Clear(); + m_thread_spec_up.release(); + m_one_shot = false; + m_ignore_count = 0; + m_auto_continue = false; + m_callback = nullptr; + m_callback_baton_sp.reset(); + m_baton_is_command_baton = false; + m_callback_is_synchronous = false; + m_enabled = false; + m_condition_text.clear(); +} |