diff options
author | Brad King <brad.king@kitware.com> | 2013-08-08 17:55:25 (GMT) |
---|---|---|
committer | CMake Topic Stage <kwrobot@kitware.com> | 2013-08-08 17:55:25 (GMT) |
commit | aaadc280c94dc8b08395616dfa3fec573076676f (patch) | |
tree | f42c13c77a0289314c36d9adc8d7e9b61a5139e5 /Source | |
parent | d422ee362db7f742930de5b2fafd9a3c30c52ef0 (diff) | |
parent | 6aa0c214054252d1fc94e5b8e6b6ffc3eae4c08b (diff) | |
download | CMake-aaadc280c94dc8b08395616dfa3fec573076676f.zip CMake-aaadc280c94dc8b08395616dfa3fec573076676f.tar.gz CMake-aaadc280c94dc8b08395616dfa3fec573076676f.tar.bz2 |
Merge topic 'dev/fix-variable-watch-crash'
6aa0c21 variable_watch: Add test for watching a variable multiple times
b86e37c variable_watch: Check newValue for NULL
f9bb20f variable_watch: Don't share memory for callbacks
05dad99 variable_watch: Fix a typo in the error message
00ce12a variable_watch: Prevent making extra entries in the watch map
34b397e variable_watch: Allow specifying the data to match in RemoveWatch
e43e207 variable_watch: Match client_data when finding duplicates
0d6acb1 variable_watch: Add a deleter for the client data
fc7c3b4 variable_watch: Store client data as pointers
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmVariableWatch.cxx | 50 | ||||
-rw-r--r-- | Source/cmVariableWatch.h | 20 | ||||
-rw-r--r-- | Source/cmVariableWatchCommand.cxx | 141 | ||||
-rw-r--r-- | Source/cmVariableWatchCommand.h | 17 |
4 files changed, 142 insertions, 86 deletions
diff --git a/Source/cmVariableWatch.cxx b/Source/cmVariableWatch.cxx index 3905e9b..8ad6fce 100644 --- a/Source/cmVariableWatch.cxx +++ b/Source/cmVariableWatch.cxx @@ -37,37 +37,63 @@ cmVariableWatch::cmVariableWatch() cmVariableWatch::~cmVariableWatch() { + cmVariableWatch::StringToVectorOfPairs::iterator svp_it; + + for ( svp_it = this->WatchMap.begin(); + svp_it != this->WatchMap.end(); ++svp_it ) + { + cmVariableWatch::VectorOfPairs::iterator p_it; + + for ( p_it = svp_it->second.begin(); + p_it != svp_it->second.end(); ++p_it ) + { + delete *p_it; + } + } } -void cmVariableWatch::AddWatch(const std::string& variable, - WatchMethod method, void* client_data /*=0*/) +bool cmVariableWatch::AddWatch(const std::string& variable, + WatchMethod method, void* client_data /*=0*/, + DeleteData delete_data /*=0*/) { - cmVariableWatch::Pair p; - p.Method = method; - p.ClientData = client_data; + cmVariableWatch::Pair* p = new cmVariableWatch::Pair; + p->Method = method; + p->ClientData = client_data; + p->DeleteDataCall = delete_data; cmVariableWatch::VectorOfPairs* vp = &this->WatchMap[variable]; cmVariableWatch::VectorOfPairs::size_type cc; for ( cc = 0; cc < vp->size(); cc ++ ) { - cmVariableWatch::Pair* pair = &(*vp)[cc]; - if ( pair->Method == method ) + cmVariableWatch::Pair* pair = (*vp)[cc]; + if ( pair->Method == method && + client_data && client_data == pair->ClientData) { - (*vp)[cc] = p; - return; + // Callback already exists + return false; } } vp->push_back(p); + return true; } void cmVariableWatch::RemoveWatch(const std::string& variable, - WatchMethod method) + WatchMethod method, + void* client_data /*=0*/) { + if ( !this->WatchMap.count(variable) ) + { + return; + } cmVariableWatch::VectorOfPairs* vp = &this->WatchMap[variable]; cmVariableWatch::VectorOfPairs::iterator it; for ( it = vp->begin(); it != vp->end(); ++it ) { - if ( it->Method == method ) + if ( (*it)->Method == method && + // If client_data is NULL, we want to disconnect all watches against + // the given method; otherwise match ClientData as well. + (!client_data || (client_data == (*it)->ClientData))) { + delete *it; vp->erase(it); return; } @@ -87,7 +113,7 @@ void cmVariableWatch::VariableAccessed(const std::string& variable, cmVariableWatch::VectorOfPairs::const_iterator it; for ( it = vp->begin(); it != vp->end(); it ++ ) { - it->Method(variable, access_type, it->ClientData, + (*it)->Method(variable, access_type, (*it)->ClientData, newValue, mf); } } diff --git a/Source/cmVariableWatch.h b/Source/cmVariableWatch.h index 7dd4ac5..790c75a 100644 --- a/Source/cmVariableWatch.h +++ b/Source/cmVariableWatch.h @@ -26,6 +26,7 @@ class cmVariableWatch public: typedef void (*WatchMethod)(const std::string& variable, int access_type, void* client_data, const char* newValue, const cmMakefile* mf); + typedef void (*DeleteData)(void* client_data); cmVariableWatch(); ~cmVariableWatch(); @@ -33,9 +34,10 @@ public: /** * Add watch to the variable */ - void AddWatch(const std::string& variable, WatchMethod method, - void* client_data=0); - void RemoveWatch(const std::string& variable, WatchMethod method); + bool AddWatch(const std::string& variable, WatchMethod method, + void* client_data=0, DeleteData delete_data=0); + void RemoveWatch(const std::string& variable, WatchMethod method, + void* client_data=0); /** * This method is called when variable is accessed @@ -67,10 +69,18 @@ protected: { WatchMethod Method; void* ClientData; - Pair() : Method(0), ClientData(0) {} + DeleteData DeleteDataCall; + Pair() : Method(0), ClientData(0), DeleteDataCall(0) {} + ~Pair() + { + if (this->DeleteDataCall && this->ClientData) + { + this->DeleteDataCall(this->ClientData); + } + } }; - typedef std::vector< Pair > VectorOfPairs; + typedef std::vector< Pair* > VectorOfPairs; typedef std::map<cmStdString, VectorOfPairs > StringToVectorOfPairs; StringToVectorOfPairs WatchMap; diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx index 297a92b..4eff19e 100644 --- a/Source/cmVariableWatchCommand.cxx +++ b/Source/cmVariableWatchCommand.cxx @@ -14,63 +14,27 @@ #include "cmVariableWatch.h" //---------------------------------------------------------------------------- -static void cmVariableWatchCommandVariableAccessed( - const std::string& variable, int access_type, void* client_data, - const char* newValue, const cmMakefile* mf) +struct cmVariableWatchCallbackData { - cmVariableWatchCommand* command - = static_cast<cmVariableWatchCommand*>(client_data); - command->VariableAccessed(variable, access_type, newValue, mf); -} + bool InCallback; + std::string Command; +}; //---------------------------------------------------------------------------- -cmVariableWatchCommand::cmVariableWatchCommand() +static void cmVariableWatchCommandVariableAccessed( + const std::string& variable, int access_type, void* client_data, + const char* newValue, const cmMakefile* mf) { - this->InCallback = false; -} + cmVariableWatchCallbackData* data + = static_cast<cmVariableWatchCallbackData*>(client_data); -//---------------------------------------------------------------------------- -bool cmVariableWatchCommand -::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) -{ - if ( args.size() < 1 ) - { - this->SetError("must be called with at least one argument."); - return false; - } - std::string variable = args[0]; - if ( args.size() > 1 ) - { - std::string command = args[1]; - this->Handlers[variable].Commands.push_back(args[1]); - } - if ( variable == "CMAKE_CURRENT_LIST_FILE" ) - { - cmOStringStream ostr; - ostr << "cannot be set on the variable: " << variable.c_str(); - this->SetError(ostr.str().c_str()); - return false; - } - - this->Makefile->GetCMakeInstance()->GetVariableWatch()->AddWatch( - variable, cmVariableWatchCommandVariableAccessed, this); - - return true; -} - -//---------------------------------------------------------------------------- -void cmVariableWatchCommand::VariableAccessed(const std::string& variable, - int access_type, const char* newValue, const cmMakefile* mf) -{ - if ( this->InCallback ) + if ( data->InCallback ) { return; } - this->InCallback = true; + data->InCallback = true; cmListFileFunction newLFF; - cmVariableWatchCommandHandler *handler = &this->Handlers[variable]; - cmVariableWatchCommandHandler::VectorOfCommands::iterator it; cmListFileArgument arg; bool processed = false; const char* accessString = cmVariableWatch::GetAccessAsString(access_type); @@ -80,10 +44,8 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable, cmMakefile* makefile = const_cast<cmMakefile*>(mf); std::string stack = makefile->GetProperty("LISTFILE_STACK"); - for ( it = handler->Commands.begin(); it != handler->Commands.end(); - ++ it ) + if ( !data->Command.empty() ) { - std::string command = *it; newLFF.Arguments.clear(); newLFF.Arguments.push_back( cmListFileArgument(variable, true, "unknown", 9999)); @@ -95,7 +57,7 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable, cmListFileArgument(currentListFile, true, "unknown", 9999)); newLFF.Arguments.push_back( cmListFileArgument(stack, true, "unknown", 9999)); - newLFF.Name = command; + newLFF.Name = data->Command; newLFF.FilePath = "Some weird path"; newLFF.Line = 9999; cmExecutionStatus status; @@ -106,10 +68,10 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable, cmOStringStream error; error << "Error in cmake code at\n" << arg.FilePath << ":" << arg.Line << ":\n" - << "A command failed during the invocation of callback\"" - << command << "\"."; + << "A command failed during the invocation of callback \"" + << data->Command << "\"."; cmSystemTools::Error(error.str().c_str()); - this->InCallback = false; + data->InCallback = false; return; } processed = true; @@ -118,8 +80,75 @@ void cmVariableWatchCommand::VariableAccessed(const std::string& variable, { cmOStringStream msg; msg << "Variable \"" << variable.c_str() << "\" was accessed using " - << accessString << " with value \"" << newValue << "\"."; + << accessString << " with value \"" << (newValue?newValue:"") << "\"."; makefile->IssueMessage(cmake::LOG, msg.str()); } - this->InCallback = false; + + data->InCallback = false; +} + +//---------------------------------------------------------------------------- +static void deleteVariableWatchCallbackData(void* client_data) +{ + cmVariableWatchCallbackData* data + = static_cast<cmVariableWatchCallbackData*>(client_data); + delete data; +} + +//---------------------------------------------------------------------------- +cmVariableWatchCommand::cmVariableWatchCommand() +{ +} + +//---------------------------------------------------------------------------- +cmVariableWatchCommand::~cmVariableWatchCommand() +{ + std::set<std::string>::const_iterator it; + for ( it = this->WatchedVariables.begin(); + it != this->WatchedVariables.end(); + ++it ) + { + this->Makefile->GetCMakeInstance()->GetVariableWatch()->RemoveWatch( + *it, cmVariableWatchCommandVariableAccessed); + } +} + +//---------------------------------------------------------------------------- +bool cmVariableWatchCommand +::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &) +{ + if ( args.size() < 1 ) + { + this->SetError("must be called with at least one argument."); + return false; + } + std::string variable = args[0]; + std::string command; + if ( args.size() > 1 ) + { + command = args[1]; + } + if ( variable == "CMAKE_CURRENT_LIST_FILE" ) + { + cmOStringStream ostr; + ostr << "cannot be set on the variable: " << variable.c_str(); + this->SetError(ostr.str().c_str()); + return false; + } + + cmVariableWatchCallbackData* data = new cmVariableWatchCallbackData; + + data->InCallback = false; + data->Command = command; + + this->WatchedVariables.insert(variable); + if ( !this->Makefile->GetCMakeInstance()->GetVariableWatch()->AddWatch( + variable, cmVariableWatchCommandVariableAccessed, + data, deleteVariableWatchCallbackData) ) + { + deleteVariableWatchCallbackData(data); + return false; + } + + return true; } diff --git a/Source/cmVariableWatchCommand.h b/Source/cmVariableWatchCommand.h index 3abc088..545535c 100644 --- a/Source/cmVariableWatchCommand.h +++ b/Source/cmVariableWatchCommand.h @@ -14,13 +14,6 @@ #include "cmCommand.h" -class cmVariableWatchCommandHandler -{ -public: - typedef std::vector<std::string> VectorOfCommands; - VectorOfCommands Commands; -}; - /** \class cmVariableWatchCommand * \brief Watch when the variable changes and invoke command * @@ -39,6 +32,9 @@ public: //! Default constructor cmVariableWatchCommand(); + //! Destructor. + ~cmVariableWatchCommand(); + /** * This is called when the command is first encountered in * the CMakeLists.txt file. @@ -83,13 +79,8 @@ public: cmTypeMacro(cmVariableWatchCommand, cmCommand); - void VariableAccessed(const std::string& variable, int access_type, - const char* newValue, const cmMakefile* mf); - protected: - std::map<std::string, cmVariableWatchCommandHandler> Handlers; - - bool InCallback; + std::set<std::string> WatchedVariables; }; |