From 025ffba8fd9d63c95855e148adb72e39b1a14062 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Tue, 13 May 2014 17:53:42 +0530 Subject: [PATCH 001/111] Removed signed-unsigned comparison warning --- src/cllazyfile/lazy_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cllazyfile/lazy_test.cc b/src/cllazyfile/lazy_test.cc index 31242ca67..f165777b5 100644 --- a/src/cllazyfile/lazy_test.cc +++ b/src/cllazyfile/lazy_test.cc @@ -89,7 +89,7 @@ void printDeps( lazyInstMgr & mgr ) { std::cout << *it << " "; } - if( dependencies->size() > displayInstances ) { + if( ( int )dependencies->size() > displayInstances ) { std::cout << ".... (Displaying only " << displayInstances << " instances) "; } From 8b8cde064f0da143438268c9fdaa76e81653aa0e Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 19 May 2014 09:33:05 +0530 Subject: [PATCH 002/111] Added Test for checking thread safety Currently it only checks whether concurrent read accesses to _fwdInstanceRefs & _revInstanceRefs are thread safe our not. --- src/cllazyfile/CMakeLists.txt | 4 + src/cllazyfile/lazy_thread_safety_test.cc | 103 ++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 src/cllazyfile/lazy_thread_safety_test.cc diff --git a/src/cllazyfile/CMakeLists.txt b/src/cllazyfile/CMakeLists.txt index 3bf255028..98dc26681 100644 --- a/src/cllazyfile/CMakeLists.txt +++ b/src/cllazyfile/CMakeLists.txt @@ -37,6 +37,10 @@ SC_ADDLIB(steplazyfile "${clLazyFile_SRCS};${clLazyFile_HDRS}" "stepcore;stepdai SC_ADDEXEC(lazy_test "lazy_test.cc" "steplazyfile;stepeditor" ) set_target_properties(lazy_test PROPERTIES COMPILE_FLAGS "-DNO_REGISTRY" ) +SC_ADDEXEC(lazy_thread_safety_test "lazy_thread_safety_test.cc" "steplazyfile;stepeditor" ) +set_target_properties(lazy_thread_safety_test PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x" ) +list(APPEND CMAKE_CXX_FLAGS "-pthread -std=c++0x") + install(FILES ${SC_CLLAZYFILE_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/stepcode/cllazyfile) diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc new file mode 100644 index 000000000..ea15b2e85 --- /dev/null +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -0,0 +1,103 @@ +#include +#include "lazyTypes.h" +#include "lazyInstMgr.h" + +/// It copies the keys of the _refs judy structure provided to it into the vector realRefs +void prepareRealRefs ( instanceRefs_t * _refs, instanceRefs &realRefs ) { + + realRefs.clear(); + + instanceID last = _refs->end().key; + instanceID current = _refs->begin().key; + + while( current != last ) { + realRefs.push_back( current ); + current = _refs->next().key; + } + + realRefs.push_back ( last ); +} + +/// Used by an individual thread to iterate over the keys of the _fwdRefs / _revRefs multiple times. For each iteration it expects the order of the keys to be the same as dictated by realRefs. +void iterateOverRefs ( instanceRefs_t * _refs, instanceRefs &realRefs, bool * success ) { + const int iterations = 10; + int i, k, instances = realRefs.size(); + instanceID current; + + for( k = 0; k < iterations; k++ ) { + current = _refs->begin().key; + for( i = 0; i < instances; i++ ) { + + if( current != realRefs[i] ) { + break; + } + + current = _refs->next().key; + } + + *success = *success && ( i == instances ); + } +} + +/// Checks the thread safety of _fwdRefs (_revRefs) when the forward value provided to it is true (false). +void checkRefsSafety( char * fileName, bool forward ) { + instanceRefs_t * _refs; + instanceRefs realRefs; + lazyInstMgr * mgr = new lazyInstMgr; + mgr->openFile( fileName ); + + if( forward ) { + std::cout << "Checking thread safety while iterating over forward references..." ; + _refs = mgr->getFwdRefs(); + } else { + std::cout << "Checking thread safety while iterating over backward references..." ; + _refs = mgr->getRevRefs(); + } + + prepareRealRefs( _refs, realRefs ); + bool success[2] = { true, true }; + + std::thread first( iterateOverRefs, _refs, realRefs, &success[0] ); + std::thread second( iterateOverRefs, _refs, realRefs, &success[1] ); + + first.join(); + second.join(); + + if( success[0] && success[1] ) { + std::cout << "..PASS!" << std::endl; + } else { + std::cout << "...FAIL!" << std::endl; + + if( !success[0] ) { + std::cout << "\tThread 0 could not iterate properly" << std::endl; + } + + if( !success[1] ) { + std::cout << "\tThread 1 could not iterate properly" << std::endl; + } + } + + std::cout << std::endl; + delete mgr; +} + +/// Checks thread safety of getFwdRefs(); +void checkFwdRefsSafety( char * fileName ) { + checkRefsSafety( fileName, true ); +} + +/// Checks thread safety of getFwdRefs(); +void checkRevRefsSafety( char * fileName ) { + checkRefsSafety( fileName, false ); +} + +int main( int argc, char ** argv ) { + if( argc != 2 ) { + std::cerr << "Expected one argument, given " << argc - 1 << ". Exiting." << std::endl; + exit( EXIT_FAILURE ); + } + + checkFwdRefsSafety( argv[1] ); + checkRevRefsSafety( argv[1] ); +} + From a47447a7f9435776d0d5722f25a88385626983cc Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 19 May 2014 10:18:22 +0530 Subject: [PATCH 003/111] Improved thread safety test Moved mgr->getFwdRefs() inside the thread workload --- src/cllazyfile/lazy_thread_safety_test.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index ea15b2e85..8b96d089e 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -19,12 +19,15 @@ void prepareRealRefs ( instanceRefs_t * _refs, instanceRefs &realRefs ) { } /// Used by an individual thread to iterate over the keys of the _fwdRefs / _revRefs multiple times. For each iteration it expects the order of the keys to be the same as dictated by realRefs. -void iterateOverRefs ( instanceRefs_t * _refs, instanceRefs &realRefs, bool * success ) { +void iterateOverRefs ( lazyInstMgr *mgr, instanceRefs &realRefs, bool forward, bool * success ) { const int iterations = 10; int i, k, instances = realRefs.size(); instanceID current; + instanceRefs_t * _refs; for( k = 0; k < iterations; k++ ) { + _refs = forward ? mgr->getFwdRefs() : mgr->getRevRefs(); + current = _refs->begin().key; for( i = 0; i < instances; i++ ) { @@ -41,24 +44,21 @@ void iterateOverRefs ( instanceRefs_t * _refs, instanceRefs &realRefs, bool * su /// Checks the thread safety of _fwdRefs (_revRefs) when the forward value provided to it is true (false). void checkRefsSafety( char * fileName, bool forward ) { - instanceRefs_t * _refs; instanceRefs realRefs; lazyInstMgr * mgr = new lazyInstMgr; mgr->openFile( fileName ); if( forward ) { std::cout << "Checking thread safety while iterating over forward references..." ; - _refs = mgr->getFwdRefs(); + prepareRealRefs( mgr->getFwdRefs(), realRefs ); } else { std::cout << "Checking thread safety while iterating over backward references..." ; - _refs = mgr->getRevRefs(); + prepareRealRefs( mgr->getRevRefs(), realRefs ); } - prepareRealRefs( _refs, realRefs ); bool success[2] = { true, true }; - - std::thread first( iterateOverRefs, _refs, realRefs, &success[0] ); - std::thread second( iterateOverRefs, _refs, realRefs, &success[1] ); + std::thread first( iterateOverRefs, mgr, realRefs, forward, &success[0] ); + std::thread second( iterateOverRefs, mgr, realRefs, forward, &success[1] ); first.join(); second.join(); From c0e26cda16bdd77f10997cd77c4ac4aaf7826214 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 19 May 2014 19:08:50 +0530 Subject: [PATCH 004/111] Added getFwdRefsSafely() and getRevRefsSafely() These functions are thread safe counterparts to getFwdRefs() and getRevRefs() respectively. The CMakeFiles have been modified to make this test run. They will be restored in the later commits. --- cmake/SC_CXX_schema_macros.cmake | 2 +- src/cllazyfile/lazyInstMgr.cc | 18 ++++++++++++++++++ src/cllazyfile/lazyInstMgr.h | 12 ++++++++++++ src/cllazyfile/lazy_thread_safety_test.cc | 6 +++--- 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/cmake/SC_CXX_schema_macros.cmake b/cmake/SC_CXX_schema_macros.cmake index ae773cb84..23c00eb1a 100644 --- a/cmake/SC_CXX_schema_macros.cmake +++ b/cmake/SC_CXX_schema_macros.cmake @@ -30,7 +30,7 @@ macro(SCHEMA_EXES) SC_ADDEXEC(p21read_${PROJECT_NAME} "${RELATIVE_PATH_COMPONENT}/src/test/p21read/p21read.cc" "${PROJECT_NAME};stepdai;stepcore;stepeditor;steputils;base" "TESTABLE") #add_dependencies(p21read_${PROJECT_NAME} version_string) if(NOT WIN32) - SC_ADDEXEC(lazy_${PROJECT_NAME} "${RELATIVE_PATH_COMPONENT}/src/cllazyfile/lazy_test.cc" "${PROJECT_NAME};steplazyfile;stepdai;stepcore;stepeditor;steputils;base" "TESTABLE") + #SC_ADDEXEC(lazy_${PROJECT_NAME} "${RELATIVE_PATH_COMPONENT}/src/cllazyfile/lazy_test.cc" "${PROJECT_NAME};steplazyfile;stepdai;stepcore;stepeditor;steputils;base" "TESTABLE") #add_dependencies(lazy_${PROJECT_NAME} version_string) endif(NOT WIN32) diff --git a/src/cllazyfile/lazyInstMgr.cc b/src/cllazyfile/lazyInstMgr.cc index 172b2358d..382b24c50 100644 --- a/src/cllazyfile/lazyInstMgr.cc +++ b/src/cllazyfile/lazyInstMgr.cc @@ -125,6 +125,24 @@ SDAI_Application_instance * lazyInstMgr::loadInstance( instanceID id ) { return inst; } +instanceRefs_t * lazyInstMgr::getFwdRefsSafely() { + + fwdRefsMtx.lock(); + instanceRefs_t * myFwdRefsCopy = new instanceRefs_t( _fwdInstanceRefs ); + fwdRefsMtx.unlock(); + + return myFwdRefsCopy; +} + +// A thread safe counterpart of getRevRefs() +instanceRefs_t * lazyInstMgr::getRevRefsSafely() { + + revRefsMtx.lock(); + instanceRefs_t * myRevRefsCopy = new instanceRefs_t( _revInstanceRefs ); + revRefsMtx.unlock(); + + return myRevRefsCopy; +} instanceSet * lazyInstMgr::instanceDependencies( instanceID id ) { instanceSet * checkedDependencies = new instanceSet(); diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index 57d3efded..194a6d9af 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "lazyDataSectionReader.h" #include "lazyFileReader.h" @@ -62,6 +63,10 @@ class lazyInstMgr { instMgrAdapter * _ima; + /** mutexes for mutual exclusion */ + std::mutex fwdRefsMtx; + std::mutex revRefsMtx; + public: lazyInstMgr(); ~lazyInstMgr(); @@ -80,6 +85,13 @@ class lazyInstMgr { instanceRefs_t * getRevRefs() { return & _revInstanceRefs; } + + /// thread safe counterpart of getFwdRefs() + instanceRefs_t * getFwdRefsSafely(); + + /// thread safe counterpart of getRevRefs() + instanceRefs_t * getRevRefsSafely(); + /// returns two iterators delimiting the instances that match `type` instanceTypes_t::cvector * getInstances( std::string type ) { /*const*/ return _instanceTypes->find( type.c_str() ); diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index 8b96d089e..b47be4425 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -20,13 +20,13 @@ void prepareRealRefs ( instanceRefs_t * _refs, instanceRefs &realRefs ) { /// Used by an individual thread to iterate over the keys of the _fwdRefs / _revRefs multiple times. For each iteration it expects the order of the keys to be the same as dictated by realRefs. void iterateOverRefs ( lazyInstMgr *mgr, instanceRefs &realRefs, bool forward, bool * success ) { - const int iterations = 10; + const int iterations = 1000; int i, k, instances = realRefs.size(); instanceID current; instanceRefs_t * _refs; for( k = 0; k < iterations; k++ ) { - _refs = forward ? mgr->getFwdRefs() : mgr->getRevRefs(); + _refs = forward ? mgr->getFwdRefsSafely() : mgr->getRevRefsSafely(); current = _refs->begin().key; for( i = 0; i < instances; i++ ) { @@ -50,7 +50,7 @@ void checkRefsSafety( char * fileName, bool forward ) { if( forward ) { std::cout << "Checking thread safety while iterating over forward references..." ; - prepareRealRefs( mgr->getFwdRefs(), realRefs ); + prepareRealRefs( mgr->getFwdRefsSafely(), realRefs ); } else { std::cout << "Checking thread safety while iterating over backward references..." ; prepareRealRefs( mgr->getRevRefs(), realRefs ); From 8a528de01c552d15a97d2eed02e0956e08284a22 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 23 May 2014 10:44:52 +0530 Subject: [PATCH 005/111] Removed Redundant Code and better formatting. --- src/cllazyfile/lazy_thread_safety_test.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index b47be4425..4f954cdd1 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -5,8 +5,6 @@ /// It copies the keys of the _refs judy structure provided to it into the vector realRefs void prepareRealRefs ( instanceRefs_t * _refs, instanceRefs &realRefs ) { - realRefs.clear(); - instanceID last = _refs->end().key; instanceID current = _refs->begin().key; @@ -15,7 +13,7 @@ void prepareRealRefs ( instanceRefs_t * _refs, instanceRefs &realRefs ) { current = _refs->next().key; } - realRefs.push_back ( last ); + realRefs.push_back( last ); } /// Used by an individual thread to iterate over the keys of the _fwdRefs / _revRefs multiple times. For each iteration it expects the order of the keys to be the same as dictated by realRefs. @@ -50,7 +48,7 @@ void checkRefsSafety( char * fileName, bool forward ) { if( forward ) { std::cout << "Checking thread safety while iterating over forward references..." ; - prepareRealRefs( mgr->getFwdRefsSafely(), realRefs ); + prepareRealRefs( mgr->getFwdRefs(), realRefs ); } else { std::cout << "Checking thread safety while iterating over backward references..." ; prepareRealRefs( mgr->getRevRefs(), realRefs ); From cc3c4ec7057079144fe6842396c37c336042c3be Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 23 May 2014 11:04:17 +0530 Subject: [PATCH 006/111] Added test for checking thread safety. The test checks for thread safety in retrieving the list of instances of a particular type. --- src/cllazyfile/lazy_thread_safety_test.cc | 86 +++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index 4f954cdd1..206521a7e 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -89,6 +89,90 @@ void checkRevRefsSafety( char * fileName ) { checkRefsSafety( fileName, false ); } +/// A vector of some common types which are present in most step files. The types persent in this vector are used to check for thread safety. +const std::vector< std::string > commonTypes { "PRODUCT_DEFINITION", "CARTESIAN_POINT", "NODE", "CLASSIFICATION_ROLE" }; + +/// Prepares a vector containing pointers to list of instances of the above types. +void prepareSameTypeInstances( lazyInstMgr *mgr, std::vector< const instanceRefs * > &sameTypeInstances ) { + + for( int i = 0; i < ( int )commonTypes.size(); i++ ) { + sameTypeInstances.push_back( mgr->getInstances( commonTypes[i] ) ); + } +} + +/// compares the list of both vectors. Returns true when the lists are same. +bool compareTypeLists( const instanceRefs * v1, const instanceRefs * v2 ) { + + if( v1 == NULL || v1->empty() ) { + //return true if both lists are NULL or EMPTY. false if only one is NULL or EMPTY + return ( v2 == NULL || v2->empty() ); + } else { + //An O(1) operation since if the first element is same so will be the rest. (std::vectors are concurrent read safe) + return ( v1->at( 0 ) == v2->at( 0 ) ); + } +} + +/// compares the original instances lists with the thread's own view of instances list. +void iterateTypeLists( lazyInstMgr * mgr, std::vector< const instanceRefs * > &sameTypeInstances, bool * success ) { + const int iterations = 100000; + const instanceRefs * refs; + int i, k, instances = commonTypes.size(); + for( k = 0; k < iterations; k++ ) { + + for( i = 0; i < instances; i++ ) { + + refs = mgr->getInstances( commonTypes[i] ); + + if( !compareTypeLists( refs, sameTypeInstances[i] ) ) { + break; + } + } + + *success = *success && ( i == instances ); + } +} + +/// checks the thread safety of getInstances(); +void checkTypeInstancesSafety( char * fileName ) { + lazyInstMgr * mgr = new lazyInstMgr; + mgr->openFile( fileName ); + + std::cout << "Checking thread safety while getting insances of a common types..." ; + + std::vector< const instanceRefs * > sameTypeInstances; + prepareSameTypeInstances( mgr, sameTypeInstances ); + + bool success[2] = { true, true }; + std::thread first( iterateTypeLists, mgr, sameTypeInstances, &success[0] ); + std::thread second( iterateTypeLists, mgr, sameTypeInstances, &success[1] ); + + first.join(); + second.join(); + + if( success[0] && success[1] ) { + std::cout << "..PASS!" << std::endl; + } else { + std::cout << "...FAIL!" << std::endl; + + if( !success[0] ) { + std::cout << "\tThread 0 could not get insances properly" << std::endl; + } + + if( !success[1] ) { + std::cout << "\tThread 1 could not get insances properly" << std::endl; + } + } + + std::cout << "\t\tNumber of instances of different types: "; + for( int i = 0; i < ( int )commonTypes.size(); i++ ) { + std::cout << ( sameTypeInstances[i] == NULL ? 0 : sameTypeInstances[i]->size() ) << " "; + } + + std::cout << std::endl; + delete mgr; +} + + int main( int argc, char ** argv ) { if( argc != 2 ) { std::cerr << "Expected one argument, given " << argc - 1 << ". Exiting." << std::endl; @@ -97,5 +181,7 @@ int main( int argc, char ** argv ) { checkFwdRefsSafety( argv[1] ); checkRevRefsSafety( argv[1] ); + + checkTypeInstancesSafety( argv[1] ); } From 88545df53766064bf3a5907cb480b3ee798ee4f9 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 23 May 2014 11:18:48 +0530 Subject: [PATCH 007/111] Added thread safe count and getInstances function The functions are countInstancesSafely( string type ) and getInstancesSafely( string type ) --- src/cllazyfile/lazyInstMgr.cc | 17 +++++++++++++++++ src/cllazyfile/lazyInstMgr.h | 8 ++++++++ src/cllazyfile/lazy_thread_safety_test.cc | 2 +- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/cllazyfile/lazyInstMgr.cc b/src/cllazyfile/lazyInstMgr.cc index 382b24c50..3a0a55f5d 100644 --- a/src/cllazyfile/lazyInstMgr.cc +++ b/src/cllazyfile/lazyInstMgr.cc @@ -144,6 +144,23 @@ instanceRefs_t * lazyInstMgr::getRevRefsSafely() { return myRevRefsCopy; } +instanceTypes_t::cvector * lazyInstMgr::getInstancesSafely( std::string type ) { + + instanceTypesMtx.lock(); + instanceTypes_t::cvector * typeInstances = _instanceTypes->find( type.c_str() ); + instanceTypesMtx.unlock(); + + return typeInstances; +} + +unsigned int lazyInstMgr::countInstancesSafely( std::string type ) { + instanceTypes_t::cvector * v = getInstancesSafely( type ); + if( !v ) { + return 0; + } + return v->size(); +} + instanceSet * lazyInstMgr::instanceDependencies( instanceID id ) { instanceSet * checkedDependencies = new instanceSet(); instanceRefs dependencies; //Acts as queue for checking duplicated dependency diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index 194a6d9af..a8acf6fa6 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -66,6 +66,7 @@ class lazyInstMgr { /** mutexes for mutual exclusion */ std::mutex fwdRefsMtx; std::mutex revRefsMtx; + std::mutex instanceTypesMtx; public: lazyInstMgr(); @@ -104,6 +105,13 @@ class lazyInstMgr { } return v->size(); } + + /// thread safe counterpart of getInstances() + instanceTypes_t::cvector * getInstancesSafely( std::string type ); + + /// thread safe counterpart of countInstances() + unsigned int countInstancesSafely( std::string type ); + instancesLoaded_t * getHeaderInstances( fileID file ) { return _files[file]->getHeaderInstances(); } diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index 206521a7e..9fbd3b238 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -121,7 +121,7 @@ void iterateTypeLists( lazyInstMgr * mgr, std::vector< const instanceRefs * > &s for( i = 0; i < instances; i++ ) { - refs = mgr->getInstances( commonTypes[i] ); + refs = mgr->getInstancesSafely( commonTypes[i] ); if( !compareTypeLists( refs, sameTypeInstances[i] ) ) { break; From ab3c2d47171ffc626693ad8e9661bae21b0dd537 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 23 May 2014 11:27:03 +0530 Subject: [PATCH 008/111] Commented on which step file was used in the test --- src/cllazyfile/lazy_thread_safety_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index 9fbd3b238..c079e659f 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -172,7 +172,7 @@ void checkTypeInstancesSafety( char * fileName ) { delete mgr; } - +/// These tests were run on stepcode/data/cd209/ATS1-out.stp (Bigger files may take a longer time) int main( int argc, char ** argv ) { if( argc != 2 ) { std::cerr << "Expected one argument, given " << argc - 1 << ". Exiting." << std::endl; From 705483d0abce0fa00a34a1b391febb57ed121f07 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Tue, 27 May 2014 17:28:54 +0530 Subject: [PATCH 009/111] Catered to unsigned-signed overflow --- src/cllazyfile/lazy_test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cllazyfile/lazy_test.cc b/src/cllazyfile/lazy_test.cc index f165777b5..511acec42 100644 --- a/src/cllazyfile/lazy_test.cc +++ b/src/cllazyfile/lazy_test.cc @@ -73,7 +73,7 @@ instanceID printRefs( lazyInstMgr & mgr ) { /// prints dependencies of an instance void printDeps( lazyInstMgr & mgr ) { - const int displayInstances = 10; + const unsigned int displayInstances = 10; instanceRefs_t * refs = mgr.getFwdRefs(); instanceRefs_t::cpair p = refs->end(); @@ -84,12 +84,12 @@ void printDeps( lazyInstMgr & mgr ) { instanceSet::const_iterator it( dependencies->begin() ), end( dependencies->end() ); std::cout << "Example: Instance #" << id << " is recursively dependent on " << dependencies->size() << " instances: "; - int i; + unsigned int i; for(i = 0; it != end && i < displayInstances; it++, i++ ) { std::cout << *it << " "; } - if( ( int )dependencies->size() > displayInstances ) { + if( dependencies->size() > displayInstances ) { std::cout << ".... (Displaying only " << displayInstances << " instances) "; } From f511696c5dc744a2c96d0ea7a5b30df181b3b191 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Tue, 27 May 2014 18:45:38 +0530 Subject: [PATCH 010/111] Used the HAVE_STD_THREAD macro HAVE_STD_THREAD macro was used in src/cllazyfile/CMakeLists.txt and various *.cc and *.h files. The *safely functions have clubbed together in this commit --- src/cllazyfile/CMakeLists.txt | 8 +-- src/cllazyfile/lazyInstMgr.cc | 60 ++++++++++++----------- src/cllazyfile/lazyInstMgr.h | 31 +++++++----- src/cllazyfile/lazy_thread_safety_test.cc | 7 ++- 4 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/cllazyfile/CMakeLists.txt b/src/cllazyfile/CMakeLists.txt index 98dc26681..7d34e439c 100644 --- a/src/cllazyfile/CMakeLists.txt +++ b/src/cllazyfile/CMakeLists.txt @@ -37,9 +37,11 @@ SC_ADDLIB(steplazyfile "${clLazyFile_SRCS};${clLazyFile_HDRS}" "stepcore;stepdai SC_ADDEXEC(lazy_test "lazy_test.cc" "steplazyfile;stepeditor" ) set_target_properties(lazy_test PROPERTIES COMPILE_FLAGS "-DNO_REGISTRY" ) -SC_ADDEXEC(lazy_thread_safety_test "lazy_thread_safety_test.cc" "steplazyfile;stepeditor" ) -set_target_properties(lazy_thread_safety_test PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x" ) -list(APPEND CMAKE_CXX_FLAGS "-pthread -std=c++0x") +if(HAVE_STD_THREAD) + list(APPEND CMAKE_CXX_FLAGS "-pthread -std=c++0x") + SC_ADDEXEC(lazy_thread_safety_test "lazy_thread_safety_test.cc" "steplazyfile;stepeditor" ) + set_target_properties(lazy_thread_safety_test PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x") +endif(HAVE_STD_THREAD) install(FILES ${SC_CLLAZYFILE_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/stepcode/cllazyfile) diff --git a/src/cllazyfile/lazyInstMgr.cc b/src/cllazyfile/lazyInstMgr.cc index 3a0a55f5d..1cb66bbbb 100644 --- a/src/cllazyfile/lazyInstMgr.cc +++ b/src/cllazyfile/lazyInstMgr.cc @@ -125,6 +125,36 @@ SDAI_Application_instance * lazyInstMgr::loadInstance( instanceID id ) { return inst; } +instanceSet * lazyInstMgr::instanceDependencies( instanceID id ) { + instanceSet * checkedDependencies = new instanceSet(); + instanceRefs dependencies; //Acts as queue for checking duplicated dependency + + instanceRefs_t * _fwdRefs = getFwdRefs(); + instanceRefs_t::cvector * _fwdRefsVec = _fwdRefs->find( id ); + //Initially populating direct dependencies of id into the queue + if( _fwdRefsVec != 0 ) { + dependencies.insert( dependencies.end(), _fwdRefsVec->begin(), _fwdRefsVec->end() ); + } + + size_t curPos = 0; + while( curPos < dependencies.size() ) { + + bool isNewElement = ( checkedDependencies->insert( dependencies.at( curPos ) ) ).second; + if( isNewElement ) { + _fwdRefsVec = _fwdRefs->find( dependencies.at( curPos ) ); + + if( _fwdRefsVec != 0 ) { + dependencies.insert( dependencies.end(), _fwdRefsVec->begin(), _fwdRefsVec->end() ); + } + } + + curPos++; + } + + return checkedDependencies; +} + +#ifdef HAVE_STD_THREAD instanceRefs_t * lazyInstMgr::getFwdRefsSafely() { fwdRefsMtx.lock(); @@ -134,7 +164,6 @@ instanceRefs_t * lazyInstMgr::getFwdRefsSafely() { return myFwdRefsCopy; } -// A thread safe counterpart of getRevRefs() instanceRefs_t * lazyInstMgr::getRevRefsSafely() { revRefsMtx.lock(); @@ -161,32 +190,5 @@ unsigned int lazyInstMgr::countInstancesSafely( std::string type ) { return v->size(); } -instanceSet * lazyInstMgr::instanceDependencies( instanceID id ) { - instanceSet * checkedDependencies = new instanceSet(); - instanceRefs dependencies; //Acts as queue for checking duplicated dependency - - instanceRefs_t * _fwdRefs = getFwdRefs(); - instanceRefs_t::cvector * _fwdRefsVec = _fwdRefs->find( id ); - //Initially populating direct dependencies of id into the queue - if( _fwdRefsVec != 0 ) { - dependencies.insert( dependencies.end(), _fwdRefsVec->begin(), _fwdRefsVec->end() ); - } - - size_t curPos = 0; - while( curPos < dependencies.size() ) { - - bool isNewElement = ( checkedDependencies->insert( dependencies.at( curPos ) ) ).second; - if( isNewElement ) { - _fwdRefsVec = _fwdRefs->find( dependencies.at( curPos ) ); - - if( _fwdRefsVec != 0 ) { - dependencies.insert( dependencies.end(), _fwdRefsVec->begin(), _fwdRefsVec->end() ); - } - } - - curPos++; - } - - return checkedDependencies; -} +#endif //HAVE_STD_THREAD diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index a8acf6fa6..0c60b5e47 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -4,12 +4,15 @@ #include #include #include -#include #include "lazyDataSectionReader.h" #include "lazyFileReader.h" #include "lazyTypes.h" +#ifdef HAVE_STD_THREAD +# include +#endif //HAVE_STD_THREAD + #include "Registry.h" #include "sc_memmgr.h" @@ -87,12 +90,6 @@ class lazyInstMgr { return & _revInstanceRefs; } - /// thread safe counterpart of getFwdRefs() - instanceRefs_t * getFwdRefsSafely(); - - /// thread safe counterpart of getRevRefs() - instanceRefs_t * getRevRefsSafely(); - /// returns two iterators delimiting the instances that match `type` instanceTypes_t::cvector * getInstances( std::string type ) { /*const*/ return _instanceTypes->find( type.c_str() ); @@ -106,12 +103,6 @@ class lazyInstMgr { return v->size(); } - /// thread safe counterpart of getInstances() - instanceTypes_t::cvector * getInstancesSafely( std::string type ); - - /// thread safe counterpart of countInstances() - unsigned int countInstancesSafely( std::string type ); - instancesLoaded_t * getHeaderInstances( fileID file ) { return _files[file]->getHeaderInstances(); } @@ -171,6 +162,20 @@ class lazyInstMgr { //list all instances that one instance depends on (recursive) instanceSet * instanceDependencies( instanceID id ); +#ifdef HAVE_STD_THREAD + /// thread safe counterpart of getFwdRefs() + instanceRefs_t * getFwdRefsSafely(); + + /// thread safe counterpart of getRevRefs() + instanceRefs_t * getRevRefsSafely(); + + /// thread safe counterpart of getInstances() + instanceTypes_t::cvector * getInstancesSafely( std::string type ); + + /// thread safe counterpart of countInstances() + unsigned int countInstancesSafely( std::string type ); +#endif //HAVE_STD_THREAD + // TODO implement these /* * the opposite of instanceDependencies() - all instances that are *not* dependencies of one particular instance same as above, but with list of instances */ diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index c079e659f..731655a17 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -1,7 +1,12 @@ -#include #include "lazyTypes.h" #include "lazyInstMgr.h" +#ifdef HAVE_STD_THREAD +# include +#else +# error Need std::thread for this test! +#endif + /// It copies the keys of the _refs judy structure provided to it into the vector realRefs void prepareRealRefs ( instanceRefs_t * _refs, instanceRefs &realRefs ) { From c2aecfb649236c3119f49f6dd9e5244b4262b316 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Tue, 27 May 2014 19:22:58 +0530 Subject: [PATCH 011/111] Added HAVE_STD_THREAD on mutex declerations also. --- src/cllazyfile/lazyInstMgr.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index 0c60b5e47..98b1c6e74 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -66,10 +66,12 @@ class lazyInstMgr { instMgrAdapter * _ima; +#ifdef HAVE_STD_THREAD /** mutexes for mutual exclusion */ std::mutex fwdRefsMtx; std::mutex revRefsMtx; std::mutex instanceTypesMtx; +#endif //HAVE_STD_THREAD public: lazyInstMgr(); From 14107427b955a2c55026a17746c9e67a0e8a0595 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Tue, 27 May 2014 22:13:16 +0530 Subject: [PATCH 012/111] Added thread-safe instance dependencies counterpart --- src/cllazyfile/lazyInstMgr.cc | 11 +++++++++-- src/cllazyfile/lazyInstMgr.h | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/cllazyfile/lazyInstMgr.cc b/src/cllazyfile/lazyInstMgr.cc index 1cb66bbbb..38359321a 100644 --- a/src/cllazyfile/lazyInstMgr.cc +++ b/src/cllazyfile/lazyInstMgr.cc @@ -125,11 +125,10 @@ SDAI_Application_instance * lazyInstMgr::loadInstance( instanceID id ) { return inst; } -instanceSet * lazyInstMgr::instanceDependencies( instanceID id ) { +instanceSet * lazyInstMgr::instanceDependenciesHelper( instanceID id, instanceRefs_t * _fwdRefs ) { instanceSet * checkedDependencies = new instanceSet(); instanceRefs dependencies; //Acts as queue for checking duplicated dependency - instanceRefs_t * _fwdRefs = getFwdRefs(); instanceRefs_t::cvector * _fwdRefsVec = _fwdRefs->find( id ); //Initially populating direct dependencies of id into the queue if( _fwdRefsVec != 0 ) { @@ -154,6 +153,10 @@ instanceSet * lazyInstMgr::instanceDependencies( instanceID id ) { return checkedDependencies; } +instanceSet * lazyInstMgr::instanceDependencies( instanceID id ) { + return instanceDependenciesHelper( id, getFwdRefs() ); +} + #ifdef HAVE_STD_THREAD instanceRefs_t * lazyInstMgr::getFwdRefsSafely() { @@ -190,5 +193,9 @@ unsigned int lazyInstMgr::countInstancesSafely( std::string type ) { return v->size(); } +instanceSet * lazyInstMgr::instanceDependenciesSafely( instanceID id ) { + return instanceDependenciesHelper( id, getFwdRefsSafely() ); +} + #endif //HAVE_STD_THREAD diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index 98b1c6e74..401de78dd 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -163,6 +163,7 @@ class lazyInstMgr { //list all instances that one instance depends on (recursive) instanceSet * instanceDependencies( instanceID id ); + instanceSet * instanceDependenciesHelper( instanceID id, instanceRefs_t * _fwdRefs ); #ifdef HAVE_STD_THREAD /// thread safe counterpart of getFwdRefs() @@ -176,6 +177,9 @@ class lazyInstMgr { /// thread safe counterpart of countInstances() unsigned int countInstancesSafely( std::string type ); + + //Thread safe counterpart of instanceDependencies( instanceID ) + instanceSet * instanceDependenciesSafely( instanceID id ); #endif //HAVE_STD_THREAD // TODO implement these From 97e6b9b3c6d5c14777215a21b4391dbef0cb4450 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 28 May 2014 19:34:00 +0530 Subject: [PATCH 013/111] Explicit HAVE_STD_THREAD decleration through CMake --- src/cllazyfile/CMakeLists.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/cllazyfile/CMakeLists.txt b/src/cllazyfile/CMakeLists.txt index 7d34e439c..c7f165cb2 100644 --- a/src/cllazyfile/CMakeLists.txt +++ b/src/cllazyfile/CMakeLists.txt @@ -33,16 +33,19 @@ include_directories( ${SC_SOURCE_DIR}/src/base/judy/src ) -SC_ADDLIB(steplazyfile "${clLazyFile_SRCS};${clLazyFile_HDRS}" "stepcore;stepdai;steputils;base") -SC_ADDEXEC(lazy_test "lazy_test.cc" "steplazyfile;stepeditor" ) -set_target_properties(lazy_test PROPERTIES COMPILE_FLAGS "-DNO_REGISTRY" ) +SC_ADDLIB(steplazyfile "${clLazyFile_SRCS};${clLazyFile_HDRS}" "stepcore;stepdai;steputils;base;") if(HAVE_STD_THREAD) list(APPEND CMAKE_CXX_FLAGS "-pthread -std=c++0x") + set_target_properties(steplazyfile PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD" ) + SC_ADDEXEC(lazy_thread_safety_test "lazy_thread_safety_test.cc" "steplazyfile;stepeditor" ) - set_target_properties(lazy_thread_safety_test PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x") + set_target_properties(lazy_thread_safety_test PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD") endif(HAVE_STD_THREAD) +SC_ADDEXEC(lazy_test "lazy_test.cc" "steplazyfile;stepeditor" ) +set_target_properties(lazy_test PROPERTIES COMPILE_FLAGS "-DNO_REGISTRY" ) + install(FILES ${SC_CLLAZYFILE_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/stepcode/cllazyfile) From e357da8a75eb5a418444b590d9820787c3382f35 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 28 May 2014 20:09:26 +0530 Subject: [PATCH 014/111] Fixed lazy parser not handling newlines in step files This bug was first noticed when trying to lazy-load instance: 637538274 in data/cd209/ATS1-out.stp. The parser now stores the first whitespace character and skips the following whitespaces. It then compares the first whitespace character and the character in the current position with the set of provided delimeters to determine whether correct delimeter has been reached. --- src/cllazyfile/sectionReader.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/cllazyfile/sectionReader.cc b/src/cllazyfile/sectionReader.cc index 05058d842..4ba9a8ab9 100644 --- a/src/cllazyfile/sectionReader.cc +++ b/src/cllazyfile/sectionReader.cc @@ -84,7 +84,7 @@ std::streampos sectionReader::findNormalString( const std::string & str, bool se //NOTE different behavior than const char * GetKeyword( istream & in, const char * delims, ErrorDescriptor & err ) in read_func.cc const char * sectionReader::getDelimitedKeyword( const char * delimiters ) { static std::string str; - char c; + char c, firstSpaceDelimeter; str.clear(); str.reserve( 100 ); skipWS(); @@ -97,13 +97,19 @@ const char * sectionReader::getDelimitedKeyword( const char * delimiters ) { findNormalString( "*/" ); skipWS(); continue; + } else if( isspace( c ) ) { + //firstSpaceDelimeter is used for comparision later to handle the case where the first whitespace was a delimeter itself + firstSpaceDelimeter = c; + skipWS();//skip the remaining whitespaces + break; } else { _file.putback( c ); break; } } c = _file.peek(); - if( !strchr( delimiters, c ) ) { + if( !strchr( delimiters, c ) && !strchr( delimiters, firstSpaceDelimeter ) ) { + // current c is not a delimiter, the first white space encountered is also not a delimeter std::cerr << SC_CURRENT_FUNCTION << ": missing delimiter. Found " << c << ", expected one of " << delimiters << " at end of keyword " << str << ". File offset: " << _file.tellg() << std::endl; abort(); } From 4bd2682b51d0242a3705da464d46b671a559996b Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 28 May 2014 20:17:02 +0530 Subject: [PATCH 015/111] Fixed an appearance of a warning in loadInstance(id) Earlier even if the instance 'id' had already been loaded before, the function would display a warning that the instance 'id' was not found in any section --- src/cllazyfile/lazyInstMgr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cllazyfile/lazyInstMgr.cc b/src/cllazyfile/lazyInstMgr.cc index 38359321a..cee10ab2d 100644 --- a/src/cllazyfile/lazyInstMgr.cc +++ b/src/cllazyfile/lazyInstMgr.cc @@ -119,7 +119,7 @@ SDAI_Application_instance * lazyInstMgr::loadInstance( instanceID id ) { } else { std::cerr << "Error loading instance #" << id << "." << std::endl; } - } else { + } else if( !inst ) { std::cerr << "Instance #" << id << " not found in any section." << std::endl; } return inst; From c6800fc9b467af065c0b448de17e177ddd025e8c Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 28 May 2014 20:31:56 +0530 Subject: [PATCH 016/111] Initializing _mainRegistry to 0 in lazyInstMgr constructor This was needed to prevent the assert in setRegistry from failing under the following workload lazyInstMgr * mgr = new lazyInstMgr; mgr->initRegistry( SchemaInit ); mgr->openFile( fileName ); delete mgr; lazyInstMgr * mgr = new lazyInstMgr; mgr->initRegistry( SchemaInit ); --- src/cllazyfile/lazyInstMgr.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cllazyfile/lazyInstMgr.cc b/src/cllazyfile/lazyInstMgr.cc index cee10ab2d..352c0e4f7 100644 --- a/src/cllazyfile/lazyInstMgr.cc +++ b/src/cllazyfile/lazyInstMgr.cc @@ -6,6 +6,7 @@ lazyInstMgr::lazyInstMgr() { _headerRegistry = new Registry( HeaderSchemaInit ); + _mainRegistry = 0; _instanceTypes = new instanceTypes_t( 255 ); //NOTE arbitrary max of 255 chars for a type name _lazyInstanceCount = 0; _loadedInstanceCount = 0; From 5f38d1bd936fea85c4861026909a6ace914ae3b2 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 28 May 2014 20:46:47 +0530 Subject: [PATCH 017/111] Added test for checking thread safety of loadInstance The check fails with a abort comming from the parser as loadInstance is not thread safe --- src/cllazyfile/CMakeLists.txt | 6 ++ src/cllazyfile/lazyInstMgr.h | 6 ++ src/cllazyfile/lazy_thread_safety_test.cc | 116 ++++++++++++++++++++++ 3 files changed, 128 insertions(+) diff --git a/src/cllazyfile/CMakeLists.txt b/src/cllazyfile/CMakeLists.txt index c7f165cb2..6260f95dd 100644 --- a/src/cllazyfile/CMakeLists.txt +++ b/src/cllazyfile/CMakeLists.txt @@ -39,8 +39,14 @@ if(HAVE_STD_THREAD) list(APPEND CMAKE_CXX_FLAGS "-pthread -std=c++0x") set_target_properties(steplazyfile PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD" ) + #Directory frim which lazy_thread_safety_test will get its schema.h + include_directories( + ${CMAKE_BINARY_DIR}/schemas/sdai_cd209 + ) + SC_ADDEXEC(lazy_thread_safety_test "lazy_thread_safety_test.cc" "steplazyfile;stepeditor" ) set_target_properties(lazy_thread_safety_test PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD") + target_link_libraries(lazy_thread_safety_test sdai_cd209 "pthread" ) endif(HAVE_STD_THREAD) SC_ADDEXEC(lazy_test "lazy_test.cc" "steplazyfile;stepeditor" ) diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index 401de78dd..888399c89 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -182,6 +182,12 @@ class lazyInstMgr { instanceSet * instanceDependenciesSafely( instanceID id ); #endif //HAVE_STD_THREAD + //unloads all instances. (For testing purpose, not thread safe) + void unloadAllInstances() { + _loadedInstanceCount = 0; + _instancesLoaded.clear(); + } + // TODO implement these /* * the opposite of instanceDependencies() - all instances that are *not* dependencies of one particular instance same as above, but with list of instances */ diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index 731655a17..6c5286ace 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -1,5 +1,9 @@ #include "lazyTypes.h" #include "lazyInstMgr.h" +#include "SdaiSchemaInit.h" +#include "instMgrHelper.h" + +#include "schema.h" #ifdef HAVE_STD_THREAD # include @@ -173,6 +177,116 @@ void checkTypeInstancesSafety( char * fileName ) { std::cout << ( sameTypeInstances[i] == NULL ? 0 : sameTypeInstances[i]->size() ) << " "; } + std::cout << std::endl << std::endl; + delete mgr; +} + +/// load instances found in _refs into the instancesLoaded. After doing this once, it iterates over the _refs and reports any changes in loaded value. +void loadInstancesFromList( lazyInstMgr * mgr, instanceRefs * _refs, instancesLoaded_t * myInstances, bool * success) { + const int instances = _refs->size(); + SDAI_Application_instance * sdaiInstance; + int i; + // Initial insertion into myInstances + for( i = 0; i < instances; i++ ) { + sdaiInstance = mgr->loadInstance( _refs->at( i ) ); + myInstances->insert( _refs->at( i ), sdaiInstance ); + } + + // For each instance comparing the new pointer with the original pointer + for( i = 0; i < instances; i++ ) { + sdaiInstance = mgr->loadInstance( _refs->at( i ) ); + + if( myInstances->find( _refs->at( i ) ) != sdaiInstance ) { + //the old value has been overwritten. An object lazy-loaded twice. Not Good!!! + *success = false; + } + } +} + +//compares the instances present in loadedOnT1 and loadedOnT2. If both have an instance belonging to a particular instanceID then the instances should be same +bool compareLoadedInstances( instanceRefs * toBeLoadedOnT1, instancesLoaded_t * loadedOnT1, instanceRefs * toBeLoadedOnT2, instancesLoaded_t * loadedOnT2 ) { + SDAI_Application_instance * sdaiInstance; + + //Iterate over instanceID's in toBeLoadedOnT1 + int i, instances = toBeLoadedOnT1->size(); + for( i = 0; i < instances; i++ ) { + sdaiInstance = loadedOnT2->find( toBeLoadedOnT1->at( i ) ); + if( sdaiInstance != NULL ) { + if( sdaiInstance != loadedOnT1->find( toBeLoadedOnT1->at( i ) ) ) { + return false; + } + } + } + + //Iterate over instanceID's in toBeLoadedOnT2 + instances = toBeLoadedOnT2->size(); + for( i = 0; i < instances; i++ ) { + sdaiInstance = loadedOnT1->find( toBeLoadedOnT2->at( i ) ); + if( sdaiInstance != NULL ) { + if( sdaiInstance != loadedOnT2->find( toBeLoadedOnT2->at( i ) ) ) { + return false; + } + } + } + + return true; +} + +//checks thread safety of loadInstance. +void checkLazyLoadingSafety( char * fileName ) { + + instanceRefs instancesToBeLoadedFwd, instancesToBeLoadedRev; + instanceRefs * toBeLoadedOnT1, * toBeLoadedOnT2; + instancesLoaded_t loadedOnT1, loadedOnT2; + + lazyInstMgr * mgr = new lazyInstMgr; + mgr->initRegistry( SchemaInit ); + mgr->openFile( fileName ); + + std::cout << "Checking thread safety in Lazy Loading..."; + + prepareRealRefs( mgr->getFwdRefs(), instancesToBeLoadedFwd ); + prepareRealRefs( mgr->getRevRefs(), instancesToBeLoadedRev ); + + bool intraThreadSuccess[2] = { true, true }; + bool interThreadSuccess = true; + const int iterations = 50; + for( int i = 0; i < 2 * iterations; i++ ) { + // First set iterations both threads will try to load from same list. + toBeLoadedOnT1 = &instancesToBeLoadedFwd; + toBeLoadedOnT2 = i < iterations ? &instancesToBeLoadedFwd : &instancesToBeLoadedRev; + + std::thread first( loadInstancesFromList, mgr, toBeLoadedOnT1, &loadedOnT1, &intraThreadSuccess[0] ); + std::thread second( loadInstancesFromList, mgr, toBeLoadedOnT2, &loadedOnT2, &intraThreadSuccess[1] ); + + first.join(); + second.join(); + + interThreadSuccess &= compareLoadedInstances( toBeLoadedOnT1, &loadedOnT1, toBeLoadedOnT2, &loadedOnT2 ); + mgr->unloadAllInstances(); + + loadedOnT1.clear(); + loadedOnT2.clear(); + } + + if( intraThreadSuccess[0] && intraThreadSuccess[1] && interThreadSuccess ) { + std::cout << "..PASS!" << std::endl; + } else { + std::cout << "...FAIL!" << std::endl; + + if( !intraThreadSuccess[0] ) { + std::cout << "\tThread 0: Difference in instances loaded within 1st and 2nd iterations" << std::endl; + } + + if( !intraThreadSuccess[1] ) { + std::cout << "\tThread 1: Difference in instances loaded within 1st and 2nd iterations" << std::endl; + } + + if( !interThreadSuccess ) { + std::cout << "\tDifference in instances loaded by the 2 threads" << std::endl; + } + } + std::cout << std::endl; delete mgr; } @@ -188,5 +302,7 @@ int main( int argc, char ** argv ) { checkRevRefsSafety( argv[1] ); checkTypeInstancesSafety( argv[1] ); + + checkLazyLoadingSafety( argv[1] ); } From 80d021e4cbef6f0dd1ceb452317adfc481d8024e Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 28 May 2014 20:49:58 +0530 Subject: [PATCH 018/111] Added thread safe loadInstanceSafely( instanceID ) It passes the test added earlier --- src/cllazyfile/lazyInstMgr.cc | 10 ++++++++++ src/cllazyfile/lazyInstMgr.h | 4 ++++ src/cllazyfile/lazy_thread_safety_test.cc | 4 ++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/cllazyfile/lazyInstMgr.cc b/src/cllazyfile/lazyInstMgr.cc index 352c0e4f7..a1e75c516 100644 --- a/src/cllazyfile/lazyInstMgr.cc +++ b/src/cllazyfile/lazyInstMgr.cc @@ -194,6 +194,16 @@ unsigned int lazyInstMgr::countInstancesSafely( std::string type ) { return v->size(); } +SDAI_Application_instance * lazyInstMgr::loadInstanceSafely( instanceID id ) { + assert( _mainRegistry && "Main registry has not been initialized. Do so with initRegistry() or setRegistry()." ); + //TODO: Locking can be made finer (2 seperate locks?) + loadInstanceMtx.lock(); + SDAI_Application_instance * sdaiInst = loadInstance( id ); + loadInstanceMtx.unlock(); + + return sdaiInst; +} + instanceSet * lazyInstMgr::instanceDependenciesSafely( instanceID id ) { return instanceDependenciesHelper( id, getFwdRefsSafely() ); } diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index 888399c89..a5d69ef22 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -71,6 +71,7 @@ class lazyInstMgr { std::mutex fwdRefsMtx; std::mutex revRefsMtx; std::mutex instanceTypesMtx; + std::mutex loadInstanceMtx; #endif //HAVE_STD_THREAD public: @@ -178,6 +179,9 @@ class lazyInstMgr { /// thread safe counterpart of countInstances() unsigned int countInstancesSafely( std::string type ); + //Thread safe counterpart of loadInstance( instanceID ) + SDAI_Application_instance * loadInstanceSafely( instanceID id ); + //Thread safe counterpart of instanceDependencies( instanceID ) instanceSet * instanceDependenciesSafely( instanceID id ); #endif //HAVE_STD_THREAD diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index 6c5286ace..6150a495d 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -188,13 +188,13 @@ void loadInstancesFromList( lazyInstMgr * mgr, instanceRefs * _refs, instancesLo int i; // Initial insertion into myInstances for( i = 0; i < instances; i++ ) { - sdaiInstance = mgr->loadInstance( _refs->at( i ) ); + sdaiInstance = mgr->loadInstanceSafely( _refs->at( i ) ); myInstances->insert( _refs->at( i ), sdaiInstance ); } // For each instance comparing the new pointer with the original pointer for( i = 0; i < instances; i++ ) { - sdaiInstance = mgr->loadInstance( _refs->at( i ) ); + sdaiInstance = mgr->loadInstanceSafely( _refs->at( i ) ); if( myInstances->find( _refs->at( i ) ) != sdaiInstance ) { //the old value has been overwritten. An object lazy-loaded twice. Not Good!!! From 21aa179953ad0ca5200648457da36f98bff937bf Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 28 May 2014 20:54:45 +0530 Subject: [PATCH 019/111] Added test checking thread safety of getSTEPentity() The test was created by modifying the test for checking thread safety of loadInstance. The test failed due to a abort from lazy parser --- src/cllazyfile/lazy_thread_safety_test.cc | 32 +++++++++++++++++------ 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index 6150a495d..232b6e904 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -182,19 +182,29 @@ void checkTypeInstancesSafety( char * fileName ) { } /// load instances found in _refs into the instancesLoaded. After doing this once, it iterates over the _refs and reports any changes in loaded value. -void loadInstancesFromList( lazyInstMgr * mgr, instanceRefs * _refs, instancesLoaded_t * myInstances, bool * success) { +/// Either directly calls loadInstance or uses an adapter, (determined by the value of useAdapter) +void loadInstancesFromList( lazyInstMgr * mgr, instanceRefs * _refs, instancesLoaded_t * myInstances, bool useAdapter, bool * success) { const int instances = _refs->size(); SDAI_Application_instance * sdaiInstance; int i; // Initial insertion into myInstances for( i = 0; i < instances; i++ ) { - sdaiInstance = mgr->loadInstanceSafely( _refs->at( i ) ); + if( useAdapter ) { + sdaiInstance = mgr->getAdapter()->FindFileId( _refs->at( i ) )->GetSTEPentity(); + } else { + sdaiInstance = mgr->loadInstanceSafely( _refs->at( i ) ); + } + myInstances->insert( _refs->at( i ), sdaiInstance ); } // For each instance comparing the new pointer with the original pointer for( i = 0; i < instances; i++ ) { - sdaiInstance = mgr->loadInstanceSafely( _refs->at( i ) ); + if( useAdapter ) { + sdaiInstance = mgr->getAdapter()->FindFileId( _refs->at( i ) )->GetSTEPentity(); + } else { + sdaiInstance = mgr->loadInstanceSafely( _refs->at( i ) ); + } if( myInstances->find( _refs->at( i ) ) != sdaiInstance ) { //the old value has been overwritten. An object lazy-loaded twice. Not Good!!! @@ -232,8 +242,8 @@ bool compareLoadedInstances( instanceRefs * toBeLoadedOnT1, instancesLoaded_t * return true; } -//checks thread safety of loadInstance. -void checkLazyLoadingSafety( char * fileName ) { +//checks thread safety of loadInstance. (Also of instMgrAdapter if useAdapter is TRUE) +void checkLazyLoadingSafety( char * fileName, bool useAdapter=false ) { instanceRefs instancesToBeLoadedFwd, instancesToBeLoadedRev; instanceRefs * toBeLoadedOnT1, * toBeLoadedOnT2; @@ -243,7 +253,7 @@ void checkLazyLoadingSafety( char * fileName ) { mgr->initRegistry( SchemaInit ); mgr->openFile( fileName ); - std::cout << "Checking thread safety in Lazy Loading..."; + std::cout << "Checking thread safety in Lazy Loading ("<< ( useAdapter ? "with" : "without" ) << " Adapter)..."; prepareRealRefs( mgr->getFwdRefs(), instancesToBeLoadedFwd ); prepareRealRefs( mgr->getRevRefs(), instancesToBeLoadedRev ); @@ -256,8 +266,8 @@ void checkLazyLoadingSafety( char * fileName ) { toBeLoadedOnT1 = &instancesToBeLoadedFwd; toBeLoadedOnT2 = i < iterations ? &instancesToBeLoadedFwd : &instancesToBeLoadedRev; - std::thread first( loadInstancesFromList, mgr, toBeLoadedOnT1, &loadedOnT1, &intraThreadSuccess[0] ); - std::thread second( loadInstancesFromList, mgr, toBeLoadedOnT2, &loadedOnT2, &intraThreadSuccess[1] ); + std::thread first( loadInstancesFromList, mgr, toBeLoadedOnT1, &loadedOnT1, useAdapter, &intraThreadSuccess[0] ); + std::thread second( loadInstancesFromList, mgr, toBeLoadedOnT2, &loadedOnT2, useAdapter, &intraThreadSuccess[1] ); first.join(); second.join(); @@ -291,6 +301,11 @@ void checkLazyLoadingSafety( char * fileName ) { delete mgr; } +//checks thread safety of lazyloading along with that of instMgrAdapter +void checkLazyLoadingSafetyWithAdapter( char * fileName ) { + checkLazyLoadingSafety( fileName, true ); +} + /// These tests were run on stepcode/data/cd209/ATS1-out.stp (Bigger files may take a longer time) int main( int argc, char ** argv ) { if( argc != 2 ) { @@ -304,5 +319,6 @@ int main( int argc, char ** argv ) { checkTypeInstancesSafety( argv[1] ); checkLazyLoadingSafety( argv[1] ); + checkLazyLoadingSafetyWithAdapter( argv[1] ); } From 343c9c54e2c5a1a811901dcb7d95dfd89935ed03 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 28 May 2014 21:02:04 +0530 Subject: [PATCH 020/111] Added FindFileIdSafely and GetSTEPentitySafely functions A new typedef in lazyTypes had to be introduced mapping threadId to a pointer to a mgrNodeHelper instance. The test for thread safety was passed by the code. --- src/cllazyfile/instMgrHelper.h | 72 ++++++++++++++++++++++- src/cllazyfile/lazyTypes.h | 14 +++++ src/cllazyfile/lazy_thread_safety_test.cc | 4 +- 3 files changed, 86 insertions(+), 4 deletions(-) diff --git a/src/cllazyfile/instMgrHelper.h b/src/cllazyfile/instMgrHelper.h index e97a485ca..05e86e8dc 100644 --- a/src/cllazyfile/instMgrHelper.h +++ b/src/cllazyfile/instMgrHelper.h @@ -3,6 +3,13 @@ #include #include +#include + +#ifdef HAVE_STD_THREAD +# include +# include +#endif //HAVE_STD_THREAD + /** * \file instMgrHelper.h helper classes for the lazyInstMgr. Allows use of SDAI_Application_instance class @@ -30,6 +37,14 @@ class mgrNodeHelper: protected MgrNode { // unsigned int c = _lim->countDataSections(); return _lim->loadInstance( _id ); } + +#ifdef HAVE_STD_THREAD + ///Thread safe counterpart of GetSTEPentity() + inline SDAI_Application_instance * GetSTEPentitySafely() { + return _lim->loadInstanceSafely( _id ); + } +#endif //HAVE_STD_THREAD + }; @@ -42,14 +57,67 @@ class mgrNodeHelper: protected MgrNode { class instMgrAdapter: public InstMgr { protected: - mgrNodeHelper _mn; + mgrNodeHelper _mn; //Used in single threaded operations + +#ifdef HAVE_STD_THREAD + lazyInstMgr * _lim; //Used in multi threaded operations + //map between threadID and the thread's local copy of mgrNodeHelper. Each thread has zero or one copy + //of mgrNodeHelper assigned to it. This _map holds the pointer to that mgrNodeHelper. + idNodeMap_t _map; + std::mutex _mapMtx; +#endif //HAVE_STD_THREAD + public: - instMgrAdapter( lazyInstMgr * lim ): InstMgr( 0 ), _mn( lim ) {} + instMgrAdapter( lazyInstMgr * lim ): InstMgr( 0 ), _mn( lim ) { +#ifdef HAVE_STD_THREAD + _lim = lim; + _map.clear(); +#endif //HAVE_STD_THREAD + } + +#ifdef HAVE_STD_THREAD + //In case of multiple threads an explicit destructor is needed to free each threads mgrNodeHelper copy + ~instMgrAdapter() { + if( _map.empty() ) { + return; + } + + for( idNodeMap_t::iterator it = _map.begin(); it != _map.end(); it++ ) { + delete it->second; + } + } +#endif //HAVE_STD_THREAD inline mgrNodeHelper * FindFileId( int fileId ) { _mn.setInstance( fileId ); return &_mn; } + + +#ifdef HAVE_STD_THREAD + ///Thread-safe counterpart of FindFileId( fileId ). It protects the state of mgrNodeHelper. + inline mgrNodeHelper * FindFileIdSafely( int fileId ) { + mgrNodeHelper * _myMN; + std::thread::id tid = std::this_thread::get_id(); + + _mapMtx.lock(); + idNodeMap_t::iterator it = _map.find( tid ); + + if( it == _map.end() ) { + //thread local copy yet not made. Hence create its copy. + _myMN = new mgrNodeHelper( _lim ); + _map.insert( idNodePair_t( tid, _myMN ) ); + } else { + //reuse the already existing copy. + _myMN = it->second; + } + + _mapMtx.unlock(); + + _myMN->setInstance( fileId ); + return _myMN; + } +#endif //HAVE_STD_THREAD }; diff --git a/src/cllazyfile/lazyTypes.h b/src/cllazyfile/lazyTypes.h index 313691a74..c62dae304 100644 --- a/src/cllazyfile/lazyTypes.h +++ b/src/cllazyfile/lazyTypes.h @@ -4,8 +4,13 @@ #include #include #include +#include #include +#ifdef HAVE_STD_THREAD +# include +#endif //HAVE_STD_THREAD + #include "judyLArray.h" #include "judySArray.h" #include "judyL2Array.h" @@ -14,6 +19,7 @@ class SDAI_Application_instance; class lazyDataSectionReader; class lazyFileReader; +class mgrNodeHelper; enum fileTypeEnum { Part21, Part28 }; // enum loadingEnum { immediate, lazy }; @@ -79,6 +85,14 @@ typedef std::vector< lazyDataSectionReader * > dataSectionReaderVec_t; // files typedef std::vector< lazyFileReader * > lazyFileReaderVec_t; +#ifdef HAVE_STD_THREAD +//map thread id to mgrNodeHelper. Each thread will have only one mgrNodeHelper value. +typedef std::map< std::thread::id, mgrNodeHelper * > idNodeMap_t; + +//thread id - mgrNodeHelper pointer pair to be used while using the above map +typedef std::pair< std::thread::id, mgrNodeHelper * > idNodePair_t; +#endif //HAVE_STD_THREAD + // type for performing actions on multiple instances // NOTE not useful? typedef std::vector< lazyInstance > lazyInstanceVec_t; diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index 232b6e904..8ae14c126 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -190,7 +190,7 @@ void loadInstancesFromList( lazyInstMgr * mgr, instanceRefs * _refs, instancesLo // Initial insertion into myInstances for( i = 0; i < instances; i++ ) { if( useAdapter ) { - sdaiInstance = mgr->getAdapter()->FindFileId( _refs->at( i ) )->GetSTEPentity(); + sdaiInstance = mgr->getAdapter()->FindFileIdSafely( _refs->at( i ) )->GetSTEPentitySafely(); } else { sdaiInstance = mgr->loadInstanceSafely( _refs->at( i ) ); } @@ -201,7 +201,7 @@ void loadInstancesFromList( lazyInstMgr * mgr, instanceRefs * _refs, instancesLo // For each instance comparing the new pointer with the original pointer for( i = 0; i < instances; i++ ) { if( useAdapter ) { - sdaiInstance = mgr->getAdapter()->FindFileId( _refs->at( i ) )->GetSTEPentity(); + sdaiInstance = mgr->getAdapter()->FindFileIdSafely( _refs->at( i ) )->GetSTEPentitySafely(); } else { sdaiInstance = mgr->loadInstanceSafely( _refs->at( i ) ); } From b865666b557e83115df9ffa65539a8d8ebe715e1 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 2 Jun 2014 22:01:25 +0530 Subject: [PATCH 021/111] Added test for opening multiple files in parallel The test fails with a string error --- src/cllazyfile/lazyInstMgr.h | 5 + src/cllazyfile/lazy_thread_safety_test.cc | 252 +++++++++++++++++++++- 2 files changed, 254 insertions(+), 3 deletions(-) diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index a5d69ef22..0a984e5b5 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -192,6 +192,11 @@ class lazyInstMgr { _instancesLoaded.clear(); } + // (For testing purpose, not thread safe) + instanceStreamPos_t * getInstanceStreamPos() { + return &_instanceStreamPos; + } + // TODO implement these /* * the opposite of instanceDependencies() - all instances that are *not* dependencies of one particular instance same as above, but with list of instances */ diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index 8ae14c126..6aebbb974 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -4,6 +4,7 @@ #include "instMgrHelper.h" #include "schema.h" +#include #ifdef HAVE_STD_THREAD # include @@ -25,6 +26,21 @@ void prepareRealRefs ( instanceRefs_t * _refs, instanceRefs &realRefs ) { realRefs.push_back( last ); } +/// It copies the keys of the _refs judy structure provided to it into the vector realRefs +void prepareRealRefsFromStreamPos ( instanceStreamPos_t * _spos, instanceRefs &realRefs ) { + + instanceID last = _spos->end().key; + instanceID current = _spos->begin().key; + + while( current != last ) { + realRefs.push_back( current ); + current = _spos->next().key; + } + + realRefs.push_back( last ); +} + + /// Used by an individual thread to iterate over the keys of the _fwdRefs / _revRefs multiple times. For each iteration it expects the order of the keys to be the same as dictated by realRefs. void iterateOverRefs ( lazyInstMgr *mgr, instanceRefs &realRefs, bool forward, bool * success ) { const int iterations = 1000; @@ -306,10 +322,238 @@ void checkLazyLoadingSafetyWithAdapter( char * fileName ) { checkLazyLoadingSafety( fileName, true ); } -/// These tests were run on stepcode/data/cd209/ATS1-out.stp (Bigger files may take a longer time) +/// enum elements represent the status used checking thread safety of openFile +enum lazyInstMgrStatus { + FWD_REFS, + REV_REFS, + TYPES, + TOTAL_COUNT, + COUNT_DATA_SECTIONS, + LONGEST_TYPE, + STREAM_POS, + OK +}; + +std::string getLazyInstMgrStatusString( lazyInstMgrStatus lIMStatus ) { + switch( lIMStatus ) { + case FWD_REFS: return "FWD_REFS"; + case REV_REFS: return "REV_REFS"; + case TYPES: return "TYPES"; + case TOTAL_COUNT: return "TOTAL_COUNT"; + case COUNT_DATA_SECTIONS: return "COUNT_DATA_SECTIONS"; + case LONGEST_TYPE: return "LONGEST_TYPE"; + case STREAM_POS: return "STREAM_POS"; + case OK: return "OK"; + default: return "Unknown Type"; + } +} + +/// compares the given instanceRefs_t. +bool compareRefs( instanceRefs_t * _refs1, instanceRefs_t * _refs2 ) { + instanceRefs refs1, refs2; + prepareRealRefs( _refs1, refs1 ); + prepareRealRefs( _refs2, refs2 ); + + //both vectors should have same number of elements + if( refs1.size() != refs2.size() ) { + return false; + } + + for( size_t i = 0; i < refs1.size(); i++ ) { + const instanceRefs * deps1 = _refs1->find( refs1[i] ); + const instanceRefs * deps2 = _refs2->find( refs1[i] ); + + //Just compare the size of both (value) vectors is sufficient + if( deps2 == NULL || deps1->size() != deps2->size() ) { + return false; + } + } + + return true; +} + +/// compares the given instance vectors. Returns true if both have same elements (irrespective of their order) +bool compareInstanceRefs( const instanceRefs * refs1, const instanceRefs * refs2 ) { + if( refs1 == NULL ) { + return ( refs2 == NULL ) || ( refs2->size() == 0 ); + } + + if( refs2 == NULL ) { + return ( refs1 == NULL ) || ( refs1->size() == 0 ); + } + + if( refs1->size() != refs2->size() ) { + return false; + } + + for( size_t i = 0; i < refs1->size(); i++ ) + { + if( std::find( refs2->begin(), refs2->end(), refs1->at( i ) ) == refs2->end() ) { + return false; + } + } + + return true; +} + +/// compares _instanceTypes data structure of both managers. +bool compareTypes( lazyInstMgr * mgr1, lazyInstMgr * mgr2 ) { + int i, types = commonTypes.size(); + for( i = 0; i < types; i++ ) { + const instanceRefs * refs1 = mgr1->getInstances( commonTypes[i] ); + const instanceRefs * refs2 = mgr2->getInstances( commonTypes[i] ); + if( !compareInstanceRefs( refs1, refs2 ) ) { + return false; + } + } + + return true; +} + +/// compares the given positionAndSection vectors. Returns true if both have same elements (irrespective of their order) +bool comparePosVectors( const std::vector< positionAndSection > * pos1, const std::vector< positionAndSection > * pos2 ) { + if( pos1->size() != pos2->size() ) { + return false; + } + + unsigned i, j; + for( i = 0; i < pos1->size(); i++ ) { + bool result = false; + for( j = 0; j < pos2->size(); j++ ) { + positionAndSection ps1, ps2; + ps1 = pos1->at( i ); + ps2 = pos2->at( j ); + + //only checking the offset as the sectionID may be different + if( ( ps1 & 0xFFFFFFFFFFFF ) == ( ps2 & 0xFFFFFFFFFFFF ) ) { + result = true; + break; + } + } + + if( !result ) { + return false; + } + } + + return true; +} + +/// For every instance compares its corresponding stream position vector in both lazyInstMgr. Returns false in case of any disprenency +bool compareStreamPos( lazyInstMgr * mgr1, lazyInstMgr * mgr2 ) { + + instanceRefs refs1, refs2; + instanceStreamPos_t * _pos1 = mgr1->getInstanceStreamPos(); + instanceStreamPos_t * _pos2 = mgr2->getInstanceStreamPos(); + + prepareRealRefsFromStreamPos( _pos1, refs1 ); + prepareRealRefsFromStreamPos( _pos2, refs2 ); + + // number of instances in both managers must be equal + if( refs1.size() != refs2.size() ) { + return false; + } + + const std::vector< positionAndSection > * pos1, * pos2; + + unsigned int i; + for( i = 0; i < refs1.size(); i++ ) { + pos1 = _pos1->find( refs1[i] ); + pos2 = _pos2->find( refs1[i] ); + //checking pos1 and pos2 for similarity + if( !comparePosVectors( pos1, pos2 ) ) { + return false; + } + } + + return true; +} + +/// compares various data structures of both lazyInstMgr's and returns OK if both are similar, else returns the point of difference. +lazyInstMgrStatus compareLazyInstMgr( lazyInstMgr * mgr1, lazyInstMgr * mgr2 ) { + + if( !compareRefs( mgr1->getFwdRefs(), mgr2->getFwdRefs() ) ) { + return FWD_REFS; + } + + if( !compareRefs( mgr1->getRevRefs(), mgr2->getRevRefs() ) ) { + return REV_REFS; + } + + // compares getType and getNumTypes + if( !compareTypes( mgr1, mgr2 ) ) { + return TYPES; + } + + if( mgr1->totalInstanceCount() != mgr2->totalInstanceCount() ) { + return TOTAL_COUNT; + } + + if( mgr1->countDataSections() != mgr2->countDataSections() ) { + return COUNT_DATA_SECTIONS; + } + + if( mgr1->getLongestTypeName().length() != mgr2->getLongestTypeName().length() ) { + return LONGEST_TYPE; + } + + if( !compareStreamPos( mgr1, mgr2 ) ) { + return STREAM_POS; + } + + return OK; +} + +/// used by different threads to open a step file +void openFile( lazyInstMgr * mgr, char * fileName ) { + mgr->openFile( fileName ); +} + +/// checks the thread safety by opening multiple files in parallel +void checkOpenFileSafety( char * file1, char * file2 ) { + lazyInstMgr * e_mgr = new lazyInstMgr; //expected lazyInstMgr + + std::cout << "Checking thread safety while opening multiple files in parallel..."; + + e_mgr->openFile( file1 ); + e_mgr->openFile( file2 ); + + lazyInstMgrStatus compareResult = OK; + const int iterations = 100; + for( int i = 0; i < iterations; i++ ) { + lazyInstMgr * a_mgr = new lazyInstMgr; //actual lazyInstMgr + + std::thread first( openFile, a_mgr, file1 ); + std::thread second( openFile, a_mgr, file2 ); + + first.join(); + second.join(); + + compareResult = compareLazyInstMgr( e_mgr, a_mgr ); + + delete a_mgr; + + if( compareResult != OK ) { + break; + } + } + + if( compareResult == OK ) { + std::cout << "..PASS!" << std::endl; + } else { + std::cout << "...FAIL!" << std::endl; + std::cout << "\tDisperency in " << getLazyInstMgrStatusString( compareResult ) << " structure" << std::endl; + } + + std::cout << std::endl; + delete e_mgr; +} + + +/// These tests were run on stepcode/data/cd209/ATS1-out.stp && stepcode/data/cd209/ATS10-out.stp (Bigger files may take a longer time) int main( int argc, char ** argv ) { - if( argc != 2 ) { - std::cerr << "Expected one argument, given " << argc - 1 << ". Exiting." << std::endl; + if( argc != 3 ) { + std::cerr << "Expected two argument, given " << argc - 1 << ". Exiting." << std::endl; exit( EXIT_FAILURE ); } @@ -320,5 +564,7 @@ int main( int argc, char ** argv ) { checkLazyLoadingSafety( argv[1] ); checkLazyLoadingSafetyWithAdapter( argv[1] ); + + checkOpenFileSafety( argv[1], argv[2] ); } From 22a6b9014fe7bf66f6cc1700a117053b33c627e3 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 2 Jun 2014 22:08:33 +0530 Subject: [PATCH 022/111] Added a compatible wrapper for mutex lock / unlock This wrapper will invoke the corresponding lock or unlock function std::thread is supported or a dummy function if not. Hence the wrapper can be easily be used by functions irrespective of whether std::mutex is supported or not. --- src/cllazyfile/lazyInstMgr.h | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index 0a984e5b5..39f6add22 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -68,10 +68,10 @@ class lazyInstMgr { #ifdef HAVE_STD_THREAD /** mutexes for mutual exclusion */ - std::mutex fwdRefsMtx; - std::mutex revRefsMtx; - std::mutex instanceTypesMtx; - std::mutex loadInstanceMtx; + std::mutex fwdRefsMtx, revRefsMtx, instanceTypesMtx, loadInstanceMtx, instanceStreamPosMtx, dataSectionsMtx, filesMtx; +#else + /** Dummy variables **/ + int fwdRefsMtx, revRefsMtx, instanceTypesMtx, loadInstanceMtx, instanceStreamPosMtx, dataSectionsMtx, filesMtx; #endif //HAVE_STD_THREAD public: @@ -184,6 +184,24 @@ class lazyInstMgr { //Thread safe counterpart of instanceDependencies( instanceID ) instanceSet * instanceDependenciesSafely( instanceID id ); + + void mtxLock( std::mutex &mtx ) { + mtx.lock(); + } + + void mtxUnlock( std::mutex &mtx ) { + mtx.unlock(); + } +#else + //dummy counterpart of mtxLock + void mtxLock( int dummy ) { + ( void )dummy; + } + + //dummy counterpart of mtxUnlock + void mtxUnlock( int dummy ) { + ( void )dummy; + } #endif //HAVE_STD_THREAD //unloads all instances. (For testing purpose, not thread safe) From 0e2ab604e94acfa5f737d7b672b3f790525a86d1 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 2 Jun 2014 22:17:08 +0530 Subject: [PATCH 023/111] Removed static variable (string str) in sectionReader.cc The function sectionReader::getDelimitedKeyword( delims ) was changed to sectionReader::fillDelimitedKeyword( delims, string& ). This was done to make reading from the file stream thread safe. --- src/cllazyfile/lazyP21DataSectionReader.cc | 6 +++++- src/cllazyfile/p21HeaderSectionReader.cc | 4 +++- src/cllazyfile/sectionReader.cc | 13 +++++++------ src/cllazyfile/sectionReader.h | 2 +- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/cllazyfile/lazyP21DataSectionReader.cc b/src/cllazyfile/lazyP21DataSectionReader.cc index d88adb213..b03d064df 100644 --- a/src/cllazyfile/lazyP21DataSectionReader.cc +++ b/src/cllazyfile/lazyP21DataSectionReader.cc @@ -54,7 +54,11 @@ const namedLazyInstance lazyP21DataSectionReader::nextInstance() { skipWS(); i.loc.section = _sectionID; skipWS(); - i.name = getDelimitedKeyword( ";( /\\" ); + + std::string * keyword = new string(); + fillDelimitedKeyword( ";( /\\", *keyword ); + i.name = keyword->c_str(); + if( _file.good() ) { end = seekInstanceEnd( & i.refs ); } diff --git a/src/cllazyfile/p21HeaderSectionReader.cc b/src/cllazyfile/p21HeaderSectionReader.cc index bcb78ac83..a1d472166 100644 --- a/src/cllazyfile/p21HeaderSectionReader.cc +++ b/src/cllazyfile/p21HeaderSectionReader.cc @@ -39,7 +39,9 @@ const namedLazyInstance p21HeaderSectionReader::nextInstance() { if( i.loc.begin <= 0 ) { i.name = 0; } else { - i.name = getDelimitedKeyword( ";( /\\" ); + std::string * keyword = new string(); + fillDelimitedKeyword( ";( /\\", *keyword ); + i.name = keyword->c_str(); if( 0 == strcmp( "FILE_DESCRIPTION", i.name ) ) { i.loc.instance = 1; diff --git a/src/cllazyfile/sectionReader.cc b/src/cllazyfile/sectionReader.cc index 4ba9a8ab9..57badcbf1 100644 --- a/src/cllazyfile/sectionReader.cc +++ b/src/cllazyfile/sectionReader.cc @@ -82,8 +82,7 @@ std::streampos sectionReader::findNormalString( const std::string & str, bool se //NOTE different behavior than const char * GetKeyword( istream & in, const char * delims, ErrorDescriptor & err ) in read_func.cc -const char * sectionReader::getDelimitedKeyword( const char * delimiters ) { - static std::string str; +void sectionReader::fillDelimitedKeyword( const char * delimiters, std::string &str ) { char c, firstSpaceDelimeter; str.clear(); str.reserve( 100 ); @@ -113,7 +112,6 @@ const char * sectionReader::getDelimitedKeyword( const char * delimiters ) { std::cerr << SC_CURRENT_FUNCTION << ": missing delimiter. Found " << c << ", expected one of " << delimiters << " at end of keyword " << str << ". File offset: " << _file.tellg() << std::endl; abort(); } - return str.c_str(); } /// search forward in the file for the end of the instance. Start position should @@ -257,7 +255,7 @@ SDAI_Application_instance * sectionReader::getRealInstance( const Registry * reg const std::string & typeName, const std::string & schName, bool header ) { char c; const char * tName = 0, * sName = 0; //these are necessary since typeName and schName are const - std::string comment; + std::string comment, keyword; Severity sev; SDAI_Application_instance * inst = 0; @@ -301,7 +299,8 @@ SDAI_Application_instance * sectionReader::getRealInstance( const Registry * reg break; default: if( ( !header ) && ( typeName.size() == 0 ) ) { - tName = getDelimitedKeyword( ";( /\\" ); + fillDelimitedKeyword( ";( /\\", keyword ); + tName = keyword.c_str(); } inst = reg->ObjCreate( tName, sName ); break; @@ -327,7 +326,9 @@ STEPcomplex * sectionReader::CreateSubSuperInstance( const Registry * reg, insta std::vector typeNames; _file.get(); //move past the first '(' while( _file.good() && ( _file.peek() != ')' ) ) { - typeNames.push_back( new std::string( getDelimitedKeyword( ";( /\\" ) ) ); + std::string keyword; + fillDelimitedKeyword( ";( /\\", keyword ); + typeNames.push_back( new std::string( keyword ) ); if( typeNames.back()->empty() ) { delete typeNames.back(); typeNames.pop_back(); diff --git a/src/cllazyfile/sectionReader.h b/src/cllazyfile/sectionReader.h index 8620c70c4..a96bb0946 100644 --- a/src/cllazyfile/sectionReader.h +++ b/src/cllazyfile/sectionReader.h @@ -41,7 +41,7 @@ class SC_LAZYFILE_EXPORT sectionReader { /** Get a keyword ending with one of delimiters. */ - const char * getDelimitedKeyword( const char * delimiters ); + void fillDelimitedKeyword( const char * delimiters, std::string &keyword ); /** Seek to the end of the current instance */ std::streampos seekInstanceEnd( instanceRefs ** refs ); From 170028848991622ed8fdcdb9d246fdc5984ac5e3 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 2 Jun 2014 22:23:28 +0530 Subject: [PATCH 024/111] Removed static variable nextFreeInstance This was done my making the static variable an object variable. Hence now it is possible that different threads give header instances present in different file, same instanceID --- src/cllazyfile/p21HeaderSectionReader.cc | 2 +- src/cllazyfile/p21HeaderSectionReader.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cllazyfile/p21HeaderSectionReader.cc b/src/cllazyfile/p21HeaderSectionReader.cc index a1d472166..236b11e04 100644 --- a/src/cllazyfile/p21HeaderSectionReader.cc +++ b/src/cllazyfile/p21HeaderSectionReader.cc @@ -20,6 +20,7 @@ p21HeaderSectionReader::p21HeaderSectionReader( lazyFileReader * parent, std::if findSectionEnd(); _file.seekg( _sectionStart ); namedLazyInstance nl; + nextFreeInstance = 4; // 1-3 are reserved per 10303-21 while( nl = nextInstance(), ( nl.loc.begin > 0 ) ) { std::streampos pos = _file.tellg(); _headerInstances->insert( nl.loc.instance, getRealInstance( _lazyFile->getInstMgr()->getHeaderRegistry(), nl.loc.begin, nl.loc.instance, nl.name, "", true ) ); @@ -31,7 +32,6 @@ p21HeaderSectionReader::p21HeaderSectionReader( lazyFileReader * parent, std::if // part of readdata1 const namedLazyInstance p21HeaderSectionReader::nextInstance() { namedLazyInstance i; - static instanceID nextFreeInstance = 4; // 1-3 are reserved per 10303-21 i.loc.begin = _file.tellg(); i.loc.section = _sectionID; diff --git a/src/cllazyfile/p21HeaderSectionReader.h b/src/cllazyfile/p21HeaderSectionReader.h index b5ce04948..d034fcd4a 100644 --- a/src/cllazyfile/p21HeaderSectionReader.h +++ b/src/cllazyfile/p21HeaderSectionReader.h @@ -6,6 +6,8 @@ #include "sc_export.h" class SC_LAZYFILE_EXPORT p21HeaderSectionReader: public headerSectionReader { + protected: + instanceID nextFreeInstance; public: p21HeaderSectionReader( lazyFileReader * parent, std::ifstream & file, std::streampos start, sectionID sid ); void findSectionStart(); From 5558c7f0b1030958685e12ed5c397c93d707a9a2 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 2 Jun 2014 22:37:31 +0530 Subject: [PATCH 025/111] lazyInstMgr::registerDataSection semantics changed Keeping in mind the thread safety, registring a data section is now a two step process. In first step an entry is reserved, by filling it with a null value, and getting its index. In the second step the null value is replaced with the new value. The destructor has been changed keeping in mind that a _dataSection entry might also be a null. Destroying _instanceTypes data structure in the destructor --- src/cllazyfile/lazyFileReader.cc | 5 +++-- src/cllazyfile/lazyInstMgr.cc | 36 +++++++++++++++++++++++++++----- src/cllazyfile/lazyInstMgr.h | 7 ++++++- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/cllazyfile/lazyFileReader.cc b/src/cllazyfile/lazyFileReader.cc index b31a6dfd3..ea2e4ebfc 100644 --- a/src/cllazyfile/lazyFileReader.cc +++ b/src/cllazyfile/lazyFileReader.cc @@ -11,13 +11,14 @@ void lazyFileReader::initP21() { for( ;; ) { lazyDataSectionReader * r; - r = new lazyP21DataSectionReader( this, _file, _file.tellg(), _parent->countDataSections() ); + sectionID sid = _parent->reserveDataSection(); + r = new lazyP21DataSectionReader( this, _file, _file.tellg(), sid ); if( !r->success() ) { delete r; //last read attempt failed std::cerr << "Corrupted data section" << std::endl; break; } - _parent->registerDataSection( r ); + _parent->registerDataSection( r, sid ); //check for new data section (DATA) or end of file (END-ISO-10303-21;) while( isspace( _file.peek() ) && _file.good() ) { diff --git a/src/cllazyfile/lazyInstMgr.cc b/src/cllazyfile/lazyInstMgr.cc index a1e75c516..c3f72707e 100644 --- a/src/cllazyfile/lazyInstMgr.cc +++ b/src/cllazyfile/lazyInstMgr.cc @@ -22,19 +22,45 @@ lazyInstMgr::~lazyInstMgr() { //loop over files, sections, instances; delete header instances lazyFileReaderVec_t::iterator fit = _files.begin(); for( ; fit != _files.end(); ++fit ) { - delete *fit; + if( *fit ) { + delete *fit; + } } dataSectionReaderVec_t::iterator sit = _dataSections.begin(); for( ; sit != _dataSections.end(); ++sit ) { - delete *sit; + if( *sit ) { + delete *sit; + } } _instancesLoaded.clear(); _instanceStreamPos.clear(); + + void * last = _instanceTypes->end().key; + void * current = _instanceTypes->begin().key; + std::string str; + while( current != last ) { + str = (char *)current; + str.clear(); + current = _instanceTypes->next().key; + } + str.clear(); + + delete _instanceTypes; +} + +sectionID lazyInstMgr::reserveDataSection() { + mtxLock( dataSectionsMtx ); + sectionID sid = _dataSections.size(); + _dataSections.push_back( NULL ); + mtxUnlock( dataSectionsMtx ); + return sid; } -sectionID lazyInstMgr::registerDataSection( lazyDataSectionReader * sreader ) { - _dataSections.push_back( sreader ); - return _dataSections.size() - 1; +void lazyInstMgr::registerDataSection( lazyDataSectionReader * sreader, sectionID sid ) { + assert( _dataSections[sid] == NULL ); + mtxLock( dataSectionsMtx ); + _dataSections[sid] = sreader; + mtxUnlock( dataSectionsMtx ); } void lazyInstMgr::addLazyInstance( namedLazyInstance inst ) { diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index 39f6add22..fee872790 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -153,7 +153,12 @@ class lazyInstMgr { /// get the number of types of instances. unsigned long getNumTypes() const; - sectionID registerDataSection( lazyDataSectionReader * sreader ); + /// reserves a slot in _dataSections vector. Gives the slot a value null, and return the index value. + sectionID reserveDataSection(); + + /// updates _dataSections vector with the sreader value at the given index. + void registerDataSection( lazyDataSectionReader * sreader, sectionID sid ); + fileID registerLazyFile( lazyFileReader * freader ); ErrorDescriptor * getErrorDesc() { From b20c9860a3d579ef5f2c265684bfb0e6e3ee9ffe Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 2 Jun 2014 22:52:28 +0530 Subject: [PATCH 026/111] Added openFileSafely( fname ) functionality Plenty of mutexes were used for this purpose. Fine grain locking addInstance in function. The code passes the test for thread safety in opening multiple files. --- src/cllazyfile/lazyInstMgr.cc | 28 ++++++++++++++++++++++- src/cllazyfile/lazyInstMgr.h | 3 +++ src/cllazyfile/lazy_thread_safety_test.cc | 2 +- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/cllazyfile/lazyInstMgr.cc b/src/cllazyfile/lazyInstMgr.cc index c3f72707e..23f5cfd27 100644 --- a/src/cllazyfile/lazyInstMgr.cc +++ b/src/cllazyfile/lazyInstMgr.cc @@ -64,14 +64,18 @@ void lazyInstMgr::registerDataSection( lazyDataSectionReader * sreader, sectionI } void lazyInstMgr::addLazyInstance( namedLazyInstance inst ) { - _lazyInstanceCount++; assert( inst.loc.begin > 0 && inst.loc.instance > 0 && inst.loc.section >= 0 ); + + mtxLock( instanceTypesMtx ); + _lazyInstanceCount++; int len = strlen( inst.name ); if( len > _longestTypeNameLen ) { _longestTypeNameLen = len; _longestTypeName = inst.name; } _instanceTypes->insert( inst.name, inst.loc.instance ); + mtxUnlock( instanceTypesMtx ); + /* store 16 bits of section id and 48 of instance offset into one 64-bit int * TODO: check and warn if anything is lost (in calling code?) * does 32bit need anything special? @@ -79,16 +83,24 @@ void lazyInstMgr::addLazyInstance( namedLazyInstance inst ) { positionAndSection ps = inst.loc.section; ps <<= 48; ps |= ( inst.loc.begin & 0xFFFFFFFFFFFFULL ); + + mtxLock( instanceStreamPosMtx ); _instanceStreamPos.insert( inst.loc.instance, ps ); + mtxUnlock( instanceStreamPosMtx ); if( inst.refs ) { if( inst.refs->size() > 0 ) { //forward refs + mtxLock( fwdRefsMtx ); _fwdInstanceRefs.insert( inst.loc.instance, *inst.refs ); + mtxUnlock( fwdRefsMtx ); + instanceRefs::iterator it = inst.refs->begin(); for( ; it != inst.refs->end(); ++it ) { //reverse refs + mtxLock( revRefsMtx ); _revInstanceRefs.insert( *it, inst.loc.instance ); + mtxUnlock( revRefsMtx ); } } else { delete inst.refs; @@ -185,6 +197,20 @@ instanceSet * lazyInstMgr::instanceDependencies( instanceID id ) { } #ifdef HAVE_STD_THREAD + +void lazyInstMgr::openFileSafely( std::string fname ) { + filesMtx.lock(); + size_t size = _files.size(); + _files.push_back( NULL ); //place Holder + filesMtx.unlock(); + + lazyFileReader * fileReader = new lazyFileReader( fname, this, size ); + + filesMtx.lock(); + _files[size] = fileReader; + filesMtx.unlock(); +} + instanceRefs_t * lazyInstMgr::getFwdRefsSafely() { fwdRefsMtx.lock(); diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index fee872790..61f299c65 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -172,6 +172,9 @@ class lazyInstMgr { instanceSet * instanceDependenciesHelper( instanceID id, instanceRefs_t * _fwdRefs ); #ifdef HAVE_STD_THREAD + /// thread safe counterpart of openFile(); + void openFileSafely( std::string fname ); + /// thread safe counterpart of getFwdRefs() instanceRefs_t * getFwdRefsSafely(); diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index 6aebbb974..ba05c44a6 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -506,7 +506,7 @@ lazyInstMgrStatus compareLazyInstMgr( lazyInstMgr * mgr1, lazyInstMgr * mgr2 ) { /// used by different threads to open a step file void openFile( lazyInstMgr * mgr, char * fileName ) { - mgr->openFile( fileName ); + mgr->openFileSafely( fileName ); } /// checks the thread safety by opening multiple files in parallel From 313e99c7f3502f002fc850652a735bd558aef429 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 2 Jun 2014 23:03:01 +0530 Subject: [PATCH 027/111] Finer grain locking in loadInstance Also doing double checking in the thread safe version for better performance in case of many threads. --- src/cllazyfile/lazyInstMgr.cc | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/cllazyfile/lazyInstMgr.cc b/src/cllazyfile/lazyInstMgr.cc index 23f5cfd27..367548090 100644 --- a/src/cllazyfile/lazyInstMgr.cc +++ b/src/cllazyfile/lazyInstMgr.cc @@ -132,7 +132,13 @@ SDAI_Application_instance * lazyInstMgr::loadInstance( instanceID id ) { SDAI_Application_instance * inst = 0; positionAndSection ps; sectionID sid; + + mtxLock( instanceStreamPosMtx ); + + mtxLock( loadInstanceMtx ); inst = _instancesLoaded.find( id ); + mtxUnlock( loadInstanceMtx ); + instanceStreamPos_t::cvector * cv; if( !inst && 0 != ( cv = _instanceStreamPos.find( id ) ) ) { //FIXME _instanceStreamPos.find( id ) can return nonzero for nonexistent key?! @@ -153,14 +159,18 @@ SDAI_Application_instance * lazyInstMgr::loadInstance( instanceID id ) { break; } if( ( inst ) && ( inst != & NilSTEPentity ) ) { + mtxLock( loadInstanceMtx ); _instancesLoaded.insert( id, inst ); _loadedInstanceCount++; + mtxUnlock( loadInstanceMtx ); } else { std::cerr << "Error loading instance #" << id << "." << std::endl; } } else if( !inst ) { std::cerr << "Instance #" << id << " not found in any section." << std::endl; } + + mtxUnlock( instanceStreamPosMtx ); return inst; } @@ -248,10 +258,15 @@ unsigned int lazyInstMgr::countInstancesSafely( std::string type ) { SDAI_Application_instance * lazyInstMgr::loadInstanceSafely( instanceID id ) { assert( _mainRegistry && "Main registry has not been initialized. Do so with initRegistry() or setRegistry()." ); - //TODO: Locking can be made finer (2 seperate locks?) - loadInstanceMtx.lock(); - SDAI_Application_instance * sdaiInst = loadInstance( id ); - loadInstanceMtx.unlock(); + SDAI_Application_instance * sdaiInst; + + mtxLock( loadInstanceMtx ); + sdaiInst = _instancesLoaded.find( id ); + mtxUnlock( loadInstanceMtx ); + + if( !sdaiInst ) { + sdaiInst = loadInstance( id ); + } return sdaiInst; } From 0972caa57396bf826132a8c92e162bb7c6af31a0 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 8 Jun 2014 11:21:23 +0530 Subject: [PATCH 028/111] Function comments made to follow conventions --- src/cllazyfile/lazyInstMgr.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index 61f299c65..8e5e40e52 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -167,7 +167,7 @@ class lazyInstMgr { SDAI_Application_instance * loadInstance( instanceID id ); - //list all instances that one instance depends on (recursive) + /// lists all instances that one instance depends on (recursive) instanceSet * instanceDependencies( instanceID id ); instanceSet * instanceDependenciesHelper( instanceID id, instanceRefs_t * _fwdRefs ); @@ -187,10 +187,10 @@ class lazyInstMgr { /// thread safe counterpart of countInstances() unsigned int countInstancesSafely( std::string type ); - //Thread safe counterpart of loadInstance( instanceID ) + /// Thread safe counterpart of loadInstance( instanceID ) SDAI_Application_instance * loadInstanceSafely( instanceID id ); - //Thread safe counterpart of instanceDependencies( instanceID ) + /// Thread safe counterpart of instanceDependencies( instanceID ) instanceSet * instanceDependenciesSafely( instanceID id ); void mtxLock( std::mutex &mtx ) { @@ -201,12 +201,12 @@ class lazyInstMgr { mtx.unlock(); } #else - //dummy counterpart of mtxLock + /// dummy counterpart of mtxLock void mtxLock( int dummy ) { ( void )dummy; } - //dummy counterpart of mtxUnlock + /// dummy counterpart of mtxUnlock void mtxUnlock( int dummy ) { ( void )dummy; } From 7981d8835bb966b0d0ec3565d4c97fe88d458753 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 8 Jun 2014 11:23:09 +0530 Subject: [PATCH 029/111] Function comments --- src/cllazyfile/lazyInstMgr.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index 8e5e40e52..07d32ae12 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -212,13 +212,13 @@ class lazyInstMgr { } #endif //HAVE_STD_THREAD - //unloads all instances. (For testing purpose, not thread safe) + /// unloads all instances. (For testing purpose, not thread safe) void unloadAllInstances() { _loadedInstanceCount = 0; _instancesLoaded.clear(); } - // (For testing purpose, not thread safe) + /// (For testing purpose, not thread safe) instanceStreamPos_t * getInstanceStreamPos() { return &_instanceStreamPos; } From e67a5f51d1bb0b52a9c76d2e51b1486c9029a9a9 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 15 Jun 2014 13:32:17 +0530 Subject: [PATCH 030/111] Added sc_mutex.h to src/clutils It is wrapper to std::mutex. It does nothing if HAVE_STD_MUTEX is not defined. --- src/clutils/CMakeLists.txt | 7 ++++++- src/clutils/sc_mutex.h | 31 +++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/clutils/sc_mutex.h diff --git a/src/clutils/CMakeLists.txt b/src/clutils/CMakeLists.txt index 22506bf00..c020525cc 100644 --- a/src/clutils/CMakeLists.txt +++ b/src/clutils/CMakeLists.txt @@ -17,6 +17,7 @@ set(SC_CLUTILS_HDRS gennodelist.h sc_hash.h Str.h + sc_mutex.h ) include_directories( @@ -25,7 +26,11 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ) -SC_ADDLIB(steputils "${LIBSTEPUTILS_SRCS}" "base") +SC_ADDLIB(steputils "${LIBSTEPUTILS_SRCS};${SC_CLUTILS_HDRS}" "base") +if(HAVE_STD_THREAD) + list(APPEND CMAKE_CXX_FLAGS "-pthread -std=c++0x") + set_target_properties(steputils PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD" ) +endif(HAVE_STD_THREAD) if(MINGW OR MSVC OR BORLAND) target_link_libraries(steputils shlwapi.lib) diff --git a/src/clutils/sc_mutex.h b/src/clutils/sc_mutex.h new file mode 100644 index 000000000..75478e9f9 --- /dev/null +++ b/src/clutils/sc_mutex.h @@ -0,0 +1,31 @@ +#ifndef SC_MUTEX_H +#define SC_MUTEX_H + +#ifdef HAVE_STD_THREAD +# include +# include +#endif //HAVE_STD_THREAD +/* + This class is a wrapper to std::mutex. + It does nothing if HAVE_STD_MUTEX is not defined. +*/ +class sc_mutex { + protected: +#ifdef HAVE_STD_THREAD + std::mutex mtx; +#endif //HAVE_STD_THREAD + + public: + void lock() { +#ifdef HAVE_STD_THREAD + mtx.lock(); +#endif //HAVE_STD_THREAD + } + + void unlock() { +#ifdef HAVE_STD_THREAD + mtx.unlock(); +#endif //HAVE_STD_THREAD + } +}; +#endif //SC_MUTEX_H From 5cba5e6a8ad7c9dd6d1de4db25bc1feae0d5af96 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 15 Jun 2014 14:21:16 +0530 Subject: [PATCH 031/111] Added a test for checking thread safety in instmgr The test tries to insert and delete instances simultaneosly, sequentially and parallely and later compares there results for any disparity. --- src/clstepcore/CMakeLists.txt | 5 + src/clstepcore/InstMgr_thread_safety_test.cc | 215 +++++++++++++++++++ 2 files changed, 220 insertions(+) create mode 100644 src/clstepcore/InstMgr_thread_safety_test.cc diff --git a/src/clstepcore/CMakeLists.txt b/src/clstepcore/CMakeLists.txt index 57f6240cd..2be17881f 100644 --- a/src/clstepcore/CMakeLists.txt +++ b/src/clstepcore/CMakeLists.txt @@ -69,6 +69,11 @@ include_directories( ) SC_ADDLIB(stepcore "${LIBSTEPCORE_SRCS}" "steputils;stepdai;base") +if(HAVE_STD_THREAD) + SC_ADDEXEC(InstMgr_thread_safety_test "InstMgr_thread_safety_test.cc" "stepcore" ) + set_target_properties(InstMgr_thread_safety_test PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD") + target_link_libraries(InstMgr_thread_safety_test "pthread" ) +endif(HAVE_STD_THREAD) install(FILES ${SC_CLSTEPCORE_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/stepcode/clstepcore) diff --git a/src/clstepcore/InstMgr_thread_safety_test.cc b/src/clstepcore/InstMgr_thread_safety_test.cc new file mode 100644 index 000000000..5243a520e --- /dev/null +++ b/src/clstepcore/InstMgr_thread_safety_test.cc @@ -0,0 +1,215 @@ +#include "instmgr.h" +#include "ExpDict.h" +#include "sdaiApplication_instance.h" +#include + +#ifdef HAVE_STD_THREAD +# include +#else +# error Need std::thread for this test! +#endif + +const std::vector< std::string > dummyEDescNames { "A", "B", "C", "A", "B", "C", "D", "B", "A", "E", "C", "D", "B", "A", "E", "F", "F", "B", "C", "E", "F", "G", "C", "A", "G", "H", "I", "B", "A", "E", "F", "F", "C", "C", "E", "F" }; + +typedef std::vector< SDAI_Application_instance * > sdaiVec_t; + +/// Deletes non-null elements of sdaiVec +void deleteSdaiVec( sdaiVec_t &sdaiVec ) { + int i, size = sdaiVec.size(); + for( i = 0; i < size; i++ ) { + if( !sdaiVec[i]) { + delete sdaiVec[i]; + } + } +} + +void appendInstances( InstMgr * im, sdaiVec_t &sdaiVec, int offset, int stride, int limit ) { + SDAI_Application_instance * sai; + for( int i = offset; i < limit; i+=stride ) { + sai = new SDAI_Application_instance( i+1 ); + sai->eDesc = new EntityDescriptor( dummyEDescNames[i].c_str(), ( Schema * ) NULL, LTrue, LFalse ); + sdaiVec[i] = sai; + im->Append( sai, completeSE ); + } +} + +void deleteInstances( InstMgr * im, sdaiVec_t &sdaiVec, int offset, int stride, int limit ) { + for( int i = offset; i < limit; i+=stride ) { + im->Delete( sdaiVec[i] ); + sdaiVec[i] = 0; + } +} + +bool compareKeywordCount ( InstMgr * mgr1, InstMgr * mgr2 ) { + int i, size = dummyEDescNames.size(); + for( i = 0; i < size; i++ ) { + //some comparisions may be repeated. + const char * str = dummyEDescNames[i].c_str(); + if( mgr1->EntityKeywordCount( str ) != mgr2->EntityKeywordCount( str ) ) { + std::cout << std::endl << "\tEntityKeywordCount mistmatch for " << str << ": " << mgr1->MaxFileId() << " and " << mgr2->MaxFileId() << std::endl; + return false; + } + } + + return true; +} + +/// Checks for similarity in the two InstMgr +bool compareInstMgr( InstMgr * mgr1, InstMgr * mgr2 ) { + if( mgr1->MaxFileId() != mgr2->MaxFileId() ) { + std::cout << std::endl << "\tMaxFileId not same: " << mgr1->MaxFileId() << " and " << mgr2->MaxFileId() << std::endl; + return false; + } + + if( mgr1->InstanceCount() != mgr2->InstanceCount() ) { + std::cout << std::endl << "\tInstance count not same: " << mgr1->InstanceCount() << " and " << mgr2->InstanceCount() << std::endl; + return false; + } + + if( !compareKeywordCount( mgr1, mgr2 ) ) { + return false; + } + + return true; +} + +/// Performs addition of different instances to the same InstMgr simultaneosly. +void checkInstMgrAppendOnlyThreadSafety() { + InstMgr * imExpected = new InstMgr( 0 ); + int size = dummyEDescNames.size(); + + //simulate the work done by two threads + sdaiVec_t sdaiVecOld( size ); + appendInstances( imExpected, sdaiVecOld, 0, 2, size ); + appendInstances( imExpected, sdaiVecOld, 1, 2, size ); + std::cout << "Checking thread safety of InstMgr in Append Operation..." ; + + int i, iterations = 100; + for( i = 0 ; i < iterations; i++ ) { + InstMgr * imActual = new InstMgr( 0 ); + sdaiVec_t sdaiVecNew( size ); + + std::thread first( appendInstances, imActual, sdaiVecNew, 0, 2, size ); + std::thread second( appendInstances, imActual, sdaiVecNew, 1, 2, size ); + + first.join(); + second.join(); + + bool success = compareInstMgr( imExpected, imActual ); + delete imActual; + deleteSdaiVec( sdaiVecNew ); + + if( !success ) { + break; + } + } + + if( i == iterations ) { + std::cout << "...PASS!" << std::endl; + } else { + std::cout << "...FAIL!" << std::endl; + } + + std::cout << std::endl; + + delete imExpected; + deleteSdaiVec( sdaiVecOld ); +} + +/// Performs deletion of different instances to the same InstMgr simultaneosly. +void checkInstMgrDeleteOnlyThreadSafety() { + InstMgr * imExpected = new InstMgr( 0 ); + int size = dummyEDescNames.size(); + //simulate the work done by two threads + + sdaiVec_t sdaiVecOld( size ); + appendInstances( imExpected, sdaiVecOld, 0, 1, size ); + deleteInstances( imExpected, sdaiVecOld, 0, 2, size ); + deleteInstances( imExpected, sdaiVecOld, 1, 2, size ); + std::cout << "Checking thread safety of InstMgr in Delete Operation..." ; + + int i, iterations = 100; + for( i = 0 ; i < iterations; i++ ) { + InstMgr * imActual = new InstMgr( 0 ); + sdaiVec_t sdaiVecNew( size ); + + appendInstances( imActual, sdaiVecNew, 0, 1, size ); //Preparetion + std::thread first( deleteInstances, imActual, sdaiVecNew, 0, 2, size ); + std::thread second( deleteInstances, imActual, sdaiVecNew, 1, 2, size ); + + first.join(); + second.join(); + + bool success = compareInstMgr( imExpected, imActual ); + delete imActual; + deleteSdaiVec( sdaiVecNew ); + + if( !success ) { + break; + } + } + + if( i == iterations ) { + std::cout << "...PASS!" << std::endl; + } else { + std::cout << "...FAIL!" << std::endl; + } + + std::cout << std::endl; + delete imExpected; + deleteSdaiVec( sdaiVecOld ); +} + +/// Performs addition and deletion of different instances to the same InstMgr simultaneosly. +void checkInstMgrAppendDeleteThreadSafety() { + InstMgr * imExpected = new InstMgr( 0 ); + int size = dummyEDescNames.size(); + //simulate the work done by two threads + + sdaiVec_t sdaiVecOld( size ); + appendInstances( imExpected, sdaiVecOld, 0, 2, size ); + appendInstances( imExpected, sdaiVecOld, 1, 2, size ); + deleteInstances( imExpected, sdaiVecOld, 0, 2, size ); + std::cout << "Checking thread safety of InstMgr in Append-Delete Operation..." ; + + int i, iterations = 100; + for( i = 0 ; i < iterations; i++ ) { + InstMgr * imActual = new InstMgr( 0 ); + sdaiVec_t sdaiVecNew( size ); + + appendInstances( imActual, sdaiVecNew, 0, 2, size ); //Preparation + std::thread first( appendInstances, imActual, sdaiVecNew, 1, 2, size ); + std::thread second( deleteInstances, imActual, sdaiVecNew, 0, 2, size ); + + first.join(); + second.join(); + + bool success = compareInstMgr( imExpected, imActual ); + delete imActual; + deleteSdaiVec( sdaiVecNew ); + + if( !success ) { + break; + } + } + + if( i == iterations ) { + std::cout << "...PASS!" << std::endl; + } else { + std::cout << "...FAIL!" << std::endl; + } + + std::cout << std::endl; + delete imExpected; + deleteSdaiVec( sdaiVecOld ); +} + +int main( int , char ** ) { + + assert( dummyEDescNames.size() % 4 == 0 && "dummyEDescNames should be a multiple of 4 "); + + checkInstMgrAppendOnlyThreadSafety(); + checkInstMgrDeleteOnlyThreadSafety(); + checkInstMgrAppendDeleteThreadSafety(); +} + From d990137d1b5352f0688bb08f7119f4749ce0ea72 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 15 Jun 2014 14:27:23 +0530 Subject: [PATCH 032/111] Modified CMakeLists.txt to include HAVE_STD_THREAD defs. The cmake files of cldai, cleditor & clstepcore libraries have been changed. --- src/cldai/CMakeLists.txt | 4 ++++ src/cleditor/CMakeLists.txt | 4 ++++ src/clstepcore/CMakeLists.txt | 3 +++ 3 files changed, 11 insertions(+) diff --git a/src/cldai/CMakeLists.txt b/src/cldai/CMakeLists.txt index 4630296a3..f466d043a 100644 --- a/src/cldai/CMakeLists.txt +++ b/src/cldai/CMakeLists.txt @@ -35,6 +35,10 @@ include_directories( ) SC_ADDLIB(stepdai "${LIBSTEPDAI_SRCS}" "steputils;base") +if(HAVE_STD_THREAD) + list(APPEND CMAKE_CXX_FLAGS "-pthread -std=c++0x") + set_target_properties(stepdai PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD" ) +endif(HAVE_STD_THREAD) install(FILES ${SC_CLDAI_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/stepcode/cldai) diff --git a/src/cleditor/CMakeLists.txt b/src/cleditor/CMakeLists.txt index dafbfd6af..8ec8517b5 100644 --- a/src/cleditor/CMakeLists.txt +++ b/src/cleditor/CMakeLists.txt @@ -28,6 +28,10 @@ include_directories( ) SC_ADDLIB(stepeditor "${LIBSTEPEDITOR_SRCS}" "stepcore;stepdai;steputils;base") +if(HAVE_STD_THREAD) + list(APPEND CMAKE_CXX_FLAGS "-pthread -std=c++0x") + set_target_properties(stepeditor PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD" ) +endif(HAVE_STD_THREAD) install(FILES ${SC_CLEDITOR_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/stepcode/cleditor) diff --git a/src/clstepcore/CMakeLists.txt b/src/clstepcore/CMakeLists.txt index 2be17881f..f7c925ca1 100644 --- a/src/clstepcore/CMakeLists.txt +++ b/src/clstepcore/CMakeLists.txt @@ -70,6 +70,9 @@ include_directories( SC_ADDLIB(stepcore "${LIBSTEPCORE_SRCS}" "steputils;stepdai;base") if(HAVE_STD_THREAD) + list(APPEND CMAKE_CXX_FLAGS "-pthread -std=c++0x") + set_target_properties(stepcore PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD" ) + SC_ADDEXEC(InstMgr_thread_safety_test "InstMgr_thread_safety_test.cc" "stepcore" ) set_target_properties(InstMgr_thread_safety_test PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD") target_link_libraries(InstMgr_thread_safety_test "pthread" ) From 485fad46ca0d3ab42f7cf13efb5b095cc7aa8644 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 15 Jun 2014 14:34:23 +0530 Subject: [PATCH 033/111] Removed duplicate code --- src/clstepcore/instmgr.cc | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/clstepcore/instmgr.cc b/src/clstepcore/instmgr.cc index e0d822b0e..756b44438 100644 --- a/src/clstepcore/instmgr.cc +++ b/src/clstepcore/instmgr.cc @@ -346,12 +346,7 @@ InstMgr::GetApplication_instance( int index ) { SDAI_Application_instance * InstMgr::GetSTEPentity( int index ) { - MgrNode * mn = ( MgrNode * )( *master )[index]; - if( mn ) { - return mn->GetApplication_instance(); - } else { - return 0; - } + return GetApplication_instance( index ); } /////////////////////////////////////////////////////////////////////////////// @@ -385,19 +380,7 @@ InstMgr::GetApplication_instance( const char * entityKeyword, int starting_index SDAI_Application_instance * InstMgr::GetSTEPentity( const char * entityKeyword, int starting_index ) { - MgrNode * node; - SDAI_Application_instance * se; - - int count = InstanceCount(); - for( int j = starting_index; j < count; ++j ) { - node = GetMgrNode( j ); - se = node->GetApplication_instance(); - if( !strcmp( se->EntityName(), - PrettyTmpName( entityKeyword ) ) ) { - return se; - } - } - return ENTITY_NULL; + return GetApplication_instance( entityKeyword, starting_index ); } /////////////////////////////////////////////////////////////////////////////// From 164c0651e18faadc47cdb2bf04b04b7443854bc8 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 15 Jun 2014 14:40:41 +0530 Subject: [PATCH 034/111] Made Append / Delete in instmgr thread safe. The InstMgr_thread_safety_test passes. Had to a change file in cmake directory in order to compile the changes. --- cmake/SC_CXX_schema_macros.cmake | 3 +++ src/clstepcore/instmgr.cc | 35 +++++++++++++++++++++++++++++--- src/clstepcore/instmgr.h | 3 +++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/cmake/SC_CXX_schema_macros.cmake b/cmake/SC_CXX_schema_macros.cmake index 23c00eb1a..346495f1e 100644 --- a/cmake/SC_CXX_schema_macros.cmake +++ b/cmake/SC_CXX_schema_macros.cmake @@ -29,6 +29,9 @@ macro(SCHEMA_EXES) RELATIVE_PATH_TO_TOPLEVEL(${CMAKE_CURRENT_SOURCE_DIR} RELATIVE_PATH_COMPONENT) SC_ADDEXEC(p21read_${PROJECT_NAME} "${RELATIVE_PATH_COMPONENT}/src/test/p21read/p21read.cc" "${PROJECT_NAME};stepdai;stepcore;stepeditor;steputils;base" "TESTABLE") #add_dependencies(p21read_${PROJECT_NAME} version_string) + if(HAVE_STD_THREAD) + set_target_properties(p21read_${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD") + endif(HAVE_STD_THREAD) if(NOT WIN32) #SC_ADDEXEC(lazy_${PROJECT_NAME} "${RELATIVE_PATH_COMPONENT}/src/cllazyfile/lazy_test.cc" "${PROJECT_NAME};steplazyfile;stepdai;stepcore;stepeditor;steputils;base" "TESTABLE") #add_dependencies(lazy_${PROJECT_NAME} version_string) diff --git a/src/clstepcore/instmgr.cc b/src/clstepcore/instmgr.cc index 756b44438..778f12053 100644 --- a/src/clstepcore/instmgr.cc +++ b/src/clstepcore/instmgr.cc @@ -67,15 +67,19 @@ InstMgr::~InstMgr() { /////////////////////////////////////////////////////////////////////////////// void InstMgr::ClearInstances() { + masterMtx.lock(); master->ClearEntries(); sortedMaster->ClearEntries(); maxFileId = -1; + masterMtx.unlock(); } void InstMgr::DeleteInstances() { + masterMtx.lock(); master->DeleteEntries(); sortedMaster->ClearEntries(); maxFileId = -1; + masterMtx.unlock(); } /////////////////////////////////////////////////////////////////////////////// @@ -95,6 +99,8 @@ InstMgr::VerifyInstances( ErrorDescriptor & err ) { int errorCount = 0; char errbuf[BUFSIZ]; + masterMtx.lock(); + int n = InstanceCount(); MgrNode * mn; SDAI_Application_instance * se; @@ -158,6 +164,7 @@ InstMgr::VerifyInstances( ErrorDescriptor & err ) { err.GreaterSeverity( SEVERITY_INCOMPLETE ); } + masterMtx.unlock(); return rval; } @@ -184,7 +191,8 @@ int InstMgr::GetIndex( MgrNode * mn ) { int InstMgr::GetIndex( SDAI_Application_instance * se ) { int fileId = se->StepFileId(); - return sortedMaster->MgrNodeIndex( fileId ); + int index = sortedMaster->MgrNodeIndex( fileId ); + return index; } /////////////////////////////////////////////////////////////////////////////// @@ -217,10 +225,12 @@ MgrNode * InstMgr::Append( SDAI_Application_instance * se, stateEnum listState ) se->StepFileId( NextFileId() ); // assign a file id } + masterMtx.lock(); mn = FindFileId( se->StepFileId() ); if( mn ) { // if id already in list // and it's because instance is already in list if( GetApplication_instance( mn ) == se ) { + masterMtx.unlock(); return 0; // return 0 or mn? } else { se->StepFileId( NextFileId() ); // otherwise assign a new file id @@ -241,13 +251,16 @@ MgrNode * InstMgr::Append( SDAI_Application_instance * se, stateEnum listState ) " doesn't have state information" << endl; master->Append( mn ); sortedMaster->Insert( mn ); + + masterMtx.unlock(); //PrintSortedFileIds(); return mn; } /////////////////////////////////////////////////////////////////////////////// -void InstMgr::Delete( MgrNode * node ) { +// Is common to both the the avalaible API +void InstMgr::DeleteHelper( MgrNode * node ) { // delete the node from its current state list node->Remove(); @@ -267,8 +280,18 @@ void InstMgr::Delete( MgrNode * node ) { /////////////////////////////////////////////////////////////////////////////// +void InstMgr::Delete( MgrNode * node ) { + masterMtx.lock(); + DeleteHelper( node ); + masterMtx.unlock(); +} + +/////////////////////////////////////////////////////////////////////////////// + void InstMgr::Delete( SDAI_Application_instance * se ) { - Delete( FindFileId( se->StepFileId() ) ); + masterMtx.lock(); + DeleteHelper( FindFileId( se->StepFileId() ) ); + masterMtx.unlock(); } /////////////////////////////////////////////////////////////////////////////// @@ -320,6 +343,8 @@ InstMgr::EntityKeywordCount( const char * name ) { int count = 0; MgrNode * node; SDAI_Application_instance * se; + + masterMtx.lock(); int n = InstanceCount(); for( int j = 0; j < n; ++j ) { node = GetMgrNode( j ); @@ -329,6 +354,7 @@ InstMgr::EntityKeywordCount( const char * name ) { ++count; } } + masterMtx.unlock(); return count; } @@ -366,6 +392,7 @@ InstMgr::GetApplication_instance( const char * entityKeyword, int starting_index MgrNode * node; SDAI_Application_instance * se; + masterMtx.lock(); int count = InstanceCount(); for( int j = starting_index; j < count; ++j ) { node = GetMgrNode( j ); @@ -375,6 +402,8 @@ InstMgr::GetApplication_instance( const char * entityKeyword, int starting_index return se; } } + + masterMtx.unlock(); return ENTITY_NULL; } diff --git a/src/clstepcore/instmgr.h b/src/clstepcore/instmgr.h index 70ec4323f..849bc9e24 100644 --- a/src/clstepcore/instmgr.h +++ b/src/clstepcore/instmgr.h @@ -36,6 +36,7 @@ #include #include +#include class SC_CORE_EXPORT InstMgr { protected: @@ -47,6 +48,7 @@ class SC_CORE_EXPORT InstMgr { // this corresponds to the display list object by index MgrNodeArraySorted * sortedMaster; // master array sorted by fileId // StateList *master; // this will be an sorted array of ptrs to MgrNodes + sc_mutex masterMtx; public: InstMgr( int ownsInstances = 0 ); @@ -87,6 +89,7 @@ class SC_CORE_EXPORT InstMgr { // void Append(MgrNode *node); MgrNode * Append( SDAI_Application_instance * se, stateEnum listState ); // deletes node from master list structure + void DeleteHelper( MgrNode * node ); void Delete( MgrNode * node ); void Delete( SDAI_Application_instance * se ); From 65f767aa7bd8515cd9111ce5da100745b9f2f40e Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 18 Jun 2014 11:30:41 +0530 Subject: [PATCH 035/111] Increasing the number of iterations. A print statement is also corrected. --- src/clstepcore/InstMgr_thread_safety_test.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/clstepcore/InstMgr_thread_safety_test.cc b/src/clstepcore/InstMgr_thread_safety_test.cc index 5243a520e..bcae26a8b 100644 --- a/src/clstepcore/InstMgr_thread_safety_test.cc +++ b/src/clstepcore/InstMgr_thread_safety_test.cc @@ -46,7 +46,7 @@ bool compareKeywordCount ( InstMgr * mgr1, InstMgr * mgr2 ) { //some comparisions may be repeated. const char * str = dummyEDescNames[i].c_str(); if( mgr1->EntityKeywordCount( str ) != mgr2->EntityKeywordCount( str ) ) { - std::cout << std::endl << "\tEntityKeywordCount mistmatch for " << str << ": " << mgr1->MaxFileId() << " and " << mgr2->MaxFileId() << std::endl; + std::cout << std::endl << "\tEntityKeywordCount mistmatch for " << str << ": " << mgr1->EntityKeywordCount( str ) << " and " << mgr2->EntityKeywordCount( str ) << std::endl; return false; } } @@ -84,7 +84,7 @@ void checkInstMgrAppendOnlyThreadSafety() { appendInstances( imExpected, sdaiVecOld, 1, 2, size ); std::cout << "Checking thread safety of InstMgr in Append Operation..." ; - int i, iterations = 100; + int i, iterations = 1000; for( i = 0 ; i < iterations; i++ ) { InstMgr * imActual = new InstMgr( 0 ); sdaiVec_t sdaiVecNew( size ); @@ -128,7 +128,7 @@ void checkInstMgrDeleteOnlyThreadSafety() { deleteInstances( imExpected, sdaiVecOld, 1, 2, size ); std::cout << "Checking thread safety of InstMgr in Delete Operation..." ; - int i, iterations = 100; + int i, iterations = 1000; for( i = 0 ; i < iterations; i++ ) { InstMgr * imActual = new InstMgr( 0 ); sdaiVec_t sdaiVecNew( size ); @@ -172,7 +172,7 @@ void checkInstMgrAppendDeleteThreadSafety() { deleteInstances( imExpected, sdaiVecOld, 0, 2, size ); std::cout << "Checking thread safety of InstMgr in Append-Delete Operation..." ; - int i, iterations = 100; + int i, iterations = 1000; for( i = 0 ; i < iterations; i++ ) { InstMgr * imActual = new InstMgr( 0 ); sdaiVec_t sdaiVecNew( size ); From f6b92019b15e84b92117dd4f3153aa207bd3e4a4 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 18 Jun 2014 11:41:26 +0530 Subject: [PATCH 036/111] Corrected locking in getApplication_Instance --- src/clstepcore/instmgr.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/clstepcore/instmgr.cc b/src/clstepcore/instmgr.cc index 778f12053..27a16380c 100644 --- a/src/clstepcore/instmgr.cc +++ b/src/clstepcore/instmgr.cc @@ -399,6 +399,7 @@ InstMgr::GetApplication_instance( const char * entityKeyword, int starting_index se = node->GetApplication_instance(); if( !strcmp( se->EntityName(), PrettyTmpName( entityKeyword ) ) ) { + masterMtx.unlock(); return se; } } From 79f9473d01f0c78c9c488c17c57af9442247b4f7 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 18 Jun 2014 11:44:54 +0530 Subject: [PATCH 037/111] Added sc_recursive_mutex This will be used to handle situtations where there are 2 public apis. Both modify an internal data structure, hence lock it. However one API depends on other. Thereby it will have to-reobtain the lock. --- src/clstepcore/instmgr.cc | 12 +++--------- src/clstepcore/instmgr.h | 3 +-- src/clutils/sc_mutex.h | 20 ++++++++++++++++++++ 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/clstepcore/instmgr.cc b/src/clstepcore/instmgr.cc index 27a16380c..bbc5171ea 100644 --- a/src/clstepcore/instmgr.cc +++ b/src/clstepcore/instmgr.cc @@ -260,8 +260,9 @@ MgrNode * InstMgr::Append( SDAI_Application_instance * se, stateEnum listState ) /////////////////////////////////////////////////////////////////////////////// // Is common to both the the avalaible API -void InstMgr::DeleteHelper( MgrNode * node ) { +void InstMgr::Delete( MgrNode * node ) { // delete the node from its current state list + masterMtx.lock(); node->Remove(); int index; @@ -276,13 +277,6 @@ void InstMgr::DeleteHelper( MgrNode * node ) { master->Remove( index ); delete node; -} - -/////////////////////////////////////////////////////////////////////////////// - -void InstMgr::Delete( MgrNode * node ) { - masterMtx.lock(); - DeleteHelper( node ); masterMtx.unlock(); } @@ -290,7 +284,7 @@ void InstMgr::Delete( MgrNode * node ) { void InstMgr::Delete( SDAI_Application_instance * se ) { masterMtx.lock(); - DeleteHelper( FindFileId( se->StepFileId() ) ); + Delete( FindFileId( se->StepFileId() ) ); masterMtx.unlock(); } diff --git a/src/clstepcore/instmgr.h b/src/clstepcore/instmgr.h index 849bc9e24..34fc7f1c6 100644 --- a/src/clstepcore/instmgr.h +++ b/src/clstepcore/instmgr.h @@ -48,7 +48,7 @@ class SC_CORE_EXPORT InstMgr { // this corresponds to the display list object by index MgrNodeArraySorted * sortedMaster; // master array sorted by fileId // StateList *master; // this will be an sorted array of ptrs to MgrNodes - sc_mutex masterMtx; + sc_recursive_mutex masterMtx; public: InstMgr( int ownsInstances = 0 ); @@ -89,7 +89,6 @@ class SC_CORE_EXPORT InstMgr { // void Append(MgrNode *node); MgrNode * Append( SDAI_Application_instance * se, stateEnum listState ); // deletes node from master list structure - void DeleteHelper( MgrNode * node ); void Delete( MgrNode * node ); void Delete( SDAI_Application_instance * se ); diff --git a/src/clutils/sc_mutex.h b/src/clutils/sc_mutex.h index 75478e9f9..90a70be76 100644 --- a/src/clutils/sc_mutex.h +++ b/src/clutils/sc_mutex.h @@ -28,4 +28,24 @@ class sc_mutex { #endif //HAVE_STD_THREAD } }; + +class sc_recursive_mutex { + protected: +#ifdef HAVE_STD_THREAD + std::recursive_mutex mtx; +#endif //HAVE_STD_THREAD + + public: + void lock() { +#ifdef HAVE_STD_THREAD + mtx.lock(); +#endif //HAVE_STD_THREAD + } + + void unlock() { +#ifdef HAVE_STD_THREAD + mtx.unlock(); +#endif //HAVE_STD_THREAD + } +}; #endif //SC_MUTEX_H From d6ad56ee6c09b1807e8936cceaabc081eaed02a2 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 18 Jun 2014 11:51:18 +0530 Subject: [PATCH 038/111] Locked more potentially thread-unsafe functions. --- src/clstepcore/instmgr.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/clstepcore/instmgr.cc b/src/clstepcore/instmgr.cc index bbc5171ea..dddf5e6cf 100644 --- a/src/clstepcore/instmgr.cc +++ b/src/clstepcore/instmgr.cc @@ -38,12 +38,14 @@ static int debug_level = 3; void InstMgr::PrintSortedFileIds() { MgrNode * mn = 0; + masterMtx.lock(); int count = InstanceCount(); int i = 0; for( i = 0; i < count; i++ ) { mn = ( MgrNode * )( ( *sortedMaster )[i] ); cout << i << " " << mn->GetFileId() << endl; } + masterMtx.unlock(); } InstMgr::InstMgr( int ownsInstances ) @@ -171,12 +173,14 @@ InstMgr::VerifyInstances( ErrorDescriptor & err ) { /////////////////////////////////////////////////////////////////////////////// MgrNode * InstMgr::FindFileId( int fileId ) { + MgrNode * mn = 0; + masterMtx.lock(); int index = sortedMaster->MgrNodeIndex( fileId ); if( index >= 0 ) { - return ( MgrNode * )( *sortedMaster )[index]; - } else { - return ( MgrNode * )0; + mn = ( MgrNode * )( *sortedMaster )[index]; } + masterMtx.unlock(); + return mn; } /////////////////////////////////////////////////////////////////////////////// @@ -190,8 +194,10 @@ int InstMgr::GetIndex( MgrNode * mn ) { /////////////////////////////////////////////////////////////////////////////// int InstMgr::GetIndex( SDAI_Application_instance * se ) { + masterMtx.lock(); int fileId = se->StepFileId(); int index = sortedMaster->MgrNodeIndex( fileId ); + masterMtx.unlock(); return index; } From 05360da87c8d06379de07f77b6c440806cbc0e8b Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 18 Jun 2014 21:36:53 +0530 Subject: [PATCH 039/111] Added containingList pointer in GenericNode This pointer will point to the list of which the node is part of. Also moved some code between files. --- src/clutils/gennode.cc | 15 +++++++++++++++ src/clutils/gennode.h | 17 ++++------------- src/clutils/gennodearray.cc | 9 --------- src/clutils/gennodelist.cc | 7 +++++++ 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/clutils/gennode.cc b/src/clutils/gennode.cc index 3036ab19d..d1e440e13 100644 --- a/src/clutils/gennode.cc +++ b/src/clutils/gennode.cc @@ -23,6 +23,15 @@ // depends on: // void GenNodeList::Append(GenericNode *node) from the gennodelist.h ////////////////////////////////////////////////////////////////////////////// +GenericNode::GenericNode() { + next = 0; + prev = 0; + containingList = 0; +} + +GenericNode::~GenericNode() { + Remove(); +} void GenericNode::Append( GenNodeList * list ) { // if(debug_level >= PrintFunctionTrace) @@ -32,3 +41,9 @@ void GenericNode::Append( GenNodeList * list ) { list->Append( this ); } +void GenericNode::Remove() { + if( containingList ) { + containingList->Remove( this ); + } +} + diff --git a/src/clutils/gennode.h b/src/clutils/gennode.h index c4c630244..24a9d74f6 100644 --- a/src/clutils/gennode.h +++ b/src/clutils/gennode.h @@ -35,6 +35,8 @@ class SC_UTILS_EXPORT GenericNode { protected: GenericNode * next; GenericNode * prev; + //pointer to the list of which this MgrNode is a element of. + GenNodeList * containingList; public: GenericNode(); virtual ~GenericNode(); @@ -45,20 +47,9 @@ class SC_UTILS_EXPORT GenericNode { GenericNode * Prev() { return prev; } - virtual void Append( GenNodeList * list ); - virtual void Remove() { - ( next ) ? ( next->prev = prev ) : 0; - ( prev ) ? ( prev->next = next ) : 0; - /* - // if(next) - // next->prev = prev; - // if(prev) - // prev->next = next; - */ - next = 0; - prev = 0; - } + virtual void Append( GenNodeList * list ); + virtual void Remove(); }; ////////////////////////////////////////////////////////////////////////////// diff --git a/src/clutils/gennodearray.cc b/src/clutils/gennodearray.cc index f78acbd14..3b039fc0c 100644 --- a/src/clutils/gennodearray.cc +++ b/src/clutils/gennodearray.cc @@ -24,15 +24,6 @@ extern "C" { } #endif -GenericNode::GenericNode() { - next = 0; - prev = 0; -} - -GenericNode::~GenericNode() { - Remove(); -} - GenNodeArray::GenNodeArray( int defaultSize ) { _bufsize = defaultSize; _buf = new GenericNode*[_bufsize]; diff --git a/src/clutils/gennodelist.cc b/src/clutils/gennodelist.cc index 9560a72b1..02a81c818 100644 --- a/src/clutils/gennodelist.cc +++ b/src/clutils/gennodelist.cc @@ -17,25 +17,30 @@ //#include #include #include +#include // inserts after existNode void GenNodeList::InsertAfter( GenericNode * newNode, GenericNode * existNode ) { + assert( newNode->containingList == 0 && "Node Already in another list, remove it first" ); newNode->next = existNode->next; newNode->next->prev = newNode; newNode->prev = existNode; existNode->next = newNode; + newNode->containingList = this; } // inserts before existNode void GenNodeList::InsertBefore( GenericNode * newNode, GenericNode * existNode ) { + assert( newNode->containingList == 0 && "Node Already in another list, remove it first" ); existNode->prev->next = newNode; newNode->prev = existNode->prev; newNode->next = existNode; existNode->prev = newNode; + newNode->containingList = this; } // inserts before the head node @@ -50,6 +55,7 @@ GenNodeList::Remove( GenericNode * node ) { node->prev->next = node->next; node->next = 0; node->prev = 0; + node->containingList = 0; } } void GenNodeList::ClearEntries() { @@ -61,6 +67,7 @@ void GenNodeList::ClearEntries() { while( gnPrev != head ) { gnPrev->prev = 0; gnPrev->next = 0; + gnPrev->containingList = 0; gnPrev = gn; gn = gn->Next(); } From 17c720206ae5e45e76e427a9b028f1a2c3b878dc Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 18 Jun 2014 21:49:32 +0530 Subject: [PATCH 040/111] Added another occurance of containingList --- src/clutils/gennodelist.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/clutils/gennodelist.h b/src/clutils/gennodelist.h index 4751f6044..80ac488b5 100644 --- a/src/clutils/gennodelist.h +++ b/src/clutils/gennodelist.h @@ -62,6 +62,7 @@ inline GenNodeList::GenNodeList( GenericNode * headNode ) { head = headNode; head->next = head; head->prev = head; + head->containingList = this; } #endif From f89e3c49997fec8017bd4001549f9f4d8dccda94 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 18 Jun 2014 21:51:28 +0530 Subject: [PATCH 041/111] Modified the insert function in gen/mgr/disp lists. The new insert function checks whether the existing node belongs to the same list or not. If it doesn't it does nothing and returns false. This will be very helpful when introducing thread safety in list structures. --- src/clstepcore/dispnodelist.cc | 8 +++---- src/clstepcore/dispnodelist.h | 4 ++-- src/clstepcore/mgrnodelist.cc | 8 +++---- src/clstepcore/mgrnodelist.h | 4 ++-- src/clutils/gennodelist.cc | 40 ++++++++++++++++++++++++---------- src/clutils/gennodelist.h | 8 ++++--- 6 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/clstepcore/dispnodelist.cc b/src/clstepcore/dispnodelist.cc index f4d00a6aa..e5cbddfc7 100644 --- a/src/clstepcore/dispnodelist.cc +++ b/src/clstepcore/dispnodelist.cc @@ -34,23 +34,23 @@ void DisplayNodeList::Append( GenericNode * node ) { // deletes newNode from its previous list & inserts after // existNode -void DisplayNodeList::InsertAfter( GenericNode * newNode, +bool DisplayNodeList::InsertAfter( GenericNode * newNode, GenericNode * existNode ) { if( newNode->next != 0 ) { // remove the node from its previous newNode->Remove(); // display state list } - GenNodeList::InsertAfter( newNode, existNode ); + return GenNodeList::InsertAfter( newNode, existNode ); // DON'T DO THIS ((DisplayNode *)newNode)->displayState = listType; } // deletes newNode from its previous list & inserts before // existNode -void DisplayNodeList::InsertBefore( GenericNode * newNode, +bool DisplayNodeList::InsertBefore( GenericNode * newNode, GenericNode * existNode ) { if( newNode->next != 0 ) { // remove the node from its previous newNode->Remove(); // display state list } - GenNodeList::InsertBefore( newNode, existNode ); + return GenNodeList::InsertBefore( newNode, existNode ); // DON'T DO THIS!!! ((DisplayNode *)newNode)->displayState = listType; } diff --git a/src/clstepcore/dispnodelist.h b/src/clstepcore/dispnodelist.h index c4fe4dde3..6c3a966ca 100644 --- a/src/clstepcore/dispnodelist.h +++ b/src/clstepcore/dispnodelist.h @@ -44,8 +44,8 @@ class SC_CORE_EXPORT DisplayNodeList : public GenNodeList { virtual void Append( GenericNode * node ); // deletes newNode from its previous list & inserts in // relation to existNode - virtual void InsertAfter( GenericNode * newNode, GenericNode * existNode ); - virtual void InsertBefore( GenericNode * newNode, GenericNode * existNode ); + virtual bool InsertAfter( GenericNode * newNode, GenericNode * existNode ); + virtual bool InsertBefore( GenericNode * newNode, GenericNode * existNode ); virtual void Remove( GenericNode * node ); protected: diff --git a/src/clstepcore/mgrnodelist.cc b/src/clstepcore/mgrnodelist.cc index 9bff8e254..91056cb2f 100644 --- a/src/clstepcore/mgrnodelist.cc +++ b/src/clstepcore/mgrnodelist.cc @@ -40,23 +40,23 @@ void MgrNodeList::Append( GenericNode * node ) { // deletes newNode from its previous list & inserts after // existNode -void MgrNodeList::InsertAfter( GenericNode * newNode, +bool MgrNodeList::InsertAfter( GenericNode * newNode, GenericNode * existNode ) { if( newNode->next != 0 ) { // remove the node from its previous list newNode->Remove(); } - GenNodeList::InsertAfter( newNode, existNode ); + return GenNodeList::InsertAfter( newNode, existNode ); // DON'T DO THIS ((MgrNode *)newNode)->currState = listType; } // deletes newNode from its previous list & inserts before // existNode -void MgrNodeList::InsertBefore( GenericNode * newNode, +bool MgrNodeList::InsertBefore( GenericNode * newNode, GenericNode * existNode ) { if( newNode->next != 0 ) { // remove the node from its previous newNode->Remove(); // state list } - GenNodeList::InsertBefore( newNode, existNode ); + return GenNodeList::InsertBefore( newNode, existNode ); // DON'T DO THIS!! ((MgrNode *)newNode)->currState = listType; } diff --git a/src/clstepcore/mgrnodelist.h b/src/clstepcore/mgrnodelist.h index be822c798..963d1e173 100644 --- a/src/clstepcore/mgrnodelist.h +++ b/src/clstepcore/mgrnodelist.h @@ -42,8 +42,8 @@ class SC_CORE_EXPORT MgrNodeList : public GenNodeList { virtual void Append( GenericNode * node ); // deletes newNode from its previous list & inserts in // relation to existNode - virtual void InsertAfter( GenericNode * newNode, GenericNode * existNode ); - virtual void InsertBefore( GenericNode * newNode, GenericNode * existNode ); + virtual bool InsertAfter( GenericNode * newNode, GenericNode * existNode ); + virtual bool InsertBefore( GenericNode * newNode, GenericNode * existNode ); virtual void Remove( GenericNode * node ); protected: diff --git a/src/clutils/gennodelist.cc b/src/clutils/gennodelist.cc index 02a81c818..5a632cc41 100644 --- a/src/clutils/gennodelist.cc +++ b/src/clutils/gennodelist.cc @@ -20,27 +20,43 @@ #include // inserts after existNode -void GenNodeList::InsertAfter( GenericNode * newNode, +bool GenNodeList::InsertAfter( GenericNode * newNode, GenericNode * existNode ) { + bool success = false; assert( newNode->containingList == 0 && "Node Already in another list, remove it first" ); - newNode->next = existNode->next; - newNode->next->prev = newNode; - newNode->prev = existNode; - existNode->next = newNode; - newNode->containingList = this; + // checking wehther existNode still belong to the same list + if( existNode->containingList == this ) { + newNode->next = existNode->next; + newNode->next->prev = newNode; + + newNode->prev = existNode; + existNode->next = newNode; + + newNode->containingList = this; + success = true; + } + return success; } // inserts before existNode -void GenNodeList::InsertBefore( GenericNode * newNode, +bool GenNodeList::InsertBefore( GenericNode * newNode, GenericNode * existNode ) { + bool success = false; assert( newNode->containingList == 0 && "Node Already in another list, remove it first" ); - existNode->prev->next = newNode; - newNode->prev = existNode->prev; - newNode->next = existNode; - existNode->prev = newNode; - newNode->containingList = this; + // checking wehther existNode still belong to the same list + if( existNode->containingList == this ) { + existNode->prev->next = newNode; + newNode->prev = existNode->prev; + + newNode->next = existNode; + existNode->prev = newNode; + + newNode->containingList = this; + success = true; + } + return success; } // inserts before the head node diff --git a/src/clutils/gennodelist.h b/src/clutils/gennodelist.h index 80ac488b5..0246f8a26 100644 --- a/src/clutils/gennodelist.h +++ b/src/clutils/gennodelist.h @@ -42,9 +42,11 @@ class SC_UTILS_EXPORT GenNodeList { // deletes node from its previous list & appends virtual void Append( GenericNode * node ); // deletes newNode from its previous list & inserts in - // relation to existNode - virtual void InsertAfter( GenericNode * newNode, GenericNode * existNode ); - virtual void InsertBefore( GenericNode * newNode, GenericNode * existNode ); + // relation to existNode. Returns true on success. If + // the existNode doesn't belong to the list then simply + // returns false + virtual bool InsertAfter( GenericNode * newNode, GenericNode * existNode ); + virtual bool InsertBefore( GenericNode * newNode, GenericNode * existNode ); virtual void Remove( GenericNode * node ); From ad6752a80f36f29dc12c2d976f5a67bdf96dca83 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 18 Jun 2014 22:00:48 +0530 Subject: [PATCH 042/111] Used containingList to remove duplicate code. --- src/clstepcore/mgrnode.cc | 9 +-------- src/clstepcore/mgrnodelist.cc | 6 +++++- src/clstepcore/mgrnodelist.h | 1 + 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/clstepcore/mgrnode.cc b/src/clstepcore/mgrnode.cc index 8e44443ee..473eab39f 100644 --- a/src/clstepcore/mgrnode.cc +++ b/src/clstepcore/mgrnode.cc @@ -50,14 +50,7 @@ MgrNode * MgrNode::StateFindFileId( int fileId ) { return this; } else { // mn is really a MgrNode - MgrNode * mn = ( MgrNode * )( startNode->Next() ); - while( mn != startNode ) { - if( mn->GetFileId() == fileId ) { - return ( MgrNode * )mn; - } - mn = ( ( MgrNode * )mn->Next() ); - } - return ( MgrNode * )0; + return ( ( MgrNodeList * )containingList )->FindFileId( fileId, startNode ); } } diff --git a/src/clstepcore/mgrnodelist.cc b/src/clstepcore/mgrnodelist.cc index 91056cb2f..0a3e67d9e 100644 --- a/src/clstepcore/mgrnodelist.cc +++ b/src/clstepcore/mgrnodelist.cc @@ -61,7 +61,11 @@ bool MgrNodeList::InsertBefore( GenericNode * newNode, } MgrNode * MgrNodeList::FindFileId( int fileId ) { - MgrNode * mn = ( MgrNode * )head->next; + return FindFileId( fileId, ( MgrNode * )head ); +} + +MgrNode * MgrNodeList::FindFileId( int fileId, MgrNode * startNode ) { + MgrNode * mn = ( MgrNode * )startNode->next; while( mn != head ) { if( mn->GetFileId() == fileId ) { return mn; diff --git a/src/clstepcore/mgrnodelist.h b/src/clstepcore/mgrnodelist.h index 963d1e173..b72f9c31c 100644 --- a/src/clstepcore/mgrnodelist.h +++ b/src/clstepcore/mgrnodelist.h @@ -36,6 +36,7 @@ class SC_CORE_EXPORT MgrNodeList : public GenNodeList { // ADDED functions virtual MgrNode * FindFileId( int fileId ); + virtual MgrNode * FindFileId( int fileId, MgrNode * startNode ); // REDEFINED functions // deletes node from its previous list & appends From d6c133f8051515532f40c38c4d1a9c91530a90f2 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 18 Jun 2014 22:03:39 +0530 Subject: [PATCH 043/111] Introduced recursive_mutex in gennodelist mgrnodelist which inherits gennodelist was also changed --- src/clstepcore/mgrnodelist.cc | 7 +++++-- src/clutils/gennodelist.cc | 10 ++++++++++ src/clutils/gennodelist.h | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/clstepcore/mgrnodelist.cc b/src/clstepcore/mgrnodelist.cc index 0a3e67d9e..fbe385297 100644 --- a/src/clstepcore/mgrnodelist.cc +++ b/src/clstepcore/mgrnodelist.cc @@ -65,13 +65,16 @@ MgrNode * MgrNodeList::FindFileId( int fileId ) { } MgrNode * MgrNodeList::FindFileId( int fileId, MgrNode * startNode ) { + MgrNode * match = 0; + mtx.lock(); MgrNode * mn = ( MgrNode * )startNode->next; while( mn != head ) { if( mn->GetFileId() == fileId ) { - return mn; + match = mn; } mn = ( MgrNode * )mn->next; } - return ( MgrNode * )0; + mtx.unlock(); + return match; } diff --git a/src/clutils/gennodelist.cc b/src/clutils/gennodelist.cc index 5a632cc41..d875efde6 100644 --- a/src/clutils/gennodelist.cc +++ b/src/clutils/gennodelist.cc @@ -25,6 +25,7 @@ bool GenNodeList::InsertAfter( GenericNode * newNode, bool success = false; assert( newNode->containingList == 0 && "Node Already in another list, remove it first" ); + mtx.lock(); // checking wehther existNode still belong to the same list if( existNode->containingList == this ) { newNode->next = existNode->next; @@ -36,6 +37,7 @@ bool GenNodeList::InsertAfter( GenericNode * newNode, newNode->containingList = this; success = true; } + mtx.unlock(); return success; } @@ -45,6 +47,7 @@ bool GenNodeList::InsertBefore( GenericNode * newNode, bool success = false; assert( newNode->containingList == 0 && "Node Already in another list, remove it first" ); + mtx.lock(); // checking wehther existNode still belong to the same list if( existNode->containingList == this ) { existNode->prev->next = newNode; @@ -56,6 +59,7 @@ bool GenNodeList::InsertBefore( GenericNode * newNode, newNode->containingList = this; success = true; } + mtx.unlock(); return success; } @@ -66,6 +70,7 @@ void GenNodeList::Append( GenericNode * node ) { void GenNodeList::Remove( GenericNode * node ) { + mtx.lock(); if( node != head ) { node->next->prev = node->prev; node->prev->next = node->next; @@ -73,10 +78,12 @@ GenNodeList::Remove( GenericNode * node ) { node->prev = 0; node->containingList = 0; } + mtx.unlock(); } void GenNodeList::ClearEntries() { // if(debug_level >= PrintFunctionTrace) // cout << "GenNodeList::ClearEntries()\n"; + mtx.lock(); GenericNode * gnPrev = head->Next(); GenericNode * gn = gnPrev->Next(); @@ -89,11 +96,13 @@ void GenNodeList::ClearEntries() { } head->next = head; head->prev = head; + mtx.unlock(); } void GenNodeList::DeleteEntries() { // if(debug_level >= PrintFunctionTrace) // cout << "GenNodeList::DeleteEntries()\n"; + mtx.lock(); GenericNode * gnPrev = head->Next(); GenericNode * gn; head->next = 0; @@ -105,4 +114,5 @@ void GenNodeList::DeleteEntries() { } head->next = head; head->prev = head; + mtx.unlock(); } diff --git a/src/clutils/gennodelist.h b/src/clutils/gennodelist.h index 0246f8a26..6daed60bb 100644 --- a/src/clutils/gennodelist.h +++ b/src/clutils/gennodelist.h @@ -17,6 +17,7 @@ #include #include +#include ////////////////////////////////////////////////////////////////////////////// // class GenNodeList @@ -52,6 +53,7 @@ class SC_UTILS_EXPORT GenNodeList { protected: GenericNode * head; + sc_recursive_mutex mtx; }; ////////////////////////////////////////////////////////////////////////////// From d0e9aa9dfb8cdef96af72439b3b2183deadb8235 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 18 Jun 2014 22:26:42 +0530 Subject: [PATCH 044/111] Added GetGenNode function in GenNodeArray. This function is a safer couterpart to [] function. Replaced call to the [] function with calls to GetGenNode function. Was feasable since the former is only used for getting GenericNode pointers. --- src/clstepcore/instmgr.cc | 8 ++++---- src/clstepcore/instmgr.h | 4 +++- src/clutils/gennodearray.cc | 10 ++++++++++ src/clutils/gennodearray.h | 6 ++++++ 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/clstepcore/instmgr.cc b/src/clstepcore/instmgr.cc index dddf5e6cf..b5644011b 100644 --- a/src/clstepcore/instmgr.cc +++ b/src/clstepcore/instmgr.cc @@ -42,7 +42,7 @@ InstMgr::PrintSortedFileIds() { int count = InstanceCount(); int i = 0; for( i = 0; i < count; i++ ) { - mn = ( MgrNode * )( ( *sortedMaster )[i] ); + mn = ( MgrNode * )( sortedMaster->GetGenNode( i ) ); cout << i << " " << mn->GetFileId() << endl; } masterMtx.unlock(); @@ -177,7 +177,7 @@ MgrNode * InstMgr::FindFileId( int fileId ) { masterMtx.lock(); int index = sortedMaster->MgrNodeIndex( fileId ); if( index >= 0 ) { - mn = ( MgrNode * )( *sortedMaster )[index]; + mn = ( MgrNode * )sortedMaster->GetGenNode( index ); } masterMtx.unlock(); return mn; @@ -362,7 +362,7 @@ InstMgr::EntityKeywordCount( const char * name ) { SDAI_Application_instance * InstMgr::GetApplication_instance( int index ) { - MgrNode * mn = ( MgrNode * )( *master )[index]; + MgrNode * mn = ( MgrNode * )master->GetGenNode( index ); if( mn ) { return mn->GetApplication_instance(); } else { @@ -417,7 +417,7 @@ InstMgr::GetSTEPentity( const char * entityKeyword, int starting_index ) { void * InstMgr::GetSEE( int index ) { - MgrNode * mn = ( MgrNode * )( *master )[index]; + MgrNode * mn = ( MgrNode * )master->GetGenNode( index ); if( mn ) { return mn->SEE(); } else { diff --git a/src/clstepcore/instmgr.h b/src/clstepcore/instmgr.h index 34fc7f1c6..aa638028d 100644 --- a/src/clstepcore/instmgr.h +++ b/src/clstepcore/instmgr.h @@ -73,8 +73,10 @@ class SC_CORE_EXPORT InstMgr { // DAS PORT possible BUG two funct's below may create a temp for the cast MgrNode * GetMgrNode( int index ) { - return ( MgrNode * ) * GetGenNode( index ); + return ( MgrNode * ) master->GetGenNode( index ); } + // Is avoided since the address of an index might change if a Check() + // operation is done by same / different thread. GenericNode ** GetGenNode( int index ) { return &( *master ) [index]; } diff --git a/src/clutils/gennodearray.cc b/src/clutils/gennodearray.cc index 3b039fc0c..a08abbf09 100644 --- a/src/clutils/gennodearray.cc +++ b/src/clutils/gennodearray.cc @@ -35,6 +35,16 @@ GenNodeArray::~GenNodeArray() { delete [] _buf; } +GenericNode * GenNodeArray::GetGenNode( int index ) { + GenericNode * gn; + if( 0 <= index && index < _count ) { + gn = _buf[index]; + } else { + gn = 0; + } + return gn; +} + int GenNodeArray::Index( GenericNode ** gn ) { return ( ( gn - _buf ) / sizeof( GenericNode * ) ); } diff --git a/src/clutils/gennodearray.h b/src/clutils/gennodearray.h index 4c0ee075a..5458f7231 100644 --- a/src/clutils/gennodearray.h +++ b/src/clutils/gennodearray.h @@ -44,7 +44,12 @@ class SC_UTILS_EXPORT GenNodeArray { GenNodeArray( int defaultSize = ARRAY_DEFAULT_SIZE ); virtual ~GenNodeArray(); + // Should be avoided as index to address mapping may + // not remain same (especially) when multiple threads + // are involved. Use GetGenNode instead GenericNode *& operator[]( int index ); + + virtual GenericNode * GetGenNode( int index ); virtual int Index( GenericNode * gn ); virtual int Index( GenericNode ** gn ); @@ -69,6 +74,7 @@ class SC_UTILS_EXPORT GenNodeArray { // class GenNodeArray inline public functions ////////////////////////////////////////////////////////////////////////////// +// Should be avoided as the check function may move the element of the array inline GenericNode *& GenNodeArray::operator[]( int index ) { Check( index ); return _buf[index]; From 29ec4e33e10a5146a740d0e0b36821b09ae752a0 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 18 Jun 2014 22:34:02 +0530 Subject: [PATCH 045/111] Minor refractoring in MgrNodeArray This will be helpful when we introduce a mutex in GenNodeArray. --- src/clstepcore/mgrnodearray.cc | 6 ++++++ src/clstepcore/mgrnodearray.h | 6 ++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/clstepcore/mgrnodearray.cc b/src/clstepcore/mgrnodearray.cc index 23069f02b..88f5ae3d6 100644 --- a/src/clstepcore/mgrnodearray.cc +++ b/src/clstepcore/mgrnodearray.cc @@ -102,6 +102,12 @@ int MgrNodeArray::Insert( GenericNode * gn, int index ) { /*****************************************************************************/ +int MgrNodeArray::Insert( GenericNode * gn ) { + return Insert( gn, _count ); +} + +/*****************************************************************************/ + void MgrNodeArray::Remove( int index ) { if( debug_level >= PrintFunctionTrace ) { cout << "MgrNodeArray::Remove()\n"; diff --git a/src/clstepcore/mgrnodearray.h b/src/clstepcore/mgrnodearray.h index 22019d071..2a6e2b59a 100644 --- a/src/clstepcore/mgrnodearray.h +++ b/src/clstepcore/mgrnodearray.h @@ -48,11 +48,9 @@ class SC_CORE_EXPORT MgrNodeArray : public GenNodeArray { // MgrNodeArray::Insert(GenericNode *, int index); virtual int Insert( GenericNode * gn, int index ); virtual void Append( GenericNode * gn ) { - Insert( gn, _count ); - } - virtual int Insert( GenericNode * gn ) { - return Insert( gn, _count ); + Insert( gn ); } + virtual int Insert( GenericNode * gn ); virtual void Remove( int index ); virtual void ClearEntries(); virtual void DeleteEntries(); From 2a4d42e5965956b5c6198c2592bc39d60aca94a5 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 18 Jun 2014 22:43:31 +0530 Subject: [PATCH 046/111] Added std_recursive_mutex in GenNodeArray. Also modified classes which inherit the above accordingly --- src/clstepcore/mgrnodearray.cc | 48 +++++++++++++++++++++++++++++----- src/clutils/gennodearray.cc | 26 ++++++++++++++++-- src/clutils/gennodearray.h | 2 ++ 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/clstepcore/mgrnodearray.cc b/src/clstepcore/mgrnodearray.cc index 88f5ae3d6..ac4f40ef3 100644 --- a/src/clstepcore/mgrnodearray.cc +++ b/src/clstepcore/mgrnodearray.cc @@ -50,7 +50,9 @@ MgrNodeArray::MgrNodeArray( int defaultSize ) void MgrNodeArray::AssignIndexAddress( int index ) { // if(debug_level >= PrintFunctionTrace) // cout << "MgrNodeArray::AssignIndexAddress()\n"; + mtx.lock(); ( ( MgrNode * )_buf[index] )->ArrayIndex( index ); + mtx.unlock(); } MgrNodeArray::~MgrNodeArray() { @@ -66,11 +68,13 @@ void MgrNodeArray::ClearEntries() { if( debug_level >= PrintFunctionTrace ) { cout << "MgrNodeArray::ClearEntries()\n"; } + mtx.lock(); int i; for( i = 0 ; i < _count; i++ ) { _buf[i] = 0; } _count = 0; + mtx.unlock(); } /*****************************************************************************/ @@ -79,11 +83,13 @@ void MgrNodeArray::DeleteEntries() { if( debug_level >= PrintFunctionTrace ) { cout << "MgrNodeArray::DeleteEntries()\n"; } + mtx.lock(); int i; for( i = 0 ; i < _count; i++ ) { delete( ( MgrNode * )_buf[i] ); } _count = 0; + mtx.unlock(); } /*****************************************************************************/ @@ -92,18 +98,23 @@ int MgrNodeArray::Insert( GenericNode * gn, int index ) { if( debug_level >= PrintFunctionTrace ) { cout << "MgrNodeArray::Insert()\n"; } + mtx.lock(); int AssignedIndex = GenNodeArray::Insert( gn, index ); int i; for( i = AssignedIndex ; i < _count; i++ ) { ( ( MgrNode * )_buf[i] )->ArrayIndex( i ); } + mtx.unlock(); return AssignedIndex; } /*****************************************************************************/ int MgrNodeArray::Insert( GenericNode * gn ) { - return Insert( gn, _count ); + mtx.lock(); + int index = Insert( gn, _count ); + mtx.unlock(); + return index; } /*****************************************************************************/ @@ -112,6 +123,7 @@ void MgrNodeArray::Remove( int index ) { if( debug_level >= PrintFunctionTrace ) { cout << "MgrNodeArray::Remove()\n"; } + mtx.lock(); if( 0 <= index && index < _count ) { GenNodeArray::Remove( index ); int i; @@ -119,6 +131,7 @@ void MgrNodeArray::Remove( int index ) { ( ( MgrNode * )_buf[i] )->ArrayIndex( i ); } } + mtx.unlock(); } /*****************************************************************************/ @@ -127,12 +140,15 @@ int MgrNodeArray::MgrNodeIndex( int fileId ) { if( debug_level >= PrintFunctionTrace ) { cout << "MgrNodeArray::MgrNodeIndex()\n"; } + mtx.lock(); int i; for( i = 0; i < _count; ++i ) { if( ( ( MgrNode * )_buf[i] )->GetApplication_instance()->GetFileId() == fileId ) { + mtx.unlock(); return i; } } + mtx.unlock(); return -1; } @@ -149,36 +165,47 @@ int MgrNodeArraySorted::Insert( GenericNode * gn ) { // cout << "MgrNodeArraySorted::Insert()\n"; // since gn is really a MgrNode + mtx.lock(); int fileId = ( ( MgrNode * )gn )->GetApplication_instance()->GetFileId(); int index = FindInsertPosition( fileId ); + index = GenNodeArray::Insert( gn, index ); + mtx.unlock(); - return GenNodeArray::Insert( gn, index ); + return index; } int MgrNodeArraySorted::Index( GenericNode * gn ) { // if(debug_level >= PrintFunctionTrace) // cout << "MgrNodeArraySorted::Index()\n"; // since gn is really a MgrNode - return MgrNodeIndex( ( ( MgrNode * )gn )->GetFileId() ); + mtx.lock(); + int index = MgrNodeIndex( ( ( MgrNode * )gn )->GetFileId() ); + mtx.unlock(); + return index; } int MgrNodeArraySorted::Index( GenericNode ** gn ) { // if(debug_level >= PrintFunctionTrace) // cout << "MgrNodeArraySorted::Index()\n"; // since gn is really a MgrNode - return MgrNodeIndex( ( ( MgrNode * )( *gn ) )->GetFileId() ); + mtx.lock(); + int index = MgrNodeIndex( ( ( MgrNode * )( *gn ) )->GetFileId() ); + mtx.unlock(); + return index; } void MgrNodeArraySorted::ClearEntries() { if( debug_level >= PrintFunctionTrace ) { cout << "MgrNodeArraySorted::ClearEntries()\n"; } + mtx.lock(); int i; for( i = 0 ; i < _count; i++ ) { _buf[i] = 0; } _count = 0; + mtx.unlock(); } /*****************************************************************************/ @@ -188,10 +215,12 @@ void MgrNodeArraySorted::DeleteEntries() { cout << "MgrNodeArraySorted::DeleteEntries()\n"; } int i; + mtx.lock(); for( i = 0 ; i < _count; i++ ) { delete( ( MgrNode * )_buf[i] ); } _count = 0; + mtx.unlock(); } /*****************************************************************************/ @@ -206,12 +235,15 @@ int MgrNodeArraySorted::FindInsertPosition( const int fileId ) { int i; int curFileId; + mtx.lock(); for( i = _count - 1; i >= 0; --i ) { curFileId = ( ( MgrNode * )_buf[i] )->GetApplication_instance()->GetFileId(); if( curFileId < fileId /*|| curFileId == fileId*/ ) { + mtx.unlock(); return i + 1; } } + mtx.unlock(); return 0; } @@ -230,6 +262,7 @@ int MgrNodeArraySorted::MgrNodeIndex( int fileId ) { int found = 0; int curFileId; + mtx.lock(); while( !found && ( low <= high ) ) { mid = ( low + high ) / 2; curFileId = ( ( MgrNode * )_buf[mid] )->GetApplication_instance()->GetFileId(); @@ -241,8 +274,9 @@ int MgrNodeArraySorted::MgrNodeIndex( int fileId ) { high = mid - 1; } } - if( found ) { - return mid; + if( !found ) { + mid = -1; } - return -1; + mtx.unlock(); + return mid; } diff --git a/src/clutils/gennodearray.cc b/src/clutils/gennodearray.cc index a08abbf09..7ef155b48 100644 --- a/src/clutils/gennodearray.cc +++ b/src/clutils/gennodearray.cc @@ -37,30 +37,41 @@ GenNodeArray::~GenNodeArray() { GenericNode * GenNodeArray::GetGenNode( int index ) { GenericNode * gn; + mtx.lock(); if( 0 <= index && index < _count ) { gn = _buf[index]; } else { gn = 0; } + mtx.unlock(); return gn; } int GenNodeArray::Index( GenericNode ** gn ) { - return ( ( gn - _buf ) / sizeof( GenericNode * ) ); + mtx.lock(); + int index = ( ( gn - _buf ) / sizeof( GenericNode * ) ); + mtx.unlock(); + return index; } void GenNodeArray::Append( GenericNode * gn ) { + mtx.lock(); Insert( gn, _count ); + mtx.unlock(); } int GenNodeArray::Insert( GenericNode * gn ) { - return Insert( gn, _count ); + mtx.lock(); + int index = Insert( gn, _count ); + mtx.unlock(); + return index; } void GenNodeArray::Check( int index ) { GenericNode ** newbuf; + mtx.lock(); if( index >= _bufsize ) { _bufsize = ( index + 1 ) * 2; newbuf = new GenericNode*[_bufsize]; @@ -70,11 +81,13 @@ GenNodeArray::Check( int index ) { delete [] _buf; _buf = newbuf; } + mtx.unlock(); } int GenNodeArray::Insert( GenericNode * gn, int index ) { const GenericNode ** spot; + mtx.lock(); index = ( index < 0 ) ? _count : index; if( index < _count ) { @@ -88,42 +101,51 @@ GenNodeArray::Insert( GenericNode * gn, int index ) { } *spot = gn; ++_count; + mtx.unlock(); return index; } void GenNodeArray::Remove( int index ) { + mtx.lock(); if( 0 <= index && index < _count ) { --_count; const GenericNode ** spot = ( const GenericNode ** )&_buf[index]; memmove( spot, spot + 1, ( _count - index )*sizeof( GenericNode * ) ); _buf[_count] = 0; } + mtx.unlock(); } void GenNodeArray::ClearEntries() { int i; + mtx.lock(); for( i = 0 ; i < _count; i++ ) { _buf[i] = 0; } _count = 0; + mtx.unlock(); } void GenNodeArray::DeleteEntries() { int i; + mtx.lock(); for( i = 0 ; i < _count; i++ ) { delete( _buf[i] ); } _count = 0; + mtx.unlock(); } int GenNodeArray::Index( GenericNode * gn ) { + mtx.lock(); for( int i = 0; i < _count; ++i ) { if( _buf[i] == gn ) { return i; } } + mtx.unlock(); return -1; } diff --git a/src/clutils/gennodearray.h b/src/clutils/gennodearray.h index 5458f7231..dcbbaec07 100644 --- a/src/clutils/gennodearray.h +++ b/src/clutils/gennodearray.h @@ -25,6 +25,7 @@ #include #include #include // to get bcopy for CenterLine +#include #include @@ -68,6 +69,7 @@ class SC_UTILS_EXPORT GenNodeArray { GenericNode ** _buf; // the array int _bufsize; // the possible number of entries in the array int _count; // the number of entries in the array + sc_recursive_mutex mtx; }; ////////////////////////////////////////////////////////////////////////////// From dc8e00b7943713bc4b71da20fbfea8967b412b40 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 22 Jun 2014 21:52:15 +0530 Subject: [PATCH 047/111] Added Dictionary_instance__set This class is intended to be a superclass of all the *__set classes. This will help to removve duplicate code --- src/clstepcore/ExpDict.cc | 89 +++++++++++++++++++++++++++++++++++++++ src/clstepcore/ExpDict.h | 26 ++++++++++++ 2 files changed, 115 insertions(+) diff --git a/src/clstepcore/ExpDict.cc b/src/clstepcore/ExpDict.cc index 7bafe9d03..e07aabc90 100644 --- a/src/clstepcore/ExpDict.cc +++ b/src/clstepcore/ExpDict.cc @@ -21,6 +21,95 @@ #include "sc_memmgr.h" +Dictionary_instance__set::Dictionary_instance__set( int defaultSize ) { + _bufsize = defaultSize; + _buf = new Dictionary_instance_ptr[_bufsize]; + _count = 0; +} + +Dictionary_instance__set::~Dictionary_instance__set() { + delete[] _buf; +} + +void Dictionary_instance__set::Check( int index ) { + Dictionary_instance_ptr * newbuf; + + if( index >= _bufsize ) { + _bufsize = ( index + 1 ) * 2; + newbuf = new Dictionary_instance_ptr[_bufsize]; + memmove( newbuf, _buf, _count * sizeof( Dictionary_instance_ptr ) ); + delete[] _buf; + _buf = newbuf; + } +} + +void Dictionary_instance__set::Insert( Dictionary_instance_ptr v, int index ) { + Dictionary_instance_ptr * spot; + index = ( index < 0 ) ? _count : index; + + if( index < _count ) { + Check( _count + 1 ); + spot = &_buf[index]; + memmove( spot + 1, spot, ( _count - index )*sizeof( Dictionary_instance_ptr ) ); + + } else { + Check( index ); + spot = &_buf[index]; + } + *spot = v; + ++_count; +} + +void Dictionary_instance__set::Append( Dictionary_instance_ptr v ) { + int index = _count; + Dictionary_instance_ptr * spot; + + if( index < _count ) { + Check( _count + 1 ); + spot = &_buf[index]; + memmove( spot + 1, spot, ( _count - index )*sizeof( Dictionary_instance_ptr ) ); + + } else { + Check( index ); + spot = &_buf[index]; + } + *spot = v; + ++_count; +} + +void Dictionary_instance__set::Remove( int index ) { + if( 0 <= index && index < _count ) { + --_count; + Dictionary_instance_ptr * spot = &_buf[index]; + memmove( spot, spot + 1, ( _count - index )*sizeof( Dictionary_instance_ptr ) ); + } +} + +int Dictionary_instance__set::Index( Dictionary_instance_ptr v ) { + for( int i = 0; i < _count; ++i ) { + if( _buf[i] == v ) { + return i; + } + } + return -1; +} + +Dictionary_instance_ptr & Dictionary_instance__set::operator[]( int index ) { + Check( index ); + _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); + return _buf[index]; +} + +int Dictionary_instance__set::Count() { + return _count; +} + +void Dictionary_instance__set::Clear() { + _count = 0; +} + +/////////////////////////////////////////////////////////////////////////////// + Explicit_item_id__set::Explicit_item_id__set( int defaultSize ) { _bufsize = defaultSize; _buf = new Explicit_item_id_ptr[_bufsize]; diff --git a/src/clstepcore/ExpDict.h b/src/clstepcore/ExpDict.h index 39da0facb..a8dc74dd6 100644 --- a/src/clstepcore/ExpDict.h +++ b/src/clstepcore/ExpDict.h @@ -63,6 +63,32 @@ class SC_CORE_EXPORT Dictionary_instance { virtual ~Dictionary_instance(); }; + +typedef Dictionary_instance * Dictionary_instance_ptr; + +/////////////////////////////////////////////////////////////////////////////// + +class SC_CORE_EXPORT Dictionary_instance__set { + public: + Dictionary_instance__set( int = 16 ); + ~Dictionary_instance__set(); + + Dictionary_instance_ptr & operator[]( int index ); + virtual void Insert( Dictionary_instance_ptr, int index ); + virtual void Append( Dictionary_instance_ptr ); + virtual void Remove( int index ); + virtual int Index( Dictionary_instance_ptr ); + + virtual int Count(); + virtual void Clear(); + private: + virtual void Check( int index ); + protected: + Dictionary_instance_ptr * _buf; + int _bufsize; + int _count; +}; + /////////////////////////////////////////////////////////////////////////////// class SC_CORE_EXPORT TypeDescLinkNode : public SingleLinkNode { From 3db2ab29c0d54b8b55cb8460a60ed0de58a2d840 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 22 Jun 2014 21:56:39 +0530 Subject: [PATCH 048/111] Took Dependency on Dictionary_instance__set Explicit_item_id__set, Implicit_item_id__set, Interface_spec__set, Global_rule__set and Uniqueness_rule__set became subclass of Dictionary_instance__set. Lot of Duplicated code was removed this way --- src/clstepcore/ExpDict.cc | 402 ++------------------------------------ src/clstepcore/ExpDict.h | 71 +------ 2 files changed, 17 insertions(+), 456 deletions(-) diff --git a/src/clstepcore/ExpDict.cc b/src/clstepcore/ExpDict.cc index e07aabc90..17fbd64e1 100644 --- a/src/clstepcore/ExpDict.cc +++ b/src/clstepcore/ExpDict.cc @@ -110,269 +110,38 @@ void Dictionary_instance__set::Clear() { /////////////////////////////////////////////////////////////////////////////// -Explicit_item_id__set::Explicit_item_id__set( int defaultSize ) { - _bufsize = defaultSize; - _buf = new Explicit_item_id_ptr[_bufsize]; - _count = 0; +Explicit_item_id__set::Explicit_item_id__set( int defaultSize ) : Dictionary_instance__set( defaultSize ) { } Explicit_item_id__set::~Explicit_item_id__set() { - delete[] _buf; -} - -void Explicit_item_id__set::Check( int index ) { - Explicit_item_id_ptr * newbuf; - - if( index >= _bufsize ) { - _bufsize = ( index + 1 ) * 2; - newbuf = new Explicit_item_id_ptr[_bufsize]; - memmove( newbuf, _buf, _count * sizeof( Explicit_item_id_ptr ) ); - delete[] _buf; - _buf = newbuf; - } -} - -void Explicit_item_id__set::Insert( Explicit_item_id_ptr v, int index ) { - Explicit_item_id_ptr * spot; - index = ( index < 0 ) ? _count : index; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( Explicit_item_id_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void Explicit_item_id__set::Append( Explicit_item_id_ptr v ) { - int index = _count; - Explicit_item_id_ptr * spot; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( Explicit_item_id_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void Explicit_item_id__set::Remove( int index ) { - if( 0 <= index && index < _count ) { - --_count; - Explicit_item_id_ptr * spot = &_buf[index]; - memmove( spot, spot + 1, ( _count - index )*sizeof( Explicit_item_id_ptr ) ); - } -} - -int Explicit_item_id__set::Index( Explicit_item_id_ptr v ) { - for( int i = 0; i < _count; ++i ) { - if( _buf[i] == v ) { - return i; - } - } - return -1; } Explicit_item_id_ptr & Explicit_item_id__set::operator[]( int index ) { - Check( index ); - _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); - return _buf[index]; -} - -int Explicit_item_id__set::Count() { - return _count; -} - -void Explicit_item_id__set::Clear() { - _count = 0; } /////////////////////////////////////////////////////////////////////////////// -Implicit_item_id__set::Implicit_item_id__set( int defaultSize ) { - _bufsize = defaultSize; - _buf = new Implicit_item_id_ptr[_bufsize]; - _count = 0; -} - -Implicit_item_id__set::~Implicit_item_id__set() { - delete[] _buf; +Implicit_item_id__set::Implicit_item_id__set( int defaultSize ) : Dictionary_instance__set( defaultSize ) { } -void Implicit_item_id__set::Check( int index ) { - Implicit_item_id_ptr * newbuf; - if( index >= _bufsize ) { - _bufsize = ( index + 1 ) * 2; - newbuf = new Implicit_item_id_ptr[_bufsize]; - memmove( newbuf, _buf, _count * sizeof( Implicit_item_id_ptr ) ); - delete[]_buf; - _buf = newbuf; - } -} - -void Implicit_item_id__set::Insert( Implicit_item_id_ptr v, int index ) { - Implicit_item_id_ptr * spot; - index = ( index < 0 ) ? _count : index; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( Implicit_item_id_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void Implicit_item_id__set::Append( Implicit_item_id_ptr v ) { - int index = _count; - Implicit_item_id_ptr * spot; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( Implicit_item_id_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void Implicit_item_id__set::Remove( int index ) { - if( 0 <= index && index < _count ) { - --_count; - Implicit_item_id_ptr * spot = &_buf[index]; - memmove( spot, spot + 1, ( _count - index )*sizeof( Implicit_item_id_ptr ) ); - } -} - -int Implicit_item_id__set::Index( Implicit_item_id_ptr v ) { - for( int i = 0; i < _count; ++i ) { - if( _buf[i] == v ) { - return i; - } - } - return -1; +Implicit_item_id__set::~Implicit_item_id__set() { } Implicit_item_id_ptr & Implicit_item_id__set::operator[]( int index ) { - Check( index ); - _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); - return _buf[index]; -} - -int Implicit_item_id__set::Count() { - return _count; -} - -void Implicit_item_id__set::Clear() { - _count = 0; + return ( Implicit_item_id_ptr & )Dictionary_instance__set::operator[]( index ); } /////////////////////////////////////////////////////////////////////////////// -Interface_spec__set::Interface_spec__set( int defaultSize ) { - _bufsize = defaultSize; - _buf = new Interface_spec_ptr[_bufsize]; - _count = 0; +Interface_spec__set::Interface_spec__set( int defaultSize ) : Dictionary_instance__set( defaultSize ) { } Interface_spec__set::~Interface_spec__set() { - delete[] _buf; -} - -void Interface_spec__set::Check( int index ) { - Interface_spec_ptr * newbuf; - - if( index >= _bufsize ) { - _bufsize = ( index + 1 ) * 2; - newbuf = new Interface_spec_ptr[_bufsize]; - memmove( newbuf, _buf, _count * sizeof( Interface_spec_ptr ) ); - delete[] _buf; - _buf = newbuf; - } -} - -void Interface_spec__set::Insert( Interface_spec_ptr v, int index ) { - Interface_spec_ptr * spot; - index = ( index < 0 ) ? _count : index; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( Interface_spec_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void Interface_spec__set::Append( Interface_spec_ptr v ) { - int index = _count; - Interface_spec_ptr * spot; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( Interface_spec_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void Interface_spec__set::Remove( int index ) { - if( 0 <= index && index < _count ) { - --_count; - Interface_spec_ptr * spot = &_buf[index]; - memmove( spot, spot + 1, ( _count - index )*sizeof( Interface_spec_ptr ) ); - } -} - -int Interface_spec__set::Index( Interface_spec_ptr v ) { - for( int i = 0; i < _count; ++i ) { - if( _buf[i] == v ) { - return i; - } - } - return -1; } Interface_spec_ptr & Interface_spec__set::operator[]( int index ) { - Check( index ); - _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); - return _buf[index]; -} - -int Interface_spec__set::Count() { - return _count; -} - -void Interface_spec__set::Clear() { - _count = 0; + return ( Interface_spec_ptr & )Dictionary_instance__set::operator[]( index ); } /////////////////////////////////////////////////////////////////////////////// @@ -1223,94 +992,20 @@ Uniqueness_rule::~Uniqueness_rule() { /////////////////////////////////////////////////////////////////////////////// -Uniqueness_rule__set::Uniqueness_rule__set( int defaultSize ) { - _bufsize = defaultSize; - _buf = new Uniqueness_rule_ptr[_bufsize]; - _count = 0; +Uniqueness_rule__set::Uniqueness_rule__set( int defaultSize ) : Dictionary_instance__set( defaultSize ) { } Uniqueness_rule__set::~Uniqueness_rule__set() { Clear(); - - delete[] _buf; -} - -void Uniqueness_rule__set::Check( int index ) { - Uniqueness_rule_ptr * newbuf; - - if( index >= _bufsize ) { - _bufsize = ( index + 1 ) * 2; - newbuf = new Uniqueness_rule_ptr[_bufsize]; - memmove( newbuf, _buf, _count * sizeof( Uniqueness_rule_ptr ) ); - delete[] _buf; - _buf = newbuf; - } -} - -void Uniqueness_rule__set::Insert( Uniqueness_rule_ptr v, int index ) { - Uniqueness_rule_ptr * spot; - index = ( index < 0 ) ? _count : index; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( Uniqueness_rule_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void Uniqueness_rule__set::Append( Uniqueness_rule_ptr v ) { - int index = _count; - Uniqueness_rule_ptr * spot; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( Uniqueness_rule_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void Uniqueness_rule__set::Remove( int index ) { - if( 0 <= index && index < _count ) { - --_count; - Uniqueness_rule_ptr * spot = &_buf[index]; - memmove( spot, spot + 1, ( _count - index )*sizeof( Uniqueness_rule_ptr ) ); - } -} - -int Uniqueness_rule__set::Index( Uniqueness_rule_ptr v ) { - for( int i = 0; i < _count; ++i ) { - if( _buf[i] == v ) { - return i; - } - } - return -1; } Uniqueness_rule_ptr & Uniqueness_rule__set::operator[]( int index ) { - Check( index ); - _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); - return _buf[index]; -} - -int Uniqueness_rule__set::Count() { - return _count; + return ( Uniqueness_rule_ptr & )Dictionary_instance__set::operator[]( index ); } void Uniqueness_rule__set::Clear() { for( int i = 0; i < _count; i ++ ) { - delete _buf[i]; + delete ( Uniqueness_rule_ptr )_buf[i]; } _count = 0; } @@ -1359,93 +1054,20 @@ void Global_rule::where_rules_( const Where_rule__list_var & wrl ) { /////////////////////////////////////////////////////////////////////////////// -Global_rule__set::Global_rule__set( int defaultSize ) { - _bufsize = defaultSize; - _buf = new Global_rule_ptr[_bufsize]; - _count = 0; +Global_rule__set::Global_rule__set( int defaultSize ) : Dictionary_instance__set( defaultSize ) { } Global_rule__set::~Global_rule__set() { Clear(); - delete[] _buf; -} - -void Global_rule__set::Check( int index ) { - Global_rule_ptr * newbuf; - - if( index >= _bufsize ) { - _bufsize = ( index + 1 ) * 2; - newbuf = new Global_rule_ptr[_bufsize]; - memmove( newbuf, _buf, _count * sizeof( Global_rule_ptr ) ); - delete[] _buf; - _buf = newbuf; - } -} - -void Global_rule__set::Insert( Global_rule_ptr v, int index ) { - Global_rule_ptr * spot; - index = ( index < 0 ) ? _count : index; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( Global_rule_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void Global_rule__set::Append( Global_rule_ptr v ) { - int index = _count; - Global_rule_ptr * spot; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( Global_rule_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void Global_rule__set::Remove( int index ) { - if( 0 <= index && index < _count ) { - --_count; - Global_rule_ptr * spot = &_buf[index]; - memmove( spot, spot + 1, ( _count - index )*sizeof( Global_rule_ptr ) ); - } -} - -int Global_rule__set::Index( Global_rule_ptr v ) { - for( int i = 0; i < _count; ++i ) { - if( _buf[i] == v ) { - return i; - } - } - return -1; } Global_rule_ptr & Global_rule__set::operator[]( int index ) { - Check( index ); - _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); - return _buf[index]; -} - -int Global_rule__set::Count() { - return _count; + return ( Global_rule_ptr & )Dictionary_instance__set::operator[]( index ); } void Global_rule__set::Clear() { for( int i = 0; i < _count; i ++ ) { - delete _buf[i]; + delete ( Global_rule_ptr )_buf[i]; } _count = 0; } diff --git a/src/clstepcore/ExpDict.h b/src/clstepcore/ExpDict.h index a8dc74dd6..26172c601 100644 --- a/src/clstepcore/ExpDict.h +++ b/src/clstepcore/ExpDict.h @@ -312,25 +312,12 @@ class SC_CORE_EXPORT Referenced_item : public Explicit_item_id { typedef Referenced_item * Referenced_item_ptr; -class SC_CORE_EXPORT Explicit_item_id__set { +class SC_CORE_EXPORT Explicit_item_id__set : public Dictionary_instance__set { public: Explicit_item_id__set( int = 16 ); ~Explicit_item_id__set(); Explicit_item_id_ptr & operator[]( int index ); - void Insert( Explicit_item_id_ptr, int index ); - void Append( Explicit_item_id_ptr ); - void Remove( int index ); - int Index( Explicit_item_id_ptr ); - - int Count(); - void Clear(); - private: - void Check( int index ); - private: - Explicit_item_id_ptr * _buf; - int _bufsize; - int _count; }; typedef Explicit_item_id__set * Explicit_item_id__set_ptr; @@ -364,25 +351,12 @@ typedef Implicit_item_id * Implicit_item_id_ptr; // Implicit_item_id__set /////////////////////////////////////////////////////////////////////////////// -class SC_CORE_EXPORT Implicit_item_id__set { +class SC_CORE_EXPORT Implicit_item_id__set : public Dictionary_instance__set { public: Implicit_item_id__set( int = 16 ); ~Implicit_item_id__set(); Implicit_item_id_ptr & operator[]( int index ); - void Insert( Implicit_item_id_ptr, int index ); - void Append( Implicit_item_id_ptr ); - void Remove( int index ); - int Index( Implicit_item_id_ptr ); - - int Count(); - void Clear(); - private: - void Check( int index ); - private: - Implicit_item_id_ptr * _buf; - int _bufsize; - int _count; }; typedef Implicit_item_id__set * Implicit_item_id__set_ptr; @@ -449,25 +423,12 @@ class SC_CORE_EXPORT Interface_spec : public Dictionary_instance { typedef Interface_spec * Interface_spec_ptr; -class SC_CORE_EXPORT Interface_spec__set { +class SC_CORE_EXPORT Interface_spec__set : public Dictionary_instance__set { public: Interface_spec__set( int = 16 ); ~Interface_spec__set(); Interface_spec_ptr & operator[]( int index ); - void Insert( Interface_spec_ptr, int index ); - void Append( Interface_spec_ptr ); - void Remove( int index ); - int Index( Interface_spec_ptr ); - - int Count(); - void Clear(); - private: - void Check( int index ); - private: - Interface_spec_ptr * _buf; - int _bufsize; - int _count; }; typedef Interface_spec__set * Interface_spec__set_ptr; @@ -592,25 +553,14 @@ class SC_CORE_EXPORT Global_rule : public Dictionary_instance { typedef Global_rule * Global_rule_ptr; -class SC_CORE_EXPORT Global_rule__set { +class SC_CORE_EXPORT Global_rule__set : public Dictionary_instance__set { public: Global_rule__set( int = 16 ); ~Global_rule__set(); Global_rule_ptr & operator[]( int index ); - void Insert( Global_rule_ptr, int index ); - void Append( Global_rule_ptr ); - void Remove( int index ); - int Index( Global_rule_ptr ); - int Count(); void Clear(); - private: - void Check( int index ); - private: - Global_rule_ptr * _buf; - int _bufsize; - int _count; }; typedef Global_rule__set * Global_rule__set_ptr; @@ -656,25 +606,14 @@ class SC_CORE_EXPORT Uniqueness_rule : public Dictionary_instance { typedef Uniqueness_rule * Uniqueness_rule_ptr; -class SC_CORE_EXPORT Uniqueness_rule__set { +class SC_CORE_EXPORT Uniqueness_rule__set : public Dictionary_instance__set { public: Uniqueness_rule__set( int = 16 ); ~Uniqueness_rule__set(); Uniqueness_rule_ptr & operator[]( int index ); - void Insert( Uniqueness_rule_ptr, int index ); - void Append( Uniqueness_rule_ptr ); - void Remove( int index ); - int Index( Uniqueness_rule_ptr ); - int Count(); void Clear(); - private: - void Check( int index ); - private: - Uniqueness_rule_ptr * _buf; - int _bufsize; - int _count; }; typedef Uniqueness_rule__set * Uniqueness_rule__set_ptr; From e02ce60f9d36841ad482bf11a127567b576eb81b Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 22 Jun 2014 22:11:31 +0530 Subject: [PATCH 049/111] Made Where_rule__list a subclass. The superclass was Dictionary_instance__set --- src/clstepcore/ExpDict.cc | 80 ++------------------------------------- src/clstepcore/ExpDict.h | 13 +------ 2 files changed, 4 insertions(+), 89 deletions(-) diff --git a/src/clstepcore/ExpDict.cc b/src/clstepcore/ExpDict.cc index 17fbd64e1..5c47eb23c 100644 --- a/src/clstepcore/ExpDict.cc +++ b/src/clstepcore/ExpDict.cc @@ -883,94 +883,20 @@ Where_rule::~Where_rule() { /////////////////////////////////////////////////////////////////////////////// -Where_rule__list::Where_rule__list( int defaultSize ) { - _bufsize = defaultSize; - _buf = new Where_rule_ptr[_bufsize]; - _count = 0; +Where_rule__list::Where_rule__list( int defaultSize ) : Dictionary_instance__set( defaultSize ) { } Where_rule__list::~Where_rule__list() { Clear(); - - delete[] _buf; -} - -void Where_rule__list::Check( int index ) { - Where_rule_ptr * newbuf; - - if( index >= _bufsize ) { - _bufsize = ( index + 1 ) * 2; - newbuf = new Where_rule_ptr[_bufsize]; - memmove( newbuf, _buf, _count * sizeof( Where_rule_ptr ) ); - delete[] _buf; - _buf = newbuf; - } -} - -void Where_rule__list::Insert( Where_rule_ptr v, int index ) { - Where_rule_ptr * spot; - index = ( index < 0 ) ? _count : index; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( Where_rule_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void Where_rule__list::Append( Where_rule_ptr v ) { - int index = _count; - Where_rule_ptr * spot; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( Where_rule_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void Where_rule__list::Remove( int index ) { - if( 0 <= index && index < _count ) { - --_count; - Where_rule_ptr * spot = &_buf[index]; - memmove( spot, spot + 1, ( _count - index )*sizeof( Where_rule_ptr ) ); - } -} - -int Where_rule__list::Index( Where_rule_ptr v ) { - for( int i = 0; i < _count; ++i ) { - if( _buf[i] == v ) { - return i; - } - } - return -1; } Where_rule_ptr & Where_rule__list::operator[]( int index ) { - Check( index ); - _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); - return _buf[index]; -} - -int Where_rule__list::Count() { - return _count; + return ( Where_rule_ptr & )Dictionary_instance__set::operator[]( index ); } void Where_rule__list::Clear() { for( int i = 0; i < _count ; i ++ ) { - delete _buf[i]; + delete ( Where_rule_ptr )_buf[i]; } _count = 0; } diff --git a/src/clstepcore/ExpDict.h b/src/clstepcore/ExpDict.h index 26172c601..1aea7f644 100644 --- a/src/clstepcore/ExpDict.h +++ b/src/clstepcore/ExpDict.h @@ -484,25 +484,14 @@ class SC_CORE_EXPORT Where_rule : public Dictionary_instance { typedef Where_rule * Where_rule_ptr; -class SC_CORE_EXPORT Where_rule__list { +class SC_CORE_EXPORT Where_rule__list : public Dictionary_instance__set { public: Where_rule__list( int = 16 ); ~Where_rule__list(); Where_rule_ptr & operator[]( int index ); - void Insert( Where_rule_ptr, int index ); - void Append( Where_rule_ptr ); - void Remove( int index ); - int Index( Where_rule_ptr ); - int Count(); void Clear(); - private: - void Check( int index ); - private: - Where_rule_ptr * _buf; - int _bufsize; - int _count; }; typedef Where_rule__list * Where_rule__list_ptr; From 643da31f92434b47fe19ae330f2351e686d41330 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 23 Jun 2014 17:26:34 +0530 Subject: [PATCH 050/111] Added a missing return statement --- src/clstepcore/ExpDict.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/clstepcore/ExpDict.cc b/src/clstepcore/ExpDict.cc index 5c47eb23c..ee084070f 100644 --- a/src/clstepcore/ExpDict.cc +++ b/src/clstepcore/ExpDict.cc @@ -117,6 +117,7 @@ Explicit_item_id__set::~Explicit_item_id__set() { } Explicit_item_id_ptr & Explicit_item_id__set::operator[]( int index ) { + return ( Explicit_item_id_ptr & )Dictionary_instance__set::operator[]( index ); } /////////////////////////////////////////////////////////////////////////////// From 6b97cbe9066adf8a38b7ab2f8820d37255dd3b36 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 25 Jun 2014 11:37:10 +0530 Subject: [PATCH 051/111] Made SingleLinkList class thread safe This was done by adding a mutex. Also a cmake file was modified inorder to compile the above changes. --- cmake/SC_CXX_schema_macros.cmake | 4 ++++ src/clstepcore/SingleLinkList.cc | 9 +++++++++ src/clstepcore/SingleLinkList.h | 5 +++++ src/clstepcore/SingleLinkList.inline.cc | 5 +++++ 4 files changed, 23 insertions(+) diff --git a/cmake/SC_CXX_schema_macros.cmake b/cmake/SC_CXX_schema_macros.cmake index 346495f1e..748724d0b 100644 --- a/cmake/SC_CXX_schema_macros.cmake +++ b/cmake/SC_CXX_schema_macros.cmake @@ -102,6 +102,10 @@ macro(SCHEMA_TARGETS expFile schemaName sourceFiles) SC_ADDLIB(${PROJECT_NAME} "${sourceFiles}" "stepdai;stepcore;stepeditor;steputils;base" "TESTABLE") add_dependencies(${PROJECT_NAME} generate_cpp_${PROJECT_NAME}) + if(HAVE_STD_THREAD) + set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD") + endif(HAVE_STD_THREAD) + SCHEMA_EXES() SCHEMA_TESTS() P21_TESTS(${expFile}) diff --git a/src/clstepcore/SingleLinkList.cc b/src/clstepcore/SingleLinkList.cc index 79796509e..3851c6935 100644 --- a/src/clstepcore/SingleLinkList.cc +++ b/src/clstepcore/SingleLinkList.cc @@ -12,8 +12,10 @@ #include #include "sc_memmgr.h" +#include void SingleLinkList::DeleteFollowingNodes( SingleLinkNode * item ) { + mtxP->lock(); if( head ) { SingleLinkNode * trailer = 0; SingleLinkNode * leader = head; @@ -42,9 +44,12 @@ void SingleLinkList::DeleteFollowingNodes( SingleLinkNode * item ) { } } } + mtxP->unlock(); } void SingleLinkList::AppendNode( SingleLinkNode * item ) { + mtxP->lock(); + assert( item->owner == 0 && "Item which is to be appended is already inside a list" ); if( head ) { tail -> next = item; tail = item; @@ -52,9 +57,12 @@ void SingleLinkList::AppendNode( SingleLinkNode * item ) { head = tail = item; } item->owner = this; + mtxP->unlock(); } void SingleLinkList::DeleteNode( SingleLinkNode * item ) { + mtxP->lock(); + assert( item->owner == this && "Item which is to be deleted is not inside this list" ); if( head ) { SingleLinkNode * trailer = 0; SingleLinkNode * leader = head; @@ -81,4 +89,5 @@ void SingleLinkList::DeleteNode( SingleLinkNode * item ) { } } } + mtxP->unlock(); } diff --git a/src/clstepcore/SingleLinkList.h b/src/clstepcore/SingleLinkList.h index 33386dd98..c1a2fe621 100644 --- a/src/clstepcore/SingleLinkList.h +++ b/src/clstepcore/SingleLinkList.h @@ -13,6 +13,7 @@ */ #include +#include class SC_CORE_EXPORT SingleLinkList { @@ -24,6 +25,10 @@ class SC_CORE_EXPORT SingleLinkList { class SingleLinkNode * head; SingleLinkNode * tail; + // had to be made into a pointer due to the equality + // operator being used elswhere for SingleLinkList object + sc_mutex * mtxP; + public: virtual SingleLinkNode * NewNode(); diff --git a/src/clstepcore/SingleLinkList.inline.cc b/src/clstepcore/SingleLinkList.inline.cc index 3a5c4815a..256b49287 100644 --- a/src/clstepcore/SingleLinkList.inline.cc +++ b/src/clstepcore/SingleLinkList.inline.cc @@ -21,6 +21,7 @@ SingleLinkNode::NextNode() const { SingleLinkList::SingleLinkList() : head( 0 ), tail( 0 ) { + mtxP = new sc_mutex(); } SingleLinkList::~SingleLinkList() { @@ -28,12 +29,14 @@ SingleLinkList::~SingleLinkList() { } void SingleLinkList::Empty() { + mtxP->lock(); SingleLinkNode * tmp = head; while( tmp ) { tmp = head -> NextNode(); delete head; head = tmp; } + mtxP->unlock(); } SingleLinkNode * SingleLinkList::NewNode() { @@ -51,9 +54,11 @@ int SingleLinkList::EntryCount() const { int entryCount = 0; SingleLinkNode * entryPtr = head; + mtxP->lock(); while( entryPtr != 0 ) { entryPtr = entryPtr->NextNode(); entryCount++; } + mtxP->unlock(); return entryCount; } From cf9a203988b807651b6cb9ec521dfa109653a57f Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 25 Jun 2014 11:45:08 +0530 Subject: [PATCH 052/111] Made Dictionary_instance__set thread safe. --- src/clstepcore/ExpDict.cc | 25 ++++++++++++++++++++----- src/clstepcore/ExpDict.h | 2 ++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/clstepcore/ExpDict.cc b/src/clstepcore/ExpDict.cc index ee084070f..4d5b9bb7b 100644 --- a/src/clstepcore/ExpDict.cc +++ b/src/clstepcore/ExpDict.cc @@ -34,6 +34,7 @@ Dictionary_instance__set::~Dictionary_instance__set() { void Dictionary_instance__set::Check( int index ) { Dictionary_instance_ptr * newbuf; + mtx.lock(); if( index >= _bufsize ) { _bufsize = ( index + 1 ) * 2; newbuf = new Dictionary_instance_ptr[_bufsize]; @@ -41,12 +42,14 @@ void Dictionary_instance__set::Check( int index ) { delete[] _buf; _buf = newbuf; } + mtx.unlock(); } void Dictionary_instance__set::Insert( Dictionary_instance_ptr v, int index ) { Dictionary_instance_ptr * spot; - index = ( index < 0 ) ? _count : index; + mtx.lock(); + index = ( index < 0 ) ? _count : index; if( index < _count ) { Check( _count + 1 ); spot = &_buf[index]; @@ -58,12 +61,14 @@ void Dictionary_instance__set::Insert( Dictionary_instance_ptr v, int index ) { } *spot = v; ++_count; + mtx.unlock(); } void Dictionary_instance__set::Append( Dictionary_instance_ptr v ) { - int index = _count; Dictionary_instance_ptr * spot; + mtx.lock(); + int index = _count; if( index < _count ) { Check( _count + 1 ); spot = &_buf[index]; @@ -75,29 +80,39 @@ void Dictionary_instance__set::Append( Dictionary_instance_ptr v ) { } *spot = v; ++_count; + mtx.unlock(); } void Dictionary_instance__set::Remove( int index ) { + mtx.lock(); if( 0 <= index && index < _count ) { --_count; Dictionary_instance_ptr * spot = &_buf[index]; memmove( spot, spot + 1, ( _count - index )*sizeof( Dictionary_instance_ptr ) ); } + mtx.unlock(); } int Dictionary_instance__set::Index( Dictionary_instance_ptr v ) { + int index = -1; + mtx.lock(); for( int i = 0; i < _count; ++i ) { if( _buf[i] == v ) { - return i; + index = i; + break; } } - return -1; + mtx.unlock(); + return index; } Dictionary_instance_ptr & Dictionary_instance__set::operator[]( int index ) { + mtx.lock(); Check( index ); _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); - return _buf[index]; + Dictionary_instance_ptr & dip = _buf[index]; + mtx.unlock(); + return dip; } int Dictionary_instance__set::Count() { diff --git a/src/clstepcore/ExpDict.h b/src/clstepcore/ExpDict.h index 1aea7f644..1ccacafc5 100644 --- a/src/clstepcore/ExpDict.h +++ b/src/clstepcore/ExpDict.h @@ -40,6 +40,7 @@ enum AggrBoundTypeEnum { #include #include #include +#include // defined and created in Registry.inline.cc extern SC_CORE_EXPORT const TypeDescriptor * t_sdaiINTEGER; @@ -87,6 +88,7 @@ class SC_CORE_EXPORT Dictionary_instance__set { Dictionary_instance_ptr * _buf; int _bufsize; int _count; + sc_recursive_mutex mtx; }; /////////////////////////////////////////////////////////////////////////////// From fe33e5d5cb335599b18b9f1f03bca0f90aedc27a Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 25 Jun 2014 11:51:09 +0530 Subject: [PATCH 053/111] Made Global_rule thread safe by using a mutex. Even though its superclass i.e Dictionary_instance__set was made thread safe, thread safety in functions 'entities_' and 'where_rules_' was being violated --- src/clstepcore/ExpDict.cc | 5 +++++ src/clstepcore/ExpDict.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/clstepcore/ExpDict.cc b/src/clstepcore/ExpDict.cc index 4d5b9bb7b..5f53b8414 100644 --- a/src/clstepcore/ExpDict.cc +++ b/src/clstepcore/ExpDict.cc @@ -975,6 +975,8 @@ Global_rule::~Global_rule() { } void Global_rule::entities_( const Entity__set_var & e ) { + // required to prevent potential double deletion + mtx.lock(); if( _entities ) { if( _entities->EntryCount() > 0 ) { std::cerr << "In " << __FILE__ << ", Global_rule::entities_(): overwriting non-empty entity set!" << std::endl; @@ -982,9 +984,11 @@ void Global_rule::entities_( const Entity__set_var & e ) { delete _entities; } _entities = e; + mtx.unlock(); } void Global_rule::where_rules_( const Where_rule__list_var & wrl ) { + mtx.lock(); if( _where_rules ) { if( _where_rules->Count() > 0 ) { std::cerr << "In " << __FILE__ << ", Global_rule::where_rules_(): overwriting non-empty rule set!" << std::endl; @@ -992,6 +996,7 @@ void Global_rule::where_rules_( const Where_rule__list_var & wrl ) { delete _where_rules; } _where_rules = wrl; + mtx.unlock(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/clstepcore/ExpDict.h b/src/clstepcore/ExpDict.h index 1ccacafc5..619a3fdf1 100644 --- a/src/clstepcore/ExpDict.h +++ b/src/clstepcore/ExpDict.h @@ -500,6 +500,9 @@ typedef Where_rule__list * Where_rule__list_ptr; typedef Where_rule__list_ptr Where_rule__list_var; class SC_CORE_EXPORT Global_rule : public Dictionary_instance { + protected: + sc_mutex mtx; + public: Express_id _name; Entity__set_var _entities; // not implemented From 391180bc2deaf881e10a5484f1fc0e1e39d9aa31 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 25 Jun 2014 11:56:11 +0530 Subject: [PATCH 054/111] Made Schema thread safe by using 3 mutexes. The 3 mutexes were used to protect the _function_list, _procedure_list & _global_rules data structures. The first two are vectors. The last is already a thread safe structure, however its being lazy-initilized hence a mutex is needed. --- src/clstepcore/ExpDict.cc | 9 +++++++++ src/clstepcore/ExpDict.h | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/src/clstepcore/ExpDict.cc b/src/clstepcore/ExpDict.cc index 5f53b8414..8c0b93b6a 100644 --- a/src/clstepcore/ExpDict.cc +++ b/src/clstepcore/ExpDict.cc @@ -196,18 +196,24 @@ Interface_spec::~Interface_spec() { ////////////////////////////////////////////////////////////////////////////// void Schema::AddFunction( const std::string & f ) { + _function_list_mtx.lock(); _function_list.push_back( f ); + _function_list_mtx.unlock(); } void Schema::AddGlobal_rule( Global_rule_ptr gr ) { + // locking here is required to prevent _global_rules from initializing twice + _global_rules_mtx.lock(); if( _global_rules == 0 ) { _global_rules = new Global_rule__set; } _global_rules->Append( gr ); + _global_rules_mtx.unlock(); } /// hope I did this right (MP) - was "not implemented" void Schema::global_rules_( Global_rule__set_var & grs ) { + _global_rules_mtx.lock(); if( _global_rules ) { if( _global_rules->Count() > 0 ) { std::cerr << "In " << __FILE__ << ", Schema::global_rules_(): overwriting non-empty global rule set!" << std::endl; @@ -215,10 +221,13 @@ void Schema::global_rules_( Global_rule__set_var & grs ) { delete _global_rules; } _global_rules = grs; + _global_rules_mtx.unlock(); } void Schema::AddProcedure( const std::string & p ) { + _procedure_list_mtx.lock(); _procedure_list.push_back( p ); + _procedure_list_mtx.unlock(); } /// the whole schema diff --git a/src/clstepcore/ExpDict.h b/src/clstepcore/ExpDict.h index 619a3fdf1..5529647ea 100644 --- a/src/clstepcore/ExpDict.h +++ b/src/clstepcore/ExpDict.h @@ -635,6 +635,10 @@ class SC_CORE_EXPORT Schema : public Dictionary_instance { Global_rule__set_var _global_rules; + sc_mutex _function_list_mtx; // required as _function_list is a vector + sc_mutex _procedure_list_mtx; // required as _procedure_list is a vector + sc_mutex _global_rules_mtx; // required in AddGlobal_rule function + public: ModelContentsCreator CreateNewModelContents; From 738d1820df08b65bfaaa6f3f2295d4c980bfd8c1 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 25 Jun 2014 12:05:20 +0530 Subject: [PATCH 055/111] Added test to check thread safety of Registry class The Entity, Schema and Type operations are tested. For each, there are 3 checks: Add-Add, Remove-Remove, Add-Remove. For every check the two operation are done first serially and then parallely. Their results are then compared. --- src/clstepcore/CMakeLists.txt | 4 + src/clstepcore/Registry_thread_safety_test.cc | 326 ++++++++++++++++++ 2 files changed, 330 insertions(+) create mode 100644 src/clstepcore/Registry_thread_safety_test.cc diff --git a/src/clstepcore/CMakeLists.txt b/src/clstepcore/CMakeLists.txt index f7c925ca1..d3d3e5551 100644 --- a/src/clstepcore/CMakeLists.txt +++ b/src/clstepcore/CMakeLists.txt @@ -76,6 +76,10 @@ if(HAVE_STD_THREAD) SC_ADDEXEC(InstMgr_thread_safety_test "InstMgr_thread_safety_test.cc" "stepcore" ) set_target_properties(InstMgr_thread_safety_test PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD") target_link_libraries(InstMgr_thread_safety_test "pthread" ) + + SC_ADDEXEC(Registry_thread_safety_test "Registry_thread_safety_test.cc" "stepcore" ) + set_target_properties(Registry_thread_safety_test PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD") + target_link_libraries(Registry_thread_safety_test "pthread" ) endif(HAVE_STD_THREAD) install(FILES ${SC_CLSTEPCORE_HDRS} diff --git a/src/clstepcore/Registry_thread_safety_test.cc b/src/clstepcore/Registry_thread_safety_test.cc new file mode 100644 index 000000000..ed0fe6b64 --- /dev/null +++ b/src/clstepcore/Registry_thread_safety_test.cc @@ -0,0 +1,326 @@ +#include +#include +#include + +#ifdef HAVE_STD_THREAD +# include +#else +# error Need std::thread for this test! +#endif + +#include "ExpDict.h" +#include "baseType.h" +#include "Registry.h" + +enum Mode { + ENTITY = 0, + SCHEMA = 1, + TYPE = 2 +}; +const std::vector< std::string > modeNames { "ENTITY", "SCHEMA", "TYPE" }; + +/// Will be populated in the main function +std::vector< std::string > names; + +/// Needed for constructing a Registry +void dummyInit( Registry & reg ) { + ( void )reg; +} + +/// Adds the elements at the specified indexes from the Registry +void addElements( Registry * reg, Mode mode, int llimit, int ulimit, int stride ) { + int i; + for( i = llimit; i < ulimit; i+=stride ) { + switch( mode ) { + case ENTITY: + reg->AddEntity( *( new EntityDescriptor( names[i].c_str(), ( Schema * ) NULL, LTrue, LFalse ) ) ); + break; + + case SCHEMA: + reg->AddSchema( *( new Schema( names[i].c_str() ) ) ); + break; + + case TYPE: + reg->AddType( *( new TypeDescriptor( names[i].c_str(), UNKNOWN_TYPE, ( Schema * )0, ( char * )0 ) ) ); + break; + } + } +} + +/// Removes the elements at the specified indexes from the Registry +void removeElements( Registry * reg, Mode mode, int llimit, int ulimit, int stride ) { + int i; + for( i = llimit; i < ulimit; i+=stride ) { + switch( mode ) { + case ENTITY: + reg->RemoveEntity( names[i].c_str() ); + break; + + case SCHEMA: + reg->RemoveSchema( names[i].c_str() ); + break; + + case TYPE: + reg->RemoveType( names[i].c_str() ); + break; + } + } +} + +/// compares the elements of the two registry. i.e. either an element should be in both the registries or none of them +bool haveSameElements( Registry * reg1, Registry * reg2 ) { + int i, size = names.size(); + for( i = 0; i < size; i++ ) { + if( ( reg1->FindEntity( names[i].c_str() ) != NULL ) && + ( reg2->FindEntity( names[i].c_str() ) == NULL ) ) { + std::cout << std::endl << modeNames[ENTITY] << " " << names[i] << " expected but not present" << std::endl; + return false; + } + if( ( reg1->FindEntity( names[i].c_str() ) == NULL ) && + ( reg2->FindEntity( names[i].c_str() ) != NULL ) ) { + std::cout << std::endl << modeNames[ENTITY] << " " << names[i] << " not expected but present" << std::endl; + return false; + } + + if( ( reg1->FindSchema( names[i].c_str() ) != NULL ) && + ( reg2->FindSchema( names[i].c_str() ) == NULL ) ) { + std::cout << std::endl << modeNames[SCHEMA] << " " << names[i] << " expected but not present" << std::endl; + return false; + } + if( ( reg1->FindSchema( names[i].c_str() ) == NULL ) && + ( reg2->FindSchema( names[i].c_str() ) != NULL ) ) { + std::cout << std::endl << modeNames[SCHEMA] << " " << names[i] << " not expected but present" << std::endl; + return false; + } + + if( ( reg1->FindType( names[i].c_str() ) != NULL ) && + ( reg2->FindType( names[i].c_str() ) == NULL ) ) { + std::cout << std::endl << modeNames[TYPE] << " " << names[i] << " expected but not present" << std::endl; + return false; + } + if( ( reg1->FindType( names[i].c_str() ) == NULL ) && + ( reg2->FindType( names[i].c_str() ) != NULL ) ) { + std::cout << std::endl << modeNames[TYPE] << " " << names[i] << " not expected but present" << std::endl; + return false; + } + } + + return true; +} + +/// compares the given registries and reports any disparity +bool compareRegistry( Registry * reg1, Registry * reg2 ) { + if( reg1->GetEntityCnt() != reg2->GetEntityCnt() ) { + std::cout << std::endl << "\tentityCnt not same: " << reg1->GetEntityCnt() << " and " << reg2->GetEntityCnt() << std::endl; + return false; + } + + if( reg1->GetFullEntCnt() != reg2->GetFullEntCnt() ) { + std::cout << std::endl << "\tall_ents_Cnt not same: " << reg1->GetFullEntCnt() << " and " << reg2->GetFullEntCnt() << std::endl; + return false; + } + + if( !haveSameElements( reg1, reg2 ) ) { + return false; + } + + return true; +} + +/// For a particular mode adds elements to one Registry serially and to another Registry parallely. +/// It then compares the two Registry and reports any disparity. +void checkRegistryAddOnlyThreadSafety( Mode mode ) { + int size = names.size(); + + Registry * regExpected = new Registry( dummyInit ); + addElements( regExpected, mode, 0, size, 2 ); // Add even indexed elements + addElements( regExpected, mode, 1, size, 2 ); // Add odd indexed elements + + std::cout << "Checking thread safety of Registry " << modeNames[( int )mode] << " Add Operations..." ; + + int i, iterations = 10; + for( i = 0 ; i < iterations; i++ ) { + Registry * regActual = new Registry( dummyInit ); + + std::thread first( addElements, regActual, mode, 0, size, 2 ); + std::thread second( addElements, regActual, mode, 1, size, 2 ); + + first.join(); + second.join(); + + bool success = compareRegistry( regExpected, regActual ); + delete regActual; + + if( !success ) { + break; + } + } + + if( i == iterations ) { + std::cout << "...PASS!" << std::endl; + } else { + std::cout << "...FAIL!" << std::endl; + } + + std::cout << std::endl; + + delete regExpected; +} + +/// For a particular mode removes elements to one Registry serially and to another Registry parallely. +/// It then compares the two Registry and reports any disparity. +void checkRegistryRemoveOnlyThreadSafety( Mode mode ) { + int size = names.size(); + + Registry * regExpected = new Registry( dummyInit ); + addElements( regExpected, mode, 0, size, 1 ); // Add all elements + removeElements( regExpected, mode, 0, size, 3 ); // remove one-third elements + removeElements( regExpected, mode, 1, size, 3 ); // remove another third elements + + std::cout << "Checking thread safety of Registry " << modeNames[( int )mode] << " Remove Operations..." ; + + int i, iterations = 10; + for( i = 0 ; i < iterations; i++ ) { + Registry * regActual = new Registry( dummyInit ); + + addElements( regActual, mode, 0, size, 1 ); + std::thread first( removeElements, regActual, mode, 0, size, 3 ); + std::thread second( removeElements, regActual, mode, 1, size, 3 ); + + first.join(); + second.join(); + + bool success = compareRegistry( regExpected, regActual ); + delete regActual; + + if( !success ) { + break; + } + } + + if( i == iterations ) { + std::cout << "...PASS!" << std::endl; + } else { + std::cout << "...FAIL!" << std::endl; + } + + std::cout << std::endl; + + delete regExpected; +} + +/// For a particular mode adds and removes elements to one Registry serially and to ther Registry parallely. +/// It then compares the two Registry and reports any disparity. +void checkRegistryAddRemoveThreadSafety( Mode mode ) { + int size = names.size(); + + Registry * regExpected = new Registry( dummyInit ); + addElements( regExpected, mode, 0, size, 2 ); // Add even indexed elements + addElements( regExpected, mode, 1, size, 2 ); // Add odd indexed elements + removeElements( regExpected, mode, 0, size, 2 ); // remove even indexed elements + + std::cout << "Checking thread safety of Registry " << modeNames[( int )mode] << " Add-Remove Operations..." ; + + int i, iterations = 10; + for( i = 0 ; i < iterations; i++ ) { + Registry * regActual = new Registry( dummyInit ); + + addElements( regActual, mode, 0, size, 2 ); + std::thread first( addElements, regActual, mode, 1, size, 2 ); + std::thread second( removeElements, regActual, mode, 0, size, 2 ); + + first.join(); + second.join(); + + bool success = compareRegistry( regExpected, regActual ); + delete regActual; + + if( !success ) { + break; + } + } + + if( i == iterations ) { + std::cout << "...PASS!" << std::endl; + } else { + std::cout << "...FAIL!" << std::endl; + } + + std::cout << std::endl; + + delete regExpected; +} + +void checkRegistryEntityAddOnlyThreadSafety() { + checkRegistryAddOnlyThreadSafety( ENTITY ); +} + +void checkRegistrySchemaAddOnlyThreadSafety() { + checkRegistryAddOnlyThreadSafety( SCHEMA ); +} + +void checkRegistryTypeAddOnlyThreadSafety() { + checkRegistryAddOnlyThreadSafety( TYPE ); +} + +void checkRegistryEntityRemoveOnlyThreadSafety() { + checkRegistryRemoveOnlyThreadSafety( ENTITY ); +} + +void checkRegistrySchemaRemoveOnlyThreadSafety() { + checkRegistryRemoveOnlyThreadSafety( SCHEMA ); +} + +void checkRegistryTypeRemoveOnlyThreadSafety() { + checkRegistryRemoveOnlyThreadSafety( TYPE ); +} + +void checkRegistryEntityAddRemoveThreadSafety() { + checkRegistryAddRemoveThreadSafety( ENTITY ); +} + +void checkRegistrySchemaAddRemoveThreadSafety() { + checkRegistryAddRemoveThreadSafety( SCHEMA ); +} + +void checkRegistryTypeAddRemoveThreadSafety() { + checkRegistryAddRemoveThreadSafety( TYPE ); +} + +// populates the vector names[] with string of the form [A-Z]/[a-z]/[a-z] +void populateNamesVector() { + char ch[3]; + ch[0] = 'A'; + while( ch[0] <= 'Z') + { + ch[1] = 'a'; + while( ch[1] <= 'z') + { + ch[2] = '0'; + while( ch[2] <= '9') + { + string str( ch ); + names.push_back( str ); + ch[2]++; + } + ch[1]++; + } + ch[0]++; + } +} + +int main( int , char ** ) { + populateNamesVector(); + + checkRegistryEntityAddOnlyThreadSafety(); + checkRegistryEntityRemoveOnlyThreadSafety(); + checkRegistryEntityAddRemoveThreadSafety(); + + checkRegistrySchemaAddOnlyThreadSafety(); + checkRegistrySchemaRemoveOnlyThreadSafety(); + checkRegistrySchemaAddRemoveThreadSafety(); + + checkRegistryTypeAddOnlyThreadSafety(); + checkRegistryTypeRemoveOnlyThreadSafety(); + checkRegistryTypeAddRemoveThreadSafety(); +} From 58ca507d1329791bd792301451f692b632269b77 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 25 Jun 2014 22:15:00 +0530 Subject: [PATCH 056/111] Made the Registry entity operation thread safe The checks related entity operations in Registry_thread_safety_test now pass. --- src/clstepcore/Registry.h | 3 +++ src/clstepcore/Registry.inline.cc | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/clstepcore/Registry.h b/src/clstepcore/Registry.h index 3ad82efcf..610776d80 100644 --- a/src/clstepcore/Registry.h +++ b/src/clstepcore/Registry.h @@ -18,6 +18,7 @@ #include #include #include +#include typedef struct Hash_Table * HashTable; @@ -37,6 +38,8 @@ class SC_CORE_EXPORT Registry { HashEntry cur_schema; HashEntry cur_type; + mutable sc_recursive_mutex entityMtx; // will protect primodialSwamp, entity_cnt and all_ents_cnt + // used by AddEntity() and RemoveEntity() to deal with renamings of an // entity done in a USE or REFERENCE clause - see header comments in // file Registry.inline.cc diff --git a/src/clstepcore/Registry.inline.cc b/src/clstepcore/Registry.inline.cc index 4b1edece5..47c710f65 100644 --- a/src/clstepcore/Registry.inline.cc +++ b/src/clstepcore/Registry.inline.cc @@ -113,10 +113,12 @@ Registry::~Registry() { void Registry::DeleteContents() { // entities first + entityMtx.lock(); SC_HASHlistinit( primordialSwamp, &cur_entity ); while( SC_HASHlist( &cur_entity ) ) { delete( EntityDescriptor * ) cur_entity.e->data; } + entityMtx.unlock(); // schemas SC_HASHlistinit( active_schemas, &cur_schema ); @@ -145,12 +147,14 @@ const EntityDescriptor * Registry::FindEntity( const char * e, const char * schN const SchRename * altlist; char schformat[BUFSIZ], altName[BUFSIZ]; + entityMtx.lock(); if( check_case ) { entd = ( EntityDescriptor * )SC_HASHfind( primordialSwamp, ( char * )e ); } else { entd = ( EntityDescriptor * )SC_HASHfind( primordialSwamp, ( char * )PrettyTmpName( e ) ); } + entityMtx.unlock(); if( entd && schNm ) { // We've now found an entity. If schNm has a value, we must ensure we // have a valid name. @@ -209,10 +213,12 @@ const TypeDescriptor * Registry::NextType() { } void Registry::AddEntity( const EntityDescriptor & e ) { + entityMtx.lock(); SC_HASHinsert( primordialSwamp, ( char * ) e.Name(), ( EntityDescriptor * ) &e ); ++entity_cnt; ++all_ents_cnt; AddClones( e ); + entityMtx.unlock(); } @@ -234,12 +240,14 @@ void Registry::AddType( const TypeDescriptor & d ) { void Registry::AddClones( const EntityDescriptor & e ) { const SchRename * alts = e.AltNameList(); + entityMtx.lock(); while( alts ) { SC_HASHinsert( primordialSwamp, ( char * )alts->objName(), ( EntityDescriptor * )&e ); alts = alts->next; } all_ents_cnt += uniqueNames( e.Name(), e.AltNameList() ); + entityMtx.unlock(); } /** @@ -271,6 +279,7 @@ static int uniqueNames( const char * entnm, const SchRename * altlist ) { } void Registry::RemoveEntity( const char * n ) { + entityMtx.lock(); const EntityDescriptor * e = FindEntity( n ); struct Element tmp; @@ -279,6 +288,7 @@ void Registry::RemoveEntity( const char * n ) { } tmp.key = ( char * ) n; SC_HASHsearch( primordialSwamp, &tmp, HASH_DELETE ) ? --entity_cnt : 0; + entityMtx.unlock(); } @@ -301,17 +311,21 @@ void Registry::RemoveClones( const EntityDescriptor & e ) { const SchRename * alts = e.AltNameList(); struct Element * tmp; + entityMtx.lock(); while( alts ) { tmp = new Element; tmp->key = ( char * ) alts->objName(); SC_HASHsearch( primordialSwamp, tmp, HASH_DELETE ); alts = alts->next; } + entityMtx.unlock(); } SDAI_Application_instance * Registry::ObjCreate( const char * nm, const char * schnm, int check_case ) const { + entityMtx.lock(); const EntityDescriptor * entd = FindEntity( nm, schnm, check_case ); + entityMtx.unlock(); if( entd ) { SDAI_Application_instance * se = ( ( EntityDescriptor * )entd ) -> NewSTEPentity(); @@ -337,7 +351,9 @@ int Registry::GetEntityCnt() { } void Registry::ResetEntities() { + entityMtx.lock(); SC_HASHlistinit( primordialSwamp, &cur_entity ); + entityMtx.unlock(); } From 077633aa77d7b6b344260cad6e0610a330c775ed Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 25 Jun 2014 22:26:17 +0530 Subject: [PATCH 057/111] Made Registry Schema and Type operations thread safe All the checks in Registry_thread_safety_test now pass --- src/clstepcore/Registry.h | 2 ++ src/clstepcore/Registry.inline.cc | 39 +++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/clstepcore/Registry.h b/src/clstepcore/Registry.h index 610776d80..ed48ab897 100644 --- a/src/clstepcore/Registry.h +++ b/src/clstepcore/Registry.h @@ -39,6 +39,8 @@ class SC_CORE_EXPORT Registry { HashEntry cur_type; mutable sc_recursive_mutex entityMtx; // will protect primodialSwamp, entity_cnt and all_ents_cnt + mutable sc_recursive_mutex schemaMtx; // will protect active_schemas + mutable sc_recursive_mutex typeMtx; // will protect active_types // used by AddEntity() and RemoveEntity() to deal with renamings of an // entity done in a USE or REFERENCE clause - see header comments in diff --git a/src/clstepcore/Registry.inline.cc b/src/clstepcore/Registry.inline.cc index 47c710f65..3a1a06aaa 100644 --- a/src/clstepcore/Registry.inline.cc +++ b/src/clstepcore/Registry.inline.cc @@ -121,16 +121,20 @@ void Registry::DeleteContents() { entityMtx.unlock(); // schemas + schemaMtx.lock(); SC_HASHlistinit( active_schemas, &cur_schema ); while( SC_HASHlist( &cur_schema ) ) { delete( Schema * ) cur_schema.e->data; } + schemaMtx.unlock(); // types + typeMtx.lock(); SC_HASHlistinit( active_types, &cur_type ); while( SC_HASHlist( &cur_type ) ) { delete( TypeDescriptor * ) cur_type.e->data; } + typeMtx.unlock(); } /** @@ -185,24 +189,35 @@ const EntityDescriptor * Registry::FindEntity( const char * e, const char * schN } const Schema * Registry::FindSchema( const char * n, int check_case ) const { + const Schema * sc; + schemaMtx.lock(); if( check_case ) { - return ( const Schema * ) SC_HASHfind( active_schemas, ( char * ) n ); - } - - return ( const Schema * ) SC_HASHfind( active_schemas, + sc = ( const Schema * ) SC_HASHfind( active_schemas, ( char * ) n ); + } else { + sc = ( const Schema * ) SC_HASHfind( active_schemas, ( char * )PrettyTmpName( n ) ); + } + schemaMtx.unlock(); + return sc; } const TypeDescriptor * Registry::FindType( const char * n, int check_case ) const { + const TypeDescriptor * td; + typeMtx.lock(); if( check_case ) { - return ( const TypeDescriptor * ) SC_HASHfind( active_types, ( char * ) n ); + td = ( const TypeDescriptor * ) SC_HASHfind( active_types, ( char * ) n ); + } else { + td = ( const TypeDescriptor * ) SC_HASHfind( active_types, + ( char * )PrettyTmpName( n ) ); } - return ( const TypeDescriptor * ) SC_HASHfind( active_types, - ( char * )PrettyTmpName( n ) ); + typeMtx.unlock(); + return td; } void Registry::ResetTypes() { + typeMtx.lock(); SC_HASHlistinit( active_types, &cur_type ); + typeMtx.unlock(); } const TypeDescriptor * Registry::NextType() { @@ -223,11 +238,15 @@ void Registry::AddEntity( const EntityDescriptor & e ) { void Registry::AddSchema( const Schema & d ) { + schemaMtx.lock(); SC_HASHinsert( active_schemas, ( char * ) d.Name(), ( Schema * ) &d ); + schemaMtx.unlock(); } void Registry::AddType( const TypeDescriptor & d ) { + typeMtx.lock(); SC_HASHinsert( active_types, ( char * ) d.Name(), ( TypeDescriptor * ) &d ); + typeMtx.unlock(); } /** @@ -295,13 +314,17 @@ void Registry::RemoveEntity( const char * n ) { void Registry::RemoveSchema( const char * n ) { struct Element tmp; tmp.key = ( char * ) n; + schemaMtx.lock(); SC_HASHsearch( active_schemas, &tmp, HASH_DELETE ); + schemaMtx.unlock(); } void Registry::RemoveType( const char * n ) { struct Element tmp; tmp.key = ( char * ) n; + typeMtx.lock(); SC_HASHsearch( active_types, &tmp, HASH_DELETE ); + typeMtx.unlock(); } /** @@ -365,7 +388,9 @@ const EntityDescriptor * Registry::NextEntity() { } void Registry::ResetSchemas() { + schemaMtx.lock(); SC_HASHlistinit( active_schemas, &cur_schema ); + schemaMtx.unlock(); } const Schema * Registry::NextSchema() { From e951c2c71a972bd28948b6cce48b50d52af3f404 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 9 Jul 2014 21:12:16 +0530 Subject: [PATCH 058/111] Corrected SingleLinkedList mtx bug The mtx is converted into sc_recursive_mtx deleted in the destructor --- src/clstepcore/SingleLinkList.h | 5 ++--- src/clstepcore/SingleLinkList.inline.cc | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/clstepcore/SingleLinkList.h b/src/clstepcore/SingleLinkList.h index c1a2fe621..ff21c77c1 100644 --- a/src/clstepcore/SingleLinkList.h +++ b/src/clstepcore/SingleLinkList.h @@ -25,11 +25,10 @@ class SC_CORE_EXPORT SingleLinkList { class SingleLinkNode * head; SingleLinkNode * tail; + public: // had to be made into a pointer due to the equality // operator being used elswhere for SingleLinkList object - sc_mutex * mtxP; - - public: + sc_recursive_mutex * mtxP; //making it public for the use in STEPaggregrate virtual SingleLinkNode * NewNode(); virtual void AppendNode( SingleLinkNode * ); diff --git a/src/clstepcore/SingleLinkList.inline.cc b/src/clstepcore/SingleLinkList.inline.cc index 256b49287..d43a66ad0 100644 --- a/src/clstepcore/SingleLinkList.inline.cc +++ b/src/clstepcore/SingleLinkList.inline.cc @@ -21,11 +21,12 @@ SingleLinkNode::NextNode() const { SingleLinkList::SingleLinkList() : head( 0 ), tail( 0 ) { - mtxP = new sc_mutex(); + mtxP = new sc_recursive_mutex(); } SingleLinkList::~SingleLinkList() { Empty(); + delete mtxP; } void SingleLinkList::Empty() { From d169a58ec5c051aa79517c6fd85b74b467b813e0 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 9 Jul 2014 22:02:34 +0530 Subject: [PATCH 059/111] Changes in cmake to build lazy tests Some changes in cmakefiles had caused the test associated with lazy_test to stop building. Those changes were reviewed and corrected. --- cmake/SC_CXX_schema_macros.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmake/SC_CXX_schema_macros.cmake b/cmake/SC_CXX_schema_macros.cmake index 748724d0b..40a3535fc 100644 --- a/cmake/SC_CXX_schema_macros.cmake +++ b/cmake/SC_CXX_schema_macros.cmake @@ -33,8 +33,11 @@ macro(SCHEMA_EXES) set_target_properties(p21read_${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD") endif(HAVE_STD_THREAD) if(NOT WIN32) - #SC_ADDEXEC(lazy_${PROJECT_NAME} "${RELATIVE_PATH_COMPONENT}/src/cllazyfile/lazy_test.cc" "${PROJECT_NAME};steplazyfile;stepdai;stepcore;stepeditor;steputils;base" "TESTABLE") + SC_ADDEXEC(lazy_${PROJECT_NAME} "${RELATIVE_PATH_COMPONENT}/src/cllazyfile/lazy_test.cc" "${PROJECT_NAME};steplazyfile;stepdai;stepcore;stepeditor;steputils;base" "TESTABLE") #add_dependencies(lazy_${PROJECT_NAME} version_string) + if(HAVE_STD_THREAD) + set_target_properties(lazy_${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD") + endif(HAVE_STD_THREAD) endif(NOT WIN32) #add user-defined executables From 529d3a0ca00fdf70682388fc7ed529e025bf54af Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Thu, 10 Jul 2014 11:18:38 +0530 Subject: [PATCH 060/111] Duplicate code was removed in STEPaggregrate STEPaggregrate and its superclass SingleLinkList.cc had the same destructor. --- src/clstepcore/STEPaggregate.cc | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/clstepcore/STEPaggregate.cc b/src/clstepcore/STEPaggregate.cc index b986f7bf8..49db1cabd 100644 --- a/src/clstepcore/STEPaggregate.cc +++ b/src/clstepcore/STEPaggregate.cc @@ -38,14 +38,7 @@ STEPaggregate::STEPaggregate() { } STEPaggregate::~STEPaggregate() { - STEPnode * node; - - node = ( STEPnode * ) head; - while( node ) { - head = node->NextNode(); - delete node; - node = ( STEPnode * ) head; - } + // Left to the superclass } STEPaggregate & STEPaggregate::ShallowCopy( const STEPaggregate & a ) { From 6e5475e37dbe1325118d8a220920e9aada240169 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Thu, 10 Jul 2014 16:33:23 +0530 Subject: [PATCH 061/111] Removed duplicated code in SubSuperIterators.cc --- src/clstepcore/SubSuperIterators.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clstepcore/SubSuperIterators.h b/src/clstepcore/SubSuperIterators.h index b40e56cc7..496141814 100644 --- a/src/clstepcore/SubSuperIterators.h +++ b/src/clstepcore/SubSuperIterators.h @@ -108,7 +108,7 @@ class recursiveEntDescripIterator { } bool operator !=( const recursiveEntDescripIterator & b ) const { - return( ( startEntity != b.startEntity ) || ( position != b.position ) ); + return( !( operator ==( b ) ) ); } /// for inequality operators, return a Logical; LUnknown means that the startEntity pointers do not match From 832154ae4440635368a85a8f15256297130c62a8 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Thu, 10 Jul 2014 17:04:37 +0530 Subject: [PATCH 062/111] Made SubSuperIterators.h thread safe This was done by introducing a recursive mutex meant to protect the std::deque 'q' and unsigned integer 'position' --- src/clstepcore/SubSuperIterators.h | 129 ++++++++++++++++++++--------- 1 file changed, 89 insertions(+), 40 deletions(-) diff --git a/src/clstepcore/SubSuperIterators.h b/src/clstepcore/SubSuperIterators.h index 496141814..3e32c430f 100644 --- a/src/clstepcore/SubSuperIterators.h +++ b/src/clstepcore/SubSuperIterators.h @@ -5,6 +5,7 @@ #include "ExpDict.h" #include #include +#include /** abstract base class for recursive breadth-first input iterators of EntityDescriptor/EntityDescLinkNode * NOTE: due to pure virtual functions being necessary for initialization, derived class constructor must call reset(t) @@ -19,6 +20,7 @@ class recursiveEntDescripIterator { std::deque< queue_pair > q; unsigned int position; ///< primarily used in comparisons between iterators + sc_recursive_mutex * dqMtxP; ///< protects 'q' and 'position' ///add contents of a linked list to q void addLinkedList( const queue_pair qp ) { @@ -27,7 +29,9 @@ class recursiveEntDescripIterator { tmp.depth = qp.depth + 1; while( a != 0 ) { tmp.ed = nodeContent( a ); + dqMtxP->lock( ); q.push_back( tmp ); + dqMtxP->unlock( ); a = ( EntityDescLinkNode * ) a->NextNode( ); } } @@ -36,15 +40,17 @@ class recursiveEntDescripIterator { public: - recursiveEntDescripIterator( const EntityDescriptor * t = 0 ): startEntity( t ), position( 0 ) { + recursiveEntDescripIterator( const EntityDescriptor * t = 0 ): startEntity( t ), position( 0 ), dqMtxP( new sc_recursive_mutex( ) ) { //NOTE due to pure virtual functions, derived class constructor *must* call reset(t) } - recursiveEntDescripIterator( ): startEntity( 0 ), position( 0 ) { + recursiveEntDescripIterator( ): startEntity( 0 ), position( 0 ), dqMtxP( new sc_recursive_mutex( ) ) { } ~recursiveEntDescripIterator( ) { + delete dqMtxP; } void reset( const EntityDescriptor * t = 0 ) { + dqMtxP->lock( ); position = 0; q.clear( ); if( t ) { @@ -56,30 +62,40 @@ class recursiveEntDescripIterator { p.ed = startEntity; addLinkedList( p ); } + dqMtxP->unlock( ); } const EntityDescriptor * next( ) { - if( q.empty( ) ) { - return ( EntityDescriptor * ) 0; - } else { + const EntityDescriptor * ed = 0; + dqMtxP->lock( ); + if( !q.empty( ) ) { position++; queue_pair qp = q.front( ); q.pop_front( ); addLinkedList( qp ); - return qp.ed; + ed = qp.ed; } + dqMtxP->unlock( ); + return ed; } const EntityDescriptor * current( ) const { - if( q.empty( ) ) { - return ( EntityDescriptor * ) 0; + const EntityDescriptor * ed = 0; + dqMtxP->lock(); + if( !q.empty( ) ) { + //q.front has to be protected by a mutex otherwise it calling front on an empty queue might lead to an undefined behavior + ed = ( q.front( ).ed ); } - return( q.front( ).ed ); + dqMtxP->unlock(); + return ed; } bool hasNext( ) const { - return( ( ( q.size( ) > 1 ) && ( q[1].ed != 0 ) ) //there is another EntityDescriptor in q - || ( nodeContent( listHead( q[0].ed ) ) != 0 ) ); //or, the only one in the queue has a non-empty list + dqMtxP->lock(); + bool has_next = ( ( ( q.size( ) > 1 ) && ( q[1].ed != 0 ) ) //there is another EntityDescriptor in q + || ( nodeContent( listHead( q[0].ed ) ) != 0 ) ); //or, the only one in the queue has a non-empty list + dqMtxP->unlock(); + return has_next; } bool empty( ) const { @@ -104,7 +120,10 @@ class recursiveEntDescripIterator { /// two iterators are not considered equal unless the startEntity pointers match and the positions match bool operator ==( const recursiveEntDescripIterator & b ) const { - return( ( startEntity == b.startEntity ) && ( position == b.position ) ); + dqMtxP->lock(); + bool eq = ( ( startEntity == b.startEntity ) && ( position == b.position ) ); + dqMtxP->unlock(); + return eq; } bool operator !=( const recursiveEntDescripIterator & b ) const { @@ -113,47 +132,63 @@ class recursiveEntDescripIterator { /// for inequality operators, return a Logical; LUnknown means that the startEntity pointers do not match Logical operator >( const recursiveEntDescripIterator & b ) const { + Logical logical; + dqMtxP->lock(); if( startEntity != b.startEntity ) { - return LUnknown; + logical = LUnknown; } - if( position > b.position ) { - return LTrue; + else if( position > b.position ) { + logical = LTrue; } else { - return LFalse; + logical = LFalse; } + dqMtxP->unlock(); + return logical; } Logical operator <( const recursiveEntDescripIterator & b ) const { + Logical logical; + dqMtxP->lock(); if( startEntity != b.startEntity ) { - return LUnknown; + logical = LUnknown; } - if( position < b.position ) { - return LTrue; + else if( position < b.position ) { + logical = LTrue; } else { - return LFalse; + logical = LFalse; } + dqMtxP->unlock(); + return logical; } Logical operator >=( const recursiveEntDescripIterator & b ) const { + Logical logical; + dqMtxP->lock(); if( startEntity != b.startEntity ) { - return LUnknown; + logical = LUnknown; } - if( position >= b.position ) { - return LTrue; + else if( position >= b.position ) { + logical = LTrue; } else { - return LFalse; + logical = LFalse; } + dqMtxP->unlock(); + return logical; } Logical operator <=( const recursiveEntDescripIterator & b ) const { + Logical logical; + dqMtxP->lock(); if( startEntity != b.startEntity ) { - return LUnknown; + logical = LUnknown; } - if( position <= b.position ) { - return LTrue; + else if( position <= b.position ) { + logical = LTrue; } else { - return LFalse; + logical = LFalse; } + dqMtxP->unlock(); + return logical; } const EntityDescriptor * operator ++( ) { @@ -161,8 +196,10 @@ class recursiveEntDescripIterator { } const EntityDescriptor * operator ++( int ) { + dqMtxP->lock(); const EntityDescriptor * c = current( ); next( ); + dqMtxP->unlock(); return c; } }; @@ -173,16 +210,22 @@ class recursiveEntDescripIterator { class supertypesIterator : public recursiveEntDescripIterator { protected: EntityDescLinkNode * listHead( const EntityDescriptor * t ) const { ///< returns the head of an EntityDescriptorList - if( !t ) { - return 0; + EntityDescLinkNode * edln = 0; + dqMtxP->lock(); + if( t ) { + edln = ( EntityDescLinkNode * ) t->Supertypes().GetHead(); } - return ( EntityDescLinkNode * ) t->Supertypes().GetHead(); + dqMtxP->unlock(); + return edln; } EntityDescriptor * nodeContent( const EntityDescLinkNode * n ) const { ///< returns the content of a EntityDescLinkNode - if( !n ) { - return 0; + EntityDescriptor * ed = 0; + dqMtxP->lock(); + if( n ) { + ed = n->EntityDesc(); } - return n->EntityDesc(); + dqMtxP->unlock(); + return ed; } public: supertypesIterator( const EntityDescriptor * t = 0 ): recursiveEntDescripIterator( t ) { @@ -196,16 +239,22 @@ class supertypesIterator : public recursiveEntDescripIterator { class subtypesIterator: public recursiveEntDescripIterator { protected: EntityDescLinkNode * listHead( const EntityDescriptor * t ) const { ///< returns the head of an EntityDescriptorList - if( !t ) { - return 0; + EntityDescLinkNode * edln = 0; + dqMtxP->lock(); + if( t ) { + edln = ( EntityDescLinkNode * ) t->Subtypes().GetHead(); } - return ( EntityDescLinkNode * ) t->Subtypes().GetHead(); + dqMtxP->unlock(); + return edln; } EntityDescriptor * nodeContent( const EntityDescLinkNode * n ) const { ///< returns the content of a EntityDescLinkNode - if( !n ) { - return 0; + EntityDescriptor * ed = 0; + dqMtxP->lock(); + if( n ) { + ed = n->EntityDesc(); } - return n->EntityDesc(); + dqMtxP->unlock(); + return ed; } public: subtypesIterator( const EntityDescriptor * t = 0 ): recursiveEntDescripIterator( t ) { From 25ec194b33c036913a1ba0e311925aa8ac4df409 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sat, 12 Jul 2014 13:52:33 +0530 Subject: [PATCH 063/111] Modified add_schema_dependent_test module Some of the unit tests were failing due to assertions failures inside mutexes. Ultimately the CMakeFiles were changed and all the tests except of 'test_inverse_attr3' are passing --- test/cpp/schema_specific/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/cpp/schema_specific/CMakeLists.txt b/test/cpp/schema_specific/CMakeLists.txt index 049596e07..73d1106c9 100644 --- a/test/cpp/schema_specific/CMakeLists.txt +++ b/test/cpp/schema_specific/CMakeLists.txt @@ -18,6 +18,9 @@ function( add_schema_dependent_test name sdai_lib exe_args ) add_executable( tst_${name} "${name}.cc" ) set_target_properties( tst_${name} PROPERTIES COMPILE_FLAGS "-I${sdai_src_path} ${ARGV3}" EXCLUDE_FROM_ALL ON ) + if(HAVE_STD_THREAD) + set_target_properties( tst_${name} PROPERTIES COMPILE_FLAGS "-I${sdai_src_path} ${ARGV3} -pthread -std=c++0x -DHAVE_STD_THREAD" EXCLUDE_FROM_ALL ON ) + endif(HAVE_STD_THREAD) if(NOT "${ARGV4}" MATCHES "NONE") DEFINE_DLL_IMPORTS( "tst_${name}" "${ARGV4}" ) endif(NOT "${ARGV4}" MATCHES "NONE") From cb1f402b1552edf1c483b25b658e13f1b0f86be5 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sat, 12 Jul 2014 16:40:46 +0530 Subject: [PATCH 064/111] Made STEPaggregrate thread safe. This was done by relying on the mtx used by its superclass: SingleLinkList. --- src/clstepcore/STEPaggregate.cc | 24 ++++++++++++++++++++++++ src/clstepcore/SingleLinkList.h | 4 +++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/clstepcore/STEPaggregate.cc b/src/clstepcore/STEPaggregate.cc index 49db1cabd..22a05e141 100644 --- a/src/clstepcore/STEPaggregate.cc +++ b/src/clstepcore/STEPaggregate.cc @@ -384,6 +384,7 @@ SingleLinkNode * GenericAggregate::NewNode() { STEPaggregate & GenericAggregate::ShallowCopy( const STEPaggregate & a ) { Empty(); + a.mtxP->lock(); // required since we are iterating on 'SingleLinkList a' SingleLinkNode * next = a.GetHead(); SingleLinkNode * copy; @@ -392,6 +393,8 @@ STEPaggregate & GenericAggregate::ShallowCopy( const STEPaggregate & a ) { AddNode( copy ); next = next->NextNode(); } + a.mtxP->unlock(); + if( head ) { _null = 0; } else { @@ -572,11 +575,14 @@ Severity EntityAggregate::ReadValue( istream & in, ErrorDescriptor * err, STEPaggregate & EntityAggregate::ShallowCopy( const STEPaggregate & a ) { + a.mtxP->lock(); // required since we are iterating on 'SingleLinkList a' const EntityNode * tmp = ( const EntityNode * ) a.GetHead(); while( tmp ) { AddNode( new EntityNode( tmp -> node ) ); tmp = ( const EntityNode * ) tmp -> NextNode(); } + a.mtxP->unlock(); + if( head ) { _null = 0; } else { @@ -810,12 +816,15 @@ Severity SelectAggregate::ReadValue( istream & in, ErrorDescriptor * err, STEPaggregate & SelectAggregate::ShallowCopy( const STEPaggregate & a ) { + a.mtxP->lock(); // required since we are iterating on 'SingleLinkList a' const SelectNode * tmp = ( const SelectNode * ) a.GetHead(); while( tmp ) { AddNode( new SelectNode( tmp -> node ) ); tmp = ( const SelectNode * ) tmp -> NextNode(); } + a.mtxP->unlock(); + if( head ) { _null = 0; } else { @@ -930,6 +939,7 @@ StringAggregate::~StringAggregate() { STEPaggregate & StringAggregate::ShallowCopy( const STEPaggregate & a ) { Empty(); + a.mtxP->lock(); // required since we are iterating on 'SingleLinkList a' SingleLinkNode * next = a.GetHead(); SingleLinkNode * copy; @@ -938,6 +948,8 @@ STEPaggregate & StringAggregate::ShallowCopy( const STEPaggregate & a ) { AddNode( copy ); next = next->NextNode(); } + a.mtxP->unlock(); + if( head ) { _null = 0; } else { @@ -1035,6 +1047,7 @@ BinaryAggregate::~BinaryAggregate() { STEPaggregate & BinaryAggregate::ShallowCopy( const STEPaggregate & a ) { Empty(); + a.mtxP->lock(); // required since we are iterating on 'SingleLinkList a' SingleLinkNode * next = a.GetHead(); SingleLinkNode * copy; @@ -1043,6 +1056,8 @@ STEPaggregate & BinaryAggregate::ShallowCopy( const STEPaggregate & a ) { AddNode( copy ); next = next->NextNode(); } + a.mtxP->unlock(); + if( head ) { _null = 0; } else { @@ -1135,6 +1150,7 @@ void BinaryNode::STEPwrite( ostream & out ) { /// COPY STEPaggregate & EnumAggregate::ShallowCopy( const STEPaggregate & a ) { + a.mtxP->lock(); // required since we are iterating on 'SingleLinkList a' const EnumNode * tmp = ( const EnumNode * ) a.GetHead(); EnumNode * to; @@ -1144,6 +1160,8 @@ STEPaggregate & EnumAggregate::ShallowCopy( const STEPaggregate & a ) { AddNode( to ); tmp = ( const EnumNode * ) tmp -> NextNode(); } + a.mtxP->unlock(); + if( head ) { _null = 0; } else { @@ -1299,6 +1317,7 @@ SingleLinkNode * RealAggregate::NewNode() { // COPY STEPaggregate & RealAggregate::ShallowCopy( const STEPaggregate & a ) { + a.mtxP->lock(); // required since we are iterating on 'SingleLinkList a' const RealNode * tmp = ( const RealNode * ) a.GetHead(); RealNode * to; @@ -1308,6 +1327,8 @@ STEPaggregate & RealAggregate::ShallowCopy( const STEPaggregate & a ) { AddNode( to ); tmp = ( const RealNode * ) tmp -> NextNode(); } + a.mtxP->unlock(); + if( head ) { _null = 0; } else { @@ -1332,6 +1353,7 @@ SingleLinkNode * IntAggregate::NewNode() { /// COPY STEPaggregate & IntAggregate::ShallowCopy( const STEPaggregate & a ) { + a.mtxP->lock(); // required since we are iterating on 'SingleLinkList a' const IntNode * tmp = ( const IntNode * ) a.GetHead(); IntNode * to; @@ -1341,6 +1363,8 @@ STEPaggregate & IntAggregate::ShallowCopy( const STEPaggregate & a ) { AddNode( to ); tmp = ( const IntNode * ) tmp -> NextNode(); } + a.mtxP->unlock(); + if( head ) { _null = 0; } else { diff --git a/src/clstepcore/SingleLinkList.h b/src/clstepcore/SingleLinkList.h index ff21c77c1..600c32a6d 100644 --- a/src/clstepcore/SingleLinkList.h +++ b/src/clstepcore/SingleLinkList.h @@ -24,11 +24,13 @@ class SC_CORE_EXPORT SingleLinkList { class SingleLinkNode * head; SingleLinkNode * tail; +Made STEPaggregrate thread safe. +This was done by relying on the mtx used by its superclass: SingleLinkList. public: // had to be made into a pointer due to the equality // operator being used elswhere for SingleLinkList object - sc_recursive_mutex * mtxP; //making it public for the use in STEPaggregrate + sc_recursive_mutex * mtxP; //making it public for the use in STEPaggregrate (where another object might lock/unlock them) virtual SingleLinkNode * NewNode(); virtual void AppendNode( SingleLinkNode * ); From b7cc806a57ff092768b5d6bd966115fc786860c0 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sat, 12 Jul 2014 18:55:33 +0530 Subject: [PATCH 065/111] Made EntNode of complexSupport.h thread safe Since EntNode had no covering list counterpart, a shared recursive mutex was introduced. The pointer to this mutex would be with every node. --- src/clstepcore/complexSupport.h | 6 +++++- src/clstepcore/entnode.cc | 25 ++++++++++++++++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/clstepcore/complexSupport.h b/src/clstepcore/complexSupport.h index 46b673b46..cf066c837 100644 --- a/src/clstepcore/complexSupport.h +++ b/src/clstepcore/complexSupport.h @@ -19,6 +19,7 @@ #include using namespace std; #include "Str.h" +#include "sc_mutex.h" #define LISTEND 999 /** \def LISTEND @@ -80,13 +81,15 @@ class SC_CORE_EXPORT EntNode { friend class ComplexList; public: - EntNode( const char * nm = "" ) : next( 0 ), mark( NOMARK ), multSupers( 0 ) { + EntNode( const char * nm = "" ) : next( 0 ), sharedMtxP( 0 ), mark( NOMARK ), multSupers( 0 ) { StrToLower( nm, name ); } EntNode( const char ** ); ///< given a list, create a linked list of EntNodes ~EntNode() { if( next ) { delete next; + } else { + delete sharedMtxP; //The last node deletes sharedMtxP; } } operator const char * () { @@ -129,6 +132,7 @@ class SC_CORE_EXPORT EntNode { void sort( EntNode ** ); EntNode * next; + sc_recursive_mutex * sharedMtxP;///< will be common for all nodes. Made recursive due to ::sort() private: MarkType mark; diff --git a/src/clstepcore/entnode.cc b/src/clstepcore/entnode.cc index 792489e4b..2f8e41636 100644 --- a/src/clstepcore/entnode.cc +++ b/src/clstepcore/entnode.cc @@ -13,6 +13,7 @@ #include "complexSupport.h" #include "sc_memmgr.h" +#include "assert.h" /** * Given a list of entity names, creates a sorted linked list of EntNodes @@ -29,6 +30,7 @@ EntNode::EntNode( const char ** names ) { // Create a first EntNode: firstnode = prev = new EntNode( names[0] ); + firstnode->sharedMtxP = new sc_recursive_mutex(); while( names[j] && *names[j] != '*' ) { nm = names[j]; @@ -43,6 +45,7 @@ EntNode::EntNode( const char ** names ) { // prev. prev or prev2 may = NULL if newnode belongs at the end of // the list or before the beginning, respectively. newnode = new EntNode( nm ); + newnode->sharedMtxP = firstnode->sharedMtxP; newnode->next = prev; if( prev2 == NULL ) { // This will be the case if the inner while was never entered. @@ -64,6 +67,8 @@ EntNode::EntNode( const char ** names ) { *this = *firstnode; firstnode->next = NULL; // (Otherwise, deleting firstnode would delete entire list.) + firstnode->sharedMtxP = NULL; + // (Otherwise, deleting firstnode would delete the sharedMtxP list.) delete firstnode; } @@ -71,10 +76,14 @@ EntNode::EntNode( const char ** names ) { * Copies all of ent's values here. */ EntNode & EntNode::operator= ( EntNode & ent ) { + assert( ent.sharedMtxP != 0 && "equality operator being used to assign an EntNode to another EntNode which is not a part of a list. (Not Supported)" ); + ent.sharedMtxP->lock(); // Makes the assignment consistent + sharedMtxP = ent.sharedMtxP; Name( ent.name ); setmark( ent.mark ); multSuprs( ent.multSupers ); next = ent.next; + ent.sharedMtxP->unlock(); return *this; } @@ -84,10 +93,12 @@ EntNode & EntNode::operator= ( EntNode & ent ) { void EntNode::markAll( MarkType stamp ) { EntNode * node = this; + sharedMtxP->lock(); // Protects the iteraton (as the next pointer can change in the sort function) while( node != NULL ) { node->mark = stamp; node = node->next; } + sharedMtxP->unlock(); } /** @@ -95,14 +106,18 @@ void EntNode::markAll( MarkType stamp ) { */ bool EntNode::allMarked() { EntNode * node = this; + bool result = true; + sharedMtxP->lock(); // Protects the iteraton (as the next pointer can change in the sort function) while( node != NULL ) { if( node->mark == NOMARK ) { - return false; + result = false; + break; } node = node->next; } - return true; + sharedMtxP->unlock(); + return result; } /** @@ -112,12 +127,14 @@ int EntNode::unmarkedCount() { int count = 0; EntNode * node = this; + sharedMtxP->lock(); // Protects the iteraton (as the next pointer can change in the sort function) while( node != NULL ) { if( node->mark == NOMARK ) { count++; } node = node->next; } + sharedMtxP->unlock(); return count; } @@ -127,7 +144,7 @@ int EntNode::unmarkedCount() { */ EntNode * EntNode::lastSmaller( EntNode * ent ) { EntNode * eptr = next, *prev = this; - + // no locking is used here as this function is always called from EntNode::sort. if( *this > *ent ) { return NULL; } @@ -150,6 +167,7 @@ EntNode * EntNode::lastSmaller( EntNode * ent ) { void EntNode::sort( EntNode ** first ) { EntNode * eptr1, *eptr2, *temp1, *temp2; + sharedMtxP->lock(); while( next && *this > *next ) { // Find the earliest node greater than next. (I.e., is not only this > @@ -189,4 +207,5 @@ void EntNode::sort( EntNode ** first ) { if( next ) { next->sort( first ); } + sharedMtxP->unlock(); } From ca7594bd758001f6a9fc0099548b39f7169ac88e Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 13 Jul 2014 22:43:40 +0530 Subject: [PATCH 066/111] Removed garbage characters --- src/clstepcore/SingleLinkList.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/clstepcore/SingleLinkList.h b/src/clstepcore/SingleLinkList.h index 600c32a6d..e4e848afc 100644 --- a/src/clstepcore/SingleLinkList.h +++ b/src/clstepcore/SingleLinkList.h @@ -24,9 +24,7 @@ class SC_CORE_EXPORT SingleLinkList { class SingleLinkNode * head; SingleLinkNode * tail; -Made STEPaggregrate thread safe. -This was done by relying on the mtx used by its superclass: SingleLinkList. public: // had to be made into a pointer due to the equality // operator being used elswhere for SingleLinkList object From 25081dfa0e0e8190eeaa25b2fd383e964d310bd1 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 18 Jul 2014 14:35:31 +0530 Subject: [PATCH 067/111] Removed the infinite recursion bug in STEPattribute The bug would surface if a STEPattribute instance which has been redefined, has its ShallowCopy function invoked. --- src/clstepcore/STEPattribute.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clstepcore/STEPattribute.cc b/src/clstepcore/STEPattribute.cc index 608f6ae5b..ac38767c1 100644 --- a/src/clstepcore/STEPattribute.cc +++ b/src/clstepcore/STEPattribute.cc @@ -606,7 +606,7 @@ void STEPattribute::ShallowCopy( const STEPattribute * sa ) { _derive = sa->_derive; _redefAttr = sa->_redefAttr; if( _redefAttr ) { - _redefAttr->ShallowCopy( sa ); + ShallowCopy( _redefAttr ); } //Should we just use memcpy()? That would be a true shallowCopy switch( sa->NonRefType() ) { From 10f041c779642474f36d234f561c0131352bef12 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 18 Jul 2014 14:46:45 +0530 Subject: [PATCH 068/111] Made STEPattributeList thread safe Couple of functions were identified as vulnerable. The mutex defined in the superclass SingleLinkList was used. --- src/clstepcore/STEPattributeList.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/clstepcore/STEPattributeList.cc b/src/clstepcore/STEPattributeList.cc index 7774321b2..12d84bc3c 100644 --- a/src/clstepcore/STEPattributeList.cc +++ b/src/clstepcore/STEPattributeList.cc @@ -30,6 +30,7 @@ STEPattributeList::~STEPattributeList() { STEPattribute & STEPattributeList::operator []( int n ) { int x = 0; + mtxP->lock(); AttrListNode * a = ( AttrListNode * )head; int cnt = EntryCount(); if( n < cnt ) { @@ -39,12 +40,15 @@ STEPattribute & STEPattributeList::operator []( int n ) { } } if( a ) { - return *( a->attr ); + STEPattribute * attr = a->attr; + mtxP->unlock(); + return *( attr ); } // else cerr << "\nERROR in STEP Core library: " << __FILE__ << ":" << __LINE__ << "\n" << _POC_ << "\n\n"; + mtxP->unlock(); return *( STEPattribute * ) 0; } @@ -53,11 +57,13 @@ int STEPattributeList::list_length() { } void STEPattributeList::push( STEPattribute * a ) { + mtxP->lock(); AttrListNode * a2 = ( AttrListNode * )head; // if the attribute already exists in the list, don't push it while( a2 ) { if( *a == *( a2 -> attr ) ) { + mtxP->unlock(); return; } a2 = ( AttrListNode * )( a2->next ); @@ -65,4 +71,5 @@ void STEPattributeList::push( STEPattribute * a ) { a->incrRefCount(); AttrListNode * saln = new AttrListNode( a ); AppendNode( saln ); + mtxP->unlock(); } From 1aa1ed110f87391e98ab4e7b9dab8c654c859835 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 18 Jul 2014 14:54:19 +0530 Subject: [PATCH 069/111] Redefined GetMiEntity API GetMiEntity function is a part of SDAI_Application_instance class. The function now accepts const char * (instead of char *) as parameter. --- src/clstepcore/sdaiApplication_instance.cc | 6 +++--- src/clstepcore/sdaiApplication_instance.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/clstepcore/sdaiApplication_instance.cc b/src/clstepcore/sdaiApplication_instance.cc index 6706e363b..367560605 100644 --- a/src/clstepcore/sdaiApplication_instance.cc +++ b/src/clstepcore/sdaiApplication_instance.cc @@ -57,8 +57,8 @@ SDAI_Application_instance::~SDAI_Application_instance() { do { attr = NextAttribute(); if( attr ) { - attr->refCount --; - if( attr->refCount <= 0 ) { + attr->decrRefCount(); + if( attr->getRefCount() <= 0 ) { delete attr; } } @@ -141,7 +141,7 @@ void SDAI_Application_instance::AppendMultInstance( SDAI_Application_instance * // BUG implement this -- FIXME function is never used -SDAI_Application_instance * SDAI_Application_instance::GetMiEntity( char * entName ) { +SDAI_Application_instance * SDAI_Application_instance::GetMiEntity( const char * entName ) { std::string s1, s2; const EntityDescLinkNode * edln = 0; diff --git a/src/clstepcore/sdaiApplication_instance.h b/src/clstepcore/sdaiApplication_instance.h index 072d5da73..6f6a0d80b 100644 --- a/src/clstepcore/sdaiApplication_instance.h +++ b/src/clstepcore/sdaiApplication_instance.h @@ -129,7 +129,7 @@ class SC_CORE_EXPORT SDAI_Application_instance : public SDAI_DAObject_SDAI { SDAI_Application_instance * GetNextMiEntity() { return nextMiEntity; } - SDAI_Application_instance * GetMiEntity( char * entName ); + SDAI_Application_instance * GetMiEntity( const char * entName ); void AppendMultInstance( SDAI_Application_instance * se ); protected: From 62761ceba8ba9506181672742a6cd2e2d807fd88 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 18 Jul 2014 15:00:28 +0530 Subject: [PATCH 070/111] Added test for checking thread safety This test would check thread safety for AppendMultInstance & GetMiEntity functions in class SDAI_Application_instance. The tests failed for both. Rest of the functions were not checked since the locking in them was trivial. --- src/clstepcore/CMakeLists.txt | 4 + ...Application_instance_thread_safety_test.cc | 206 ++++++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 src/clstepcore/sdaiApplication_instance_thread_safety_test.cc diff --git a/src/clstepcore/CMakeLists.txt b/src/clstepcore/CMakeLists.txt index d3d3e5551..bca5fb297 100644 --- a/src/clstepcore/CMakeLists.txt +++ b/src/clstepcore/CMakeLists.txt @@ -80,6 +80,10 @@ if(HAVE_STD_THREAD) SC_ADDEXEC(Registry_thread_safety_test "Registry_thread_safety_test.cc" "stepcore" ) set_target_properties(Registry_thread_safety_test PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD") target_link_libraries(Registry_thread_safety_test "pthread" ) + + SC_ADDEXEC(sdaiApplication_instance_thread_safety_test "sdaiApplication_instance_thread_safety_test.cc" "stepcore" ) + set_target_properties(sdaiApplication_instance_thread_safety_test PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD") + target_link_libraries(sdaiApplication_instance_thread_safety_test "pthread" ) endif(HAVE_STD_THREAD) install(FILES ${SC_CLSTEPCORE_HDRS} diff --git a/src/clstepcore/sdaiApplication_instance_thread_safety_test.cc b/src/clstepcore/sdaiApplication_instance_thread_safety_test.cc new file mode 100644 index 000000000..fac9c4bc7 --- /dev/null +++ b/src/clstepcore/sdaiApplication_instance_thread_safety_test.cc @@ -0,0 +1,206 @@ +#include +#include +#include +#include + +#ifdef HAVE_STD_THREAD +# include +#else +# error Need std::thread for this test! +#endif + +#include "ExpDict.h" +#include "baseType.h" +#include "sdaiApplication_instance.h" + +typedef std::vector sdaiVec_t; +/// Will be populated in the createInstanceList function +std::vector< std::string > EntityNames; + +// populates the vector names[] with string of the form [A-Z]/[a-z]/[a-z] +void populateNamesVector() { + char ch[4]; + ch[3] = '\0'; + ch[0] = 'A'; + while( ch[0] <= 'Z') + { + ch[1] = 'a'; + while( ch[1] <= 'z') + { + ch[2] = '0'; + while( ch[2] <= '9') + { + string str( ch ); + EntityNames.push_back( str ); + ch[2]++; + } + ch[1]++; + } + ch[0]++; + } +} + +// creates a List of sdaiApplication_instance's, along with initializing its eDesc. +void createInstanceList( sdaiVec_t & sdaiVec ) { + const int size = 1000; + assert( size > 10 && size % 4 == 0 && "size of the sdaiVec should be greater then 10 and multiple of 4" ); // A hard reminder + populateNamesVector(); + + assert( ( int )EntityNames.size() >= size && "EntityNames vector is smaller then sdaiVec size" ); + SDAI_Application_instance * sai; + for( int i = 0; i < size; i++ ) { + sai = new SDAI_Application_instance( i+1 ); + sai->eDesc = new EntityDescriptor( EntityNames[i].c_str(), ( Schema * ) NULL, LTrue, LFalse ); + sdaiVec.push_back( sai ); + } +} + +// deletes the sdaiApplication_instances from the given vector. +void deleteInstanceList( sdaiVec_t & sdaiVec ) { + int size = sdaiVec.size(); + for( int i = 0; i < size; i++ ) { + delete sdaiVec[i]->eDesc; + delete sdaiVec[i]; + } + sdaiVec.clear(); +} + +// appends the sdaiApplication_instances from a certain section of the list to sai. (upper and lower limits are inclusive) +void appendListTo( SDAI_Application_instance * sai, sdaiVec_t & sdaiVec, int llimit, int ulimit ) { + for( int i = llimit; i <= ulimit; i++ ) { + sai->AppendMultInstance( sdaiVec[i] ); + } +} + +// searches for the sdaiApplication_instances belonging to ahe certain section of the list from sai. (upper and lower limits are inclusive) +// nullAllowedIndex marks the index after which GetMiEntity is allowed to return a NULL value +void searchForElements( SDAI_Application_instance * sai, sdaiVec_t & sdaiVec, int llimit, int ulimit, int nullAllowedIndex, bool * errorInFinding ) { + SDAI_Application_instance * saiFound; + for( int i = llimit; i <= ulimit; i++ ) { + saiFound = sai->GetMiEntity( EntityNames[i].c_str() ); + if( saiFound != sdaiVec[i] ) { + if( saiFound == NULL && i >= nullAllowedIndex ) { + continue; + } else if( i < nullAllowedIndex ) { + std::cout << "Disparity in the confirmed region" << std::endl; + } else /* if( saiFound != NULL ) */ { + std::cout << "Non Null Disparity in the unconfirmed region" << std::endl; + } + *errorInFinding = true; + return; + } + } + *errorInFinding = false; +} + +// compares the sdaiApplication_instance's list (headed by sai) with sdaiVec and reports any disparity. +bool validate( SDAI_Application_instance * sai, sdaiVec_t & sdaiVec ) { + int size = sdaiVec.size(); + int saiSize = 0; + SDAI_Application_instance * next = sai; + while( next ) { + saiSize++; + next = next->GetNextMiEntity(); + } + + if( saiSize != size ) { + std::cout << "Expected size: " << size << "\tActual size: "<< saiSize << std::endl; + return false; + } + + for( int i = 0; i < size; i++ ) { + if( sdaiVec[i] != sai->GetMiEntity( EntityNames[i].c_str() ) ) { + std::cout << "Address are different" << std::endl; + return false; + } + } + + return true; +} + +// checks thread safety of two intertwine append operations. +bool checkAddAddInstance() { + sdaiVec_t sdaiVec; + std::cout << "Checking thread safety in Adding Instances to a sdaiApplication_instance ..."; + + const int iterations = 10; + int i, size; + for( i = 0; i < iterations; i++ ) { + createInstanceList( sdaiVec ); + size = sdaiVec.size(); + + appendListTo( sdaiVec[0], sdaiVec, 1, 4 ); //Initializing List before test + + std::thread first( appendListTo, sdaiVec[0], sdaiVec, 5, size/2 ); + std::thread second( appendListTo, sdaiVec[4], sdaiVec, ( size/2 )+1 , size-1 ); + + first.join(); + second.join(); + + if ( !validate( sdaiVec[0], sdaiVec ) ) { + break; + } + deleteInstanceList( sdaiVec ); + } + + if( i == iterations ) { + std::cout << "...PASS" << std::endl; + return true; + } else { + std::cout << "...FAIL" << std::endl; + return false; + } +} + +// checks thread safety of two intertwine append operations and an append operation with GetMiEntity operation (which may or may not return a null value) +bool checkAddAddGetInstance() { + sdaiVec_t sdaiVec; + std::cout << "Checking thread safety in Adding Instances to a sdaiApplication_instance ..."; + + const int iterations = 10; + int i, size; + for( i = 0; i < iterations; i++ ) { + createInstanceList( sdaiVec ); + size = sdaiVec.size(); + + appendListTo( sdaiVec[0], sdaiVec, 1, 4 ); //Initializing List before test + + // The elements added by the two threads are in the ratio 1:3 + std::thread first( appendListTo, sdaiVec[0], sdaiVec, 5, size/4 ); + std::thread second( appendListTo, sdaiVec[4], sdaiVec, ( size/4 )+1 , size-1 ); + + first.join(); + + bool errorInFinding; + //search for first half of the sdaiApplication_instances. 1/4 elements will be present. rest 1/4 elements may / may not be present + std::thread third( searchForElements, sdaiVec[0], sdaiVec, 0, size/2, size/4, &errorInFinding ); + + second.join(); + third.join(); + + if ( errorInFinding || !validate( sdaiVec[0], sdaiVec ) ) { + break; + } + deleteInstanceList( sdaiVec ); + } + + if( i == iterations ) { + std::cout << "...PASS" << std::endl; + return true; + } else { + std::cout << "...FAIL" << std::endl; + return false; + } +} + +int main( int, char ** ) { + bool pass = true; + pass &= checkAddAddInstance(); + pass &= checkAddAddGetInstance(); + + if( pass ) { + exit( EXIT_SUCCESS ); + } + exit( EXIT_FAILURE ); +} + From 66999c76aad3a6f89494f177ed96182471d25d05 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 18 Jul 2014 16:02:12 +0530 Subject: [PATCH 071/111] Internal changes in sdaiApplication_instance.cc These changes have been done to facitilate the use of mutexes to make the SDAI_Application_instance class thread safe. (No mutex has been used introduced yet) --- src/clstepcore/sdaiApplication_instance.cc | 63 ++++++++++++---------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/src/clstepcore/sdaiApplication_instance.cc b/src/clstepcore/sdaiApplication_instance.cc index 367560605..691b67d65 100644 --- a/src/clstepcore/sdaiApplication_instance.cc +++ b/src/clstepcore/sdaiApplication_instance.cc @@ -72,6 +72,7 @@ SDAI_Application_instance::~SDAI_Application_instance() { SDAI_Application_instance * SDAI_Application_instance::Replicate() { char errStr[BUFSIZ]; + SDAI_Application_instance * seNew; if( IsComplex() ) { cerr << "STEPcomplex::Replicate() should be called: " << __FILE__ << __LINE__ << "\n" << _POC_ "\n"; @@ -82,16 +83,16 @@ SDAI_Application_instance * SDAI_Application_instance::Replicate() { _error.AppendToDetailMsg( errStr ); _error.AppendToUserMsg( errStr ); _error.GreaterSeverity( SEVERITY_BUG ); - return S_ENTITY_NULL; + seNew = S_ENTITY_NULL; } else { if( !eDesc ) { - return S_ENTITY_NULL; + seNew = S_ENTITY_NULL; } - SDAI_Application_instance * seNew = eDesc->NewSTEPentity(); + seNew = eDesc->NewSTEPentity(); seNew -> CopyAs( this ); - return seNew; } + return seNew; } void SDAI_Application_instance::AddP21Comment( const char * s, bool replace ) { @@ -126,11 +127,12 @@ const char * SDAI_Application_instance::STEPwrite_reference( std::string & buf ) } void SDAI_Application_instance::AppendMultInstance( SDAI_Application_instance * se ) { + SDAI_Application_instance * link; + SDAI_Application_instance * linkTrailing = this; if( nextMiEntity == 0 ) { nextMiEntity = se; } else { - SDAI_Application_instance * link = nextMiEntity; - SDAI_Application_instance * linkTrailing = 0; + link = nextMiEntity; while( link ) { linkTrailing = link; link = link->nextMiEntity; @@ -143,6 +145,7 @@ void SDAI_Application_instance::AppendMultInstance( SDAI_Application_instance * SDAI_Application_instance * SDAI_Application_instance::GetMiEntity( const char * entName ) { std::string s1, s2; + SDAI_Application_instance * mie = 0; const EntityDescLinkNode * edln = 0; const EntityDescriptor * ed = eDesc; @@ -161,9 +164,9 @@ SDAI_Application_instance * SDAI_Application_instance::GetMiEntity( const char * } // search alternate parent path since didn't find it in this one. if( nextMiEntity ) { - return nextMiEntity->GetMiEntity( entName ); + mie = nextMiEntity->GetMiEntity( entName ); } - return 0; + return mie; } @@ -231,10 +234,11 @@ void SDAI_Application_instance::CopyAs( SDAI_Application_instance * other ) { const char * SDAI_Application_instance::EntityName( const char * schnm ) const { - if( !eDesc ) { - return NULL; + const char * en = NULL; + if( eDesc ) { + en = eDesc->Name( schnm ); } - return eDesc->Name( schnm ); + return en; } /** @@ -242,10 +246,11 @@ const char * SDAI_Application_instance::EntityName( const char * schnm ) const { * type as this one */ const EntityDescriptor * SDAI_Application_instance::IsA( const EntityDescriptor * ed ) const { - if( !eDesc ) { - return NULL; + const EntityDescriptor * edA = NULL; + if( eDesc ) { + edA = ( eDesc->IsA( ed ) ); } - return ( eDesc->IsA( ed ) ); + return edA; } /** @@ -263,7 +268,8 @@ Severity SDAI_Application_instance::ValidLevel( ErrorDescriptor * error, InstMgr error->GreaterSeverity( attributes[i].ValidLevel( attributes[i].asStr().c_str(), &err, im, 0 ) ); } - return error->severity(); + Severity sev = error->severity(); + return sev; } /** @@ -502,7 +508,8 @@ Severity SDAI_Application_instance::STEPread( int id, int idIncr, if( n == 0 ) { // no attributes in >> c; // look for the close paren if( c == ')' ) { - return _error.severity(); + severe = _error.severity(); + return severe; } } @@ -576,11 +583,9 @@ Severity SDAI_Application_instance::STEPread( int id, int idIncr, "attribute is mapped as an asterisk so needs delimiter.\n" ); } CheckRemainingInput( in, &_error, "ENTITY", ",)" ); - if( !in.good() ) { - return _error.severity(); - } - if( _error.severity() <= SEVERITY_INPUT_ERROR ) { - return _error.severity(); + severe = _error.severity(); + if( !in.good() || severe <= SEVERITY_INPUT_ERROR ) { + return severe; } } else if( c == ')' ) { while( i < n - 1 ) { @@ -590,11 +595,12 @@ Severity SDAI_Application_instance::STEPread( int id, int idIncr, _error.AppendToDetailMsg( "Missing attribute value[s].\n" ); // recoverable error _error.GreaterSeverity( SEVERITY_WARNING ); - return _error.severity(); + break; } i++; } - return _error.severity(); + severe = _error.severity(); + return severe; } } STEPread_error( c, i, in, currSch ); @@ -626,7 +632,8 @@ Severity SDAI_Application_instance::STEPread( int id, int idIncr, sprintf( errStr, "\nfinished reading #%d\n", STEPfile_id ); _error.AppendToDetailMsg( errStr ); // end of imported code - return _error.severity(); + severe = _error.severity(); + return severe; } /// read an entity reference and return a pointer to the SDAI_Application_instance @@ -890,13 +897,13 @@ Severity EntityValidLevel( const char * attrValue, // string contain entity ref ** \Returns reference to an attribute pointer ******************************************************************/ STEPattribute * SDAI_Application_instance::NextAttribute() { + STEPattribute * sa = 0; int i = AttributeCount(); ++_cur; - if( i < _cur ) { - return 0; + if( i >= _cur ) { + sa = &attributes [_cur - 1]; } - return &attributes [_cur - 1]; - + return sa; } int SDAI_Application_instance::AttributeCount() { From cdede9ee274b2558537f940566eb515cc5f18eb7 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 18 Jul 2014 20:49:02 +0530 Subject: [PATCH 072/111] Made SDAI_Application_instance thread safe. This was done by introducing a mutex for each SDAI_Application_instance. AppendMultInstance was made thread safe by doing hand to hand locking. GetMiEntity was made thread safe acquiring locks in increasing order and releasing locks in decreasing order. The checks in sdaiApplication_instance_thread_safety_test now pass. --- src/clstepcore/sdaiApplication_instance.cc | 55 +++++++++++++++++++++- src/clstepcore/sdaiApplication_instance.h | 3 ++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/clstepcore/sdaiApplication_instance.cc b/src/clstepcore/sdaiApplication_instance.cc index 691b67d65..b754d54a4 100644 --- a/src/clstepcore/sdaiApplication_instance.cc +++ b/src/clstepcore/sdaiApplication_instance.cc @@ -73,6 +73,7 @@ SDAI_Application_instance::~SDAI_Application_instance() { SDAI_Application_instance * SDAI_Application_instance::Replicate() { char errStr[BUFSIZ]; SDAI_Application_instance * seNew; + mtx.lock(); // protects _error if( IsComplex() ) { cerr << "STEPcomplex::Replicate() should be called: " << __FILE__ << __LINE__ << "\n" << _POC_ "\n"; @@ -92,27 +93,34 @@ SDAI_Application_instance * SDAI_Application_instance::Replicate() { seNew = eDesc->NewSTEPentity(); seNew -> CopyAs( this ); } + mtx.unlock(); return seNew; } void SDAI_Application_instance::AddP21Comment( const char * s, bool replace ) { + mtx.lock(); // protects p21Comment if( replace ) { p21Comment.clear(); } if( s ) { p21Comment += s; } + mtx.unlock(); } void SDAI_Application_instance::AddP21Comment( const std::string & s, bool replace ) { + mtx.lock(); // protects p21Comment if( replace ) { p21Comment.clear(); } p21Comment += s; + mtx.unlock(); } void SDAI_Application_instance::PrependP21Comment( const std::string & s ) { + mtx.lock(); // protects p21Comment p21Comment.insert( 0, s ); + mtx.unlock(); } void SDAI_Application_instance::STEPwrite_reference( ostream & out ) { @@ -129,16 +137,22 @@ const char * SDAI_Application_instance::STEPwrite_reference( std::string & buf ) void SDAI_Application_instance::AppendMultInstance( SDAI_Application_instance * se ) { SDAI_Application_instance * link; SDAI_Application_instance * linkTrailing = this; + linkTrailing->mtx.lock(); // protects nextMiEntity and the link loop if( nextMiEntity == 0 ) { nextMiEntity = se; } else { link = nextMiEntity; while( link ) { + //hand to hand locking + link->mtx.lock(); //acquire lock for nextMiEntity + linkTrailing->mtx.unlock();//release lock trailing MiEntity. + linkTrailing = link; link = link->nextMiEntity; } linkTrailing->nextMiEntity = se; } + linkTrailing->mtx.unlock(); } // BUG implement this -- FIXME function is never used @@ -147,12 +161,14 @@ SDAI_Application_instance * SDAI_Application_instance::GetMiEntity( const char * std::string s1, s2; SDAI_Application_instance * mie = 0; + mtx.lock(); // protects the ed loop const EntityDescLinkNode * edln = 0; const EntityDescriptor * ed = eDesc; // compare up the *leftmost* parent path while( ed ) { if( !strcmp( StrToLower( ed->Name(), s1 ), StrToLower( entName, s2 ) ) ) { + mtx.unlock(); return this; // return this parent path } edln = ( EntityDescLinkNode * )( ed->Supertypes().GetHead() ); @@ -164,8 +180,11 @@ SDAI_Application_instance * SDAI_Application_instance::GetMiEntity( const char * } // search alternate parent path since didn't find it in this one. if( nextMiEntity ) { + nextMiEntity->mtx.lock(); //lock is acquired increasing order mie = nextMiEntity->GetMiEntity( entName ); + nextMiEntity->mtx.unlock();//locks are released in the reverse order } + mtx.unlock(); return mie; } @@ -181,6 +200,7 @@ STEPattribute * SDAI_Application_instance::GetSTEPattribute( const char * nm, co } STEPattribute * a = 0; + mtx.lock(); // protects attribute loop ResetAttributes(); // keep going until no more attributes, or attribute is found while( ( a = NextAttribute() ) ) { @@ -191,17 +211,20 @@ STEPattribute * SDAI_Application_instance::GetSTEPattribute( const char * nm, co } } + mtx.unlock(); return a; } STEPattribute * SDAI_Application_instance::MakeRedefined( STEPattribute * redefiningAttr, const char * nm ) { // find the attribute being redefined + mtx.lock(); // protects the redefine operation (from a possible pointer exception) STEPattribute * a = GetSTEPattribute( nm ); // assign its pointer to the redefining attribute if( a ) { a->RedefiningAttr( redefiningAttr ); } + mtx.unlock(); return a; } @@ -211,14 +234,17 @@ STEPattribute * SDAI_Application_instance::MakeRedefined( STEPattribute * redefi * \param entity If not null, check that the attribute comes from this entity. When called from generated code, this is used to ensure that the correct attr is marked as derived. Issue #232 */ STEPattribute * SDAI_Application_instance::MakeDerived( const char * nm, const char * entity ) { + mtx.lock(); STEPattribute * a = GetSTEPattribute( nm, entity ); if( a ) { a ->Derive(); } + mtx.unlock(); return a; } void SDAI_Application_instance::CopyAs( SDAI_Application_instance * other ) { + mtx.lock(); int numAttrs = AttributeCount(); ResetAttributes(); other -> ResetAttributes(); @@ -230,14 +256,17 @@ void SDAI_Application_instance::CopyAs( SDAI_Application_instance * other ) { this_attr -> ShallowCopy( other_attr ); numAttrs--; } + mtx.unlock(); } const char * SDAI_Application_instance::EntityName( const char * schnm ) const { const char * en = NULL; + mtx.lock(); if( eDesc ) { en = eDesc->Name( schnm ); } + mtx.unlock(); return en; } @@ -247,9 +276,11 @@ const char * SDAI_Application_instance::EntityName( const char * schnm ) const { */ const EntityDescriptor * SDAI_Application_instance::IsA( const EntityDescriptor * ed ) const { const EntityDescriptor * edA = NULL; + mtx.lock(); if( eDesc ) { edA = ( eDesc->IsA( ed ) ); } + mtx.unlock(); return edA; } @@ -259,6 +290,7 @@ const EntityDescriptor * SDAI_Application_instance::IsA( const EntityDescriptor Severity SDAI_Application_instance::ValidLevel( ErrorDescriptor * error, InstMgr * im, int clearError ) { ErrorDescriptor err; + mtx.lock(); if( clearError ) { ClearError(); } @@ -269,6 +301,7 @@ Severity SDAI_Application_instance::ValidLevel( ErrorDescriptor * error, InstMgr attributes[i].asStr().c_str(), &err, im, 0 ) ); } Severity sev = error->severity(); + mtx.unlock(); return sev; } @@ -276,10 +309,12 @@ Severity SDAI_Application_instance::ValidLevel( ErrorDescriptor * error, InstMgr * clears all attr's errors */ void SDAI_Application_instance::ClearAttrError() { + mtx.lock(); // For n int n = attributes.list_length(); for( int i = 0 ; i < n; i++ ) { attributes[i].Error().ClearErrorMsg(); } + mtx.unlock(); } /** @@ -302,6 +337,7 @@ void SDAI_Application_instance::beginSTEPwrite( ostream & out ) { out << "begin STEPwrite ... \n" ; out.flush(); + mtx.lock(); // For n int n = attributes.list_length(); for( int i = 0 ; i < n; i++ ) { if( attributes[i].Type() == ENTITY_TYPE @@ -309,6 +345,7 @@ void SDAI_Application_instance::beginSTEPwrite( ostream & out ) { ( *( attributes[i].ptr.c ) ) -> STEPwrite(); } } + mtx.unlock(); } /**************************************************************//** @@ -327,6 +364,7 @@ void SDAI_Application_instance::STEPwrite( ostream & out, const char * currSch, } out << "#" << STEPfile_id << "=" << StrToUpper( EntityName( currSch ), tmp ) << "("; + mtx.lock(); // protects n, loop int n = attributes.list_length(); for( int i = 0 ; i < n; i++ ) { @@ -337,6 +375,7 @@ void SDAI_Application_instance::STEPwrite( ostream & out, const char * currSch, ( attributes[i] ).STEPwrite( out, currSch ); } } + mtx.unlock(); out << ");\n"; } @@ -350,6 +389,7 @@ void SDAI_Application_instance::WriteValuePairs( ostream & out, int writeComments, int mixedCase ) { std::string s, tmp, tmp2; + mtx.lock(); if( writeComments && !p21Comment.empty() ) { out << p21Comment; } @@ -382,6 +422,7 @@ void SDAI_Application_instance::WriteValuePairs( ostream & out, } } out << endl; + mtx.unlock(); } @@ -398,6 +439,7 @@ const char * SDAI_Application_instance::STEPwrite( std::string & buf, const char sprintf( instanceInfo, "#%d=%s(", STEPfile_id, StrToUpper( EntityName( currSch ), tmp ) ); buf.append( instanceInfo ); + mtx.lock(); int n = attributes.list_length(); for( int i = 0 ; i < n; i++ ) { @@ -410,6 +452,7 @@ const char * SDAI_Application_instance::STEPwrite( std::string & buf, const char } } buf.append( ");" ); + mtx.unlock(); return const_cast( buf.c_str() ); } @@ -417,12 +460,14 @@ void SDAI_Application_instance::PrependEntityErrMsg() { char errStr[BUFSIZ]; errStr[0] = '\0'; + mtx.lock(); if( _error.severity() == SEVERITY_NULL ) { // if there is not an error already sprintf( errStr, "\nERROR: ENTITY #%d %s\n", GetFileId(), EntityName() ); _error.PrependToDetailMsg( errStr ); } + mtx.unlock(); } /**************************************************************//** @@ -438,6 +483,7 @@ void SDAI_Application_instance::STEPread_error( char c, int i, istream & in, con char errStr[BUFSIZ]; errStr[0] = '\0'; + mtx.lock(); if( _error.severity() == SEVERITY_NULL ) { // if there is not an error already sprintf( errStr, "\nERROR: ENTITY #%d %s\n", GetFileId(), @@ -465,7 +511,7 @@ void SDAI_Application_instance::STEPread_error( char c, int i, istream & in, con sprintf( errStr, "\nfinished reading #%d\n", STEPfile_id ); _error.AppendToDetailMsg( errStr ); - return; + mtx.unlock(); } /**************************************************************//** @@ -492,6 +538,7 @@ Severity SDAI_Application_instance::STEPread( int id, int idIncr, Severity severe; int i = 0; + mtx.lock(); ClearError( 1 ); in >> ws; @@ -509,6 +556,7 @@ Severity SDAI_Application_instance::STEPread( int id, int idIncr, in >> c; // look for the close paren if( c == ')' ) { severe = _error.severity(); + mtx.unlock(); return severe; } } @@ -585,6 +633,7 @@ Severity SDAI_Application_instance::STEPread( int id, int idIncr, CheckRemainingInput( in, &_error, "ENTITY", ",)" ); severe = _error.severity(); if( !in.good() || severe <= SEVERITY_INPUT_ERROR ) { + mtx.unlock(); return severe; } } else if( c == ')' ) { @@ -600,6 +649,7 @@ Severity SDAI_Application_instance::STEPread( int id, int idIncr, i++; } severe = _error.severity(); + mtx.unlock(); return severe; } } @@ -633,6 +683,7 @@ Severity SDAI_Application_instance::STEPread( int id, int idIncr, _error.AppendToDetailMsg( errStr ); // end of imported code severe = _error.severity(); + mtx.unlock(); return severe; } @@ -898,11 +949,13 @@ Severity EntityValidLevel( const char * attrValue, // string contain entity ref ******************************************************************/ STEPattribute * SDAI_Application_instance::NextAttribute() { STEPattribute * sa = 0; + mtx.lock(); int i = AttributeCount(); ++_cur; if( i >= _cur ) { sa = &attributes [_cur - 1]; } + mtx.unlock(); return sa; } diff --git a/src/clstepcore/sdaiApplication_instance.h b/src/clstepcore/sdaiApplication_instance.h index 6f6a0d80b..56ec7329a 100644 --- a/src/clstepcore/sdaiApplication_instance.h +++ b/src/clstepcore/sdaiApplication_instance.h @@ -13,6 +13,7 @@ */ #include +#include /////////////////////////////////////////////////////////////////////////////// // SDAI_Application_instance used to be STEPentity @@ -40,6 +41,8 @@ class SC_CORE_EXPORT SDAI_Application_instance : public SDAI_DAObject_SDAI { /// these form a chain of other entity parents for multiple inheritance SDAI_Application_instance * nextMiEntity; + mutable sc_recursive_mutex mtx; + protected: int _complex; From 36d4876333d0d64cf50478e0266e947a7ffc606f Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Tue, 22 Jul 2014 10:54:10 +0530 Subject: [PATCH 073/111] Locking in ExpDict.cc There were some functions in ExpDict.cc that were not properly locked before. Locking was done in them --- src/clstepcore/ExpDict.cc | 73 +++++++++++++++++++++++++++++++-------- src/clstepcore/ExpDict.h | 2 +- 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/src/clstepcore/ExpDict.cc b/src/clstepcore/ExpDict.cc index 8c0b93b6a..2dbf69531 100644 --- a/src/clstepcore/ExpDict.cc +++ b/src/clstepcore/ExpDict.cc @@ -361,6 +361,7 @@ void Schema::GenerateUseRefExpress( ostream & out ) const { /// TYPE definitions void Schema::GenerateTypesExpress( ostream & out ) const { + _typeList.mtxP->lock(); TypeDescItr tdi( _typeList ); tdi.ResetItr(); std::string tmp; @@ -370,10 +371,12 @@ void Schema::GenerateTypesExpress( ostream & out ) const { out << endl << td->GenerateExpress( tmp ); td = tdi.NextTypeDesc(); } + _typeList.mtxP->unlock(); } /// Entity definitions void Schema::GenerateEntitiesExpress( ostream & out ) const { + _entList.mtxP->lock(); EntityDescItr edi( _entList ); edi.ResetItr(); std::string tmp; @@ -383,6 +386,7 @@ void Schema::GenerateEntitiesExpress( ostream & out ) const { out << endl << ed->GenerateExpress( tmp ); ed = edi.NextEntityDesc(); } + _entList.mtxP->unlock(); } /////////////////////////////////////////////////////////////////////////////// @@ -640,6 +644,7 @@ const char * EnumTypeDescriptor::GenerateExpress( std::string & buf ) const { /////////////// // count is # of WHERE rules if( _where_rules != 0 ) { + _where_rules->mtx.lock(); int all_comments = 1; int count = _where_rules->Count(); for( int i = 0; i < count; i++ ) { // print out each UNIQUE rule @@ -664,6 +669,7 @@ const char * EnumTypeDescriptor::GenerateExpress( std::string & buf ) const { buf.append( ( *( _where_rules ) )[i]->label_() ); } } + _where_rules->mtx.unlock(); } buf.append( "END_TYPE;\n" ); @@ -710,6 +716,7 @@ const char * EntityDescriptor::GenerateExpress( std::string & buf ) const { const EntityDescriptor * ed = 0; + _supertypes.mtxP->lock(); EntityDescItr edi_super( _supertypes ); edi_super.ResetItr(); ed = edi_super.NextEntityDesc(); @@ -728,9 +735,11 @@ const char * EntityDescriptor::GenerateExpress( std::string & buf ) const { if( supertypes ) { buf.append( ")" ); } + _supertypes.mtxP->unlock(); buf.append( ";\n" ); + _explicitAttr.mtxP->lock(); AttrDescItr adi( _explicitAttr ); adi.ResetItr(); @@ -759,8 +768,10 @@ const char * EntityDescriptor::GenerateExpress( std::string & buf ) const { } ad = adi.NextAttrDesc(); } + _explicitAttr.mtxP->unlock(); ///////// + _inverseAttr.mtxP->lock(); InverseAItr iai( _inverseAttr ); iai.ResetItr(); @@ -775,9 +786,11 @@ const char * EntityDescriptor::GenerateExpress( std::string & buf ) const { buf.append( ia->GenerateExpress( sstr ) ); ia = iai.NextInverse_attribute(); } + _inverseAttr.mtxP->unlock(); /////////////// // count is # of UNIQUE rules if( _uniqueness_rules != 0 ) { + _uniqueness_rules->mtx.lock(); count = _uniqueness_rules->Count(); for( i = 0; i < count; i++ ) { // print out each UNIQUE rule if( !( *( _uniqueness_rules ) )[i]->_label.size() ) { @@ -802,11 +815,13 @@ const char * EntityDescriptor::GenerateExpress( std::string & buf ) const { buf.append( "\n" ); } } + _uniqueness_rules->mtx.unlock(); } /////////////// // count is # of WHERE rules if( _where_rules != 0 ) { + _where_rules->mtx.lock(); all_comments = 1; count = _where_rules->Count(); for( i = 0; i < count; i++ ) { // print out each UNIQUE rule @@ -832,6 +847,7 @@ const char * EntityDescriptor::GenerateExpress( std::string & buf ) const { buf.append( "\n" ); } } + _where_rules->mtx.unlock(); } buf.append( "END_ENTITY;\n" ); @@ -841,6 +857,7 @@ const char * EntityDescriptor::GenerateExpress( std::string & buf ) const { const char * EntityDescriptor::QualifiedName( std::string & s ) const { s.clear(); + _supertypes.mtxP->lock(); EntityDescItr edi( _supertypes ); int count = 1; @@ -853,6 +870,8 @@ const char * EntityDescriptor::QualifiedName( std::string & s ) const { count++; ed = edi.NextEntityDesc(); } + _supertypes.mtxP->unlock(); + if( count > 1 ) { s.append( "&" ); } @@ -870,16 +889,18 @@ const TypeDescriptor * EntityDescriptor::IsA( const TypeDescriptor * td ) const const EntityDescriptor * EntityDescriptor::IsA( const EntityDescriptor * other ) const { const EntityDescriptor * found = 0; - const EntityDescLinkNode * link = ( const EntityDescLinkNode * )( GetSupertypes().GetHead() ); + _supertypes.mtxP->lock(); + const EntityDescLinkNode * link = ( const EntityDescLinkNode * )( _supertypes.GetHead() ); if( this == other ) { - return other; + found = other; } else { while( link && ! found ) { found = link -> EntityDesc() -> IsA( other ); link = ( EntityDescLinkNode * ) link -> NextNode(); } } + _supertypes.mtxP->unlock(); return found; } @@ -920,10 +941,12 @@ Where_rule_ptr & Where_rule__list::operator[]( int index ) { } void Where_rule__list::Clear() { + mtx.lock(); for( int i = 0; i < _count ; i ++ ) { delete ( Where_rule_ptr )_buf[i]; } _count = 0; + mtx.unlock(); } /////////////////////////////////////////////////////////////////////////////// @@ -955,10 +978,12 @@ Uniqueness_rule_ptr & Uniqueness_rule__set::operator[]( int index ) { } void Uniqueness_rule__set::Clear() { + mtx.lock(); for( int i = 0; i < _count; i ++ ) { delete ( Uniqueness_rule_ptr )_buf[i]; } _count = 0; + mtx.unlock(); } /////////////////////////////////////////////////////////////////////////////// @@ -1022,10 +1047,12 @@ Global_rule_ptr & Global_rule__set::operator[]( int index ) { } void Global_rule__set::Clear() { + mtx.lock(); for( int i = 0; i < _count; i ++ ) { delete ( Global_rule_ptr )_buf[i]; } _count = 0; + mtx.unlock(); } @@ -1063,6 +1090,7 @@ const char * TypeDescriptor::GenerateExpress( std::string & buf ) const { /////////////// // count is # of WHERE rules if( _where_rules != 0 ) { + _where_rules->mtx.lock(); int all_comments = 1; int count = _where_rules->Count(); for( int i = 0; i < count; i++ ) { // print out each UNIQUE rule @@ -1087,6 +1115,7 @@ const char * TypeDescriptor::GenerateExpress( std::string & buf ) const { buf.append( ( *( _where_rules ) )[i]->label_() ); } } + _where_rules->mtx.unlock(); } buf.append( "END_TYPE;\n" ); @@ -1371,15 +1400,20 @@ const TypeDescriptor * SelectTypeDescriptor::CanBe( const TypeDescriptor * other return other; } - TypeDescItr elements( GetElements() ) ; + const TypeDescriptor * rettd = 0; + const TypeDescriptorList & tl = GetElements(); + tl.mtxP->lock(); + TypeDescItr elements( tl ) ; const TypeDescriptor * td = elements.NextTypeDesc(); while( td ) { if( td -> CanBe( other ) ) { - return td; + rettd = td; + break; } td = elements.NextTypeDesc(); } - return 0; + tl.mtxP->unlock(); + return rettd; } /** @@ -1388,21 +1422,26 @@ const TypeDescriptor * SelectTypeDescriptor::CanBe( const TypeDescriptor * other * type may be an element of a td for a select that is returned. */ const TypeDescriptor * SelectTypeDescriptor::CanBe( const char * other ) const { - TypeDescItr elements( GetElements() ) ; - const TypeDescriptor * td = 0; - // see if other is the select if( !StrCmpIns( _name, other ) ) { return this; } + const TypeDescriptor * td = 0; + const TypeDescriptor * rettd = 0; + const TypeDescriptorList & tl = GetElements(); + tl.mtxP->lock(); + + TypeDescItr elements( tl ) ; // see if other is one of the elements while( ( td = elements.NextTypeDesc() ) ) { if( td -> CanBe( other ) ) { - return td; + rettd = td; + break; } } - return 0; + tl.mtxP->unlock(); + return rettd; } /** @@ -1425,21 +1464,27 @@ const TypeDescriptor * SelectTypeDescriptor::CanBe( const char * other ) const { * from XX (A as B)"). */ const TypeDescriptor * SelectTypeDescriptor::CanBeSet( const char * other, const char * schNm ) const { - TypeDescItr elements( GetElements() ) ; + const TypeDescriptorList & tl = GetElements(); + tl.mtxP->lock(); + TypeDescItr elements( tl ) ; const TypeDescriptor * td = elements.NextTypeDesc(); + const TypeDescriptor * rettd = 0; while( td ) { if( td->Type() == REFERENCE_TYPE && td->NonRefType() == sdaiSELECT ) { // Just look at this level, don't look at my items (see intro). if( td->CurrName( other, schNm ) ) { - return td; + rettd = td; + break; } } else if( td->CanBeSet( other, schNm ) ) { - return td; + rettd = td; + break; } td = elements.NextTypeDesc(); } - return 0; + tl.mtxP->unlock(); + return rettd; } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/clstepcore/ExpDict.h b/src/clstepcore/ExpDict.h index 5529647ea..95ec73b6d 100644 --- a/src/clstepcore/ExpDict.h +++ b/src/clstepcore/ExpDict.h @@ -82,13 +82,13 @@ class SC_CORE_EXPORT Dictionary_instance__set { virtual int Count(); virtual void Clear(); + sc_recursive_mutex mtx; private: virtual void Check( int index ); protected: Dictionary_instance_ptr * _buf; int _bufsize; int _count; - sc_recursive_mutex mtx; }; /////////////////////////////////////////////////////////////////////////////// From 06b7ee58236316ad12b0d76680a731b8277632cb Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Tue, 22 Jul 2014 11:03:32 +0530 Subject: [PATCH 074/111] Made sdaiSelect::CanBe( BASE_TYPE ) thread safe. --- src/clstepcore/sdaiSelect.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/clstepcore/sdaiSelect.cc b/src/clstepcore/sdaiSelect.cc index 2914fa7c7..bb2bb3e51 100644 --- a/src/clstepcore/sdaiSelect.cc +++ b/src/clstepcore/sdaiSelect.cc @@ -84,9 +84,12 @@ SDAI_Select::CanBe( const char * n ) const { const TypeDescriptor * SDAI_Select::CanBe( BASE_TYPE bt ) const { - const TypeDescLinkNode * tdn = - ( const TypeDescLinkNode * ) _type -> GetElements().GetHead(); + const TypeDescriptorList & tl = _type -> GetElements(); + tl.mtxP->lock(); + + const TypeDescLinkNode * tdn = ( const TypeDescLinkNode * ) tl.GetHead(); const TypeDescriptor * td = tdn -> TypeDesc(); + const TypeDescriptor * rettd = 0; BASE_TYPE bt_thisnode; while( tdn ) { @@ -96,11 +99,13 @@ SDAI_Select::CanBe( BASE_TYPE bt ) const { ( bt_thisnode == LIST_TYPE ) || ( bt_thisnode == SET_TYPE ) || ( bt_thisnode == BAG_TYPE ) ) ) ) { - return td; // they are the same + rettd = td; // they are the same + break; } tdn = ( TypeDescLinkNode * )( tdn -> NextNode() ); } - return 0; + tl.mtxP->unlock(); + return rettd; } const TypeDescriptor * From 7233d604a1b92fe48554254576d89d030b05f8d7 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Thu, 24 Jul 2014 22:31:26 +0530 Subject: [PATCH 075/111] Fixed locking in sdaiApplication_instance.cc The STEPattributeList data was being iterated and modiefied by the SDAI_Application_instance class without invoking the mutex of the STEPattribute class. This was fixed in this commit. --- src/clstepcore/sdaiApplication_instance.cc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/clstepcore/sdaiApplication_instance.cc b/src/clstepcore/sdaiApplication_instance.cc index b754d54a4..c8e541062 100644 --- a/src/clstepcore/sdaiApplication_instance.cc +++ b/src/clstepcore/sdaiApplication_instance.cc @@ -294,6 +294,7 @@ Severity SDAI_Application_instance::ValidLevel( ErrorDescriptor * error, InstMgr if( clearError ) { ClearError(); } + attributes.mtxP->lock(); int n = attributes.list_length(); for( int i = 0 ; i < n; i++ ) { if( !( attributes[i].aDesc->AttrType() == AttrType_Redefining ) ) @@ -301,6 +302,7 @@ Severity SDAI_Application_instance::ValidLevel( ErrorDescriptor * error, InstMgr attributes[i].asStr().c_str(), &err, im, 0 ) ); } Severity sev = error->severity(); + attributes.mtxP->unlock(); mtx.unlock(); return sev; } @@ -310,10 +312,12 @@ Severity SDAI_Application_instance::ValidLevel( ErrorDescriptor * error, InstMgr */ void SDAI_Application_instance::ClearAttrError() { mtx.lock(); // For n + attributes.mtxP->lock(); int n = attributes.list_length(); for( int i = 0 ; i < n; i++ ) { attributes[i].Error().ClearErrorMsg(); } + attributes.mtxP->unlock(); mtx.unlock(); } @@ -338,6 +342,7 @@ void SDAI_Application_instance::beginSTEPwrite( ostream & out ) { out.flush(); mtx.lock(); // For n + attributes.mtxP->lock(); int n = attributes.list_length(); for( int i = 0 ; i < n; i++ ) { if( attributes[i].Type() == ENTITY_TYPE @@ -345,6 +350,7 @@ void SDAI_Application_instance::beginSTEPwrite( ostream & out ) { ( *( attributes[i].ptr.c ) ) -> STEPwrite(); } } + attributes.mtxP->unlock(); mtx.unlock(); } @@ -365,6 +371,7 @@ void SDAI_Application_instance::STEPwrite( ostream & out, const char * currSch, out << "#" << STEPfile_id << "=" << StrToUpper( EntityName( currSch ), tmp ) << "("; mtx.lock(); // protects n, loop + attributes.mtxP->lock(); int n = attributes.list_length(); for( int i = 0 ; i < n; i++ ) { @@ -375,6 +382,7 @@ void SDAI_Application_instance::STEPwrite( ostream & out, const char * currSch, ( attributes[i] ).STEPwrite( out, currSch ); } } + attributes.mtxP->unlock(); mtx.unlock(); out << ");\n"; } @@ -404,6 +412,7 @@ void SDAI_Application_instance::WriteValuePairs( ostream & out, } } + attributes.mtxP->lock(); int n = attributes.list_length(); for( int i = 0 ; i < n; i++ ) { @@ -422,6 +431,7 @@ void SDAI_Application_instance::WriteValuePairs( ostream & out, } } out << endl; + attributes.mtxP->unlock(); mtx.unlock(); } @@ -440,6 +450,7 @@ const char * SDAI_Application_instance::STEPwrite( std::string & buf, const char buf.append( instanceInfo ); mtx.lock(); + attributes.mtxP->lock(); int n = attributes.list_length(); for( int i = 0 ; i < n; i++ ) { @@ -452,6 +463,7 @@ const char * SDAI_Application_instance::STEPwrite( std::string & buf, const char } } buf.append( ");" ); + attributes.mtxP->unlock(); mtx.unlock(); return const_cast( buf.c_str() ); } @@ -491,6 +503,7 @@ void SDAI_Application_instance::STEPread_error( char c, int i, istream & in, con _error.PrependToDetailMsg( errStr ); } + attributes.mtxP->lock(); if( ( i >= 0 ) && ( i < attributes.list_length() ) ) { // i is an attribute Error().GreaterSeverity( SEVERITY_WARNING ); sprintf( errStr, " invalid data before type \'%s\'\n", @@ -500,6 +513,7 @@ void SDAI_Application_instance::STEPread_error( char c, int i, istream & in, con Error().GreaterSeverity( SEVERITY_INPUT_ERROR ); _error.AppendToDetailMsg( " No more attributes were expected.\n" ); } + attributes.mtxP->unlock(); std::string tmp; STEPwrite( tmp, schnm ); // STEPwrite writes to a static buffer inside function @@ -551,11 +565,13 @@ Severity SDAI_Application_instance::STEPread( int id, int idIncr, } ReadTokenSeparator( in, &p21Comment ); + attributes.mtxP->lock(); int n = attributes.list_length(); if( n == 0 ) { // no attributes in >> c; // look for the close paren if( c == ')' ) { severe = _error.severity(); + attributes.mtxP->unlock(); mtx.unlock(); return severe; } @@ -633,6 +649,7 @@ Severity SDAI_Application_instance::STEPread( int id, int idIncr, CheckRemainingInput( in, &_error, "ENTITY", ",)" ); severe = _error.severity(); if( !in.good() || severe <= SEVERITY_INPUT_ERROR ) { + attributes.mtxP->unlock(); mtx.unlock(); return severe; } @@ -649,10 +666,12 @@ Severity SDAI_Application_instance::STEPread( int id, int idIncr, i++; } severe = _error.severity(); + attributes.mtxP->unlock(); mtx.unlock(); return severe; } } + attributes.mtxP->unlock(); STEPread_error( c, i, in, currSch ); // code fragment imported from STEPread_error // for some currently unknown reason it was commented out of STEPread_error @@ -950,11 +969,13 @@ Severity EntityValidLevel( const char * attrValue, // string contain entity ref STEPattribute * SDAI_Application_instance::NextAttribute() { STEPattribute * sa = 0; mtx.lock(); + attributes.mtxP->lock(); int i = AttributeCount(); ++_cur; if( i >= _cur ) { sa = &attributes [_cur - 1]; } + attributes.mtxP->unlock(); mtx.unlock(); return sa; } From 2cabefa944ea0b640a9950ceec3b943f920767a2 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Thu, 24 Jul 2014 22:47:23 +0530 Subject: [PATCH 076/111] Minor STEPcomplex optimization Collapsed an if condition into a while condition without changing the semantics --- src/clstepcore/STEPcomplex.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/clstepcore/STEPcomplex.cc b/src/clstepcore/STEPcomplex.cc index 47c5a853f..358273059 100644 --- a/src/clstepcore/STEPcomplex.cc +++ b/src/clstepcore/STEPcomplex.cc @@ -189,11 +189,9 @@ void STEPcomplex::AssignDerives() { attrNm = nm; } scomp2 = head; - while( scomp2 && !a ) { - if( scomp1 != scomp2 ) { - scomp2->MakeDerived( attrNm ); - a = scomp2->GetSTEPattribute( attrNm ); - } + while( scomp2 && !a && ( scomp1 != scomp2 ) ) { + scomp2->MakeDerived( attrNm ); + a = scomp2->GetSTEPattribute( attrNm ); scomp2 = scomp2->sc; } } From 3fdbe460f14abd181e60c306443924cde1680c10 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Thu, 24 Jul 2014 23:06:21 +0530 Subject: [PATCH 077/111] Made STEPcomplex thread safe The assumption used was that STEPcomplex class wont in future provide an API through which threads can remove / insert a STEPcomplex node. Three already declared mutexes were used in for this purpose: (1) A recursive mutex for each STEPcomplex node (borrowed from the superclass SDAI_Application_instance) (2) A recursive mutex belonging to AttrDescriptorList class (originally defined in SingleLinkList class) (3) A recursive shared mutex belonging to EntNode class. The fixed order between the locks was: (2) > (1). (3) was independent. --- src/clstepcore/STEPcomplex.cc | 61 ++++++++++++++++++++++++++++------- src/clstepcore/STEPcomplex.h | 8 +++++ 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/clstepcore/STEPcomplex.cc b/src/clstepcore/STEPcomplex.cc index 358273059..ceef34585 100644 --- a/src/clstepcore/STEPcomplex.cc +++ b/src/clstepcore/STEPcomplex.cc @@ -64,6 +64,7 @@ void STEPcomplex::Initialize( const char ** names, const char * schnm ) { bool invalid = false, outOfOrder = false; // Splice out the invalid names from our list: + ents->sharedMtxP->lock(); while( eptr ) { enext = eptr->next; enDesc = _registry->FindEntity( *eptr, schnm ); @@ -95,10 +96,13 @@ void STEPcomplex::Initialize( const char ** names, const char * schnm ) { } eptr->next = NULL; // must set eptr->next to NULL or next line would del entire list + eptr->sharedMtxP = NULL; + // must set eptr->sharedMtxP to NULL or the sharedMtxP for the EntNode link-list will get deleted delete eptr; } eptr = enext; } + ents->sharedMtxP->unlock(); // If we changed the name of any of the entities, resort: if( outOfOrder ) { @@ -129,20 +133,25 @@ void STEPcomplex::Initialize( const char ** names, const char * schnm ) { "Entity combination does not represent a legal complex entity" ); cerr << "ERROR: Could not create instance of the following complex" << " entity:" << endl; + + ents->sharedMtxP->lock(); eptr = ents; while( eptr ) { cerr << *eptr << endl; eptr = eptr->next; } cerr << endl; + ents->sharedMtxP->unlock(); return; } // Finally, build what we can: + ents->sharedMtxP->lock(); BuildAttrs( *ents ); for( eptr = ents->next; eptr; eptr = eptr->next ) { AddEntityPart( *eptr ); } + ents->sharedMtxP->unlock(); AssignDerives(); delete ents; } @@ -170,9 +179,13 @@ void STEPcomplex::AssignDerives() { AttrDescLinkNode * attrPtr; const AttrDescriptor * ad; + // Even though the following is an interation on sc, we dont + // use the STEPcomplex mutex since we are assuming that no node + // can be removed or inserted between two while( scomp1 && scomp1->eDesc ) { a = 0; attrList = &( scomp1->eDesc->ExplicitAttr() ); + attrList->mtxP->lock(); attrPtr = ( AttrDescLinkNode * )attrList->GetHead(); // assign nm to be derived attr @@ -188,7 +201,9 @@ void STEPcomplex::AssignDerives() { } else { attrNm = nm; } - scomp2 = head; + scomp2 = head; //locked earlier + // If we had used the generic hand-over-hand fine grain + // locking, the following loop could have caused a deadlock. while( scomp2 && !a && ( scomp1 != scomp2 ) ) { scomp2->MakeDerived( attrNm ); a = scomp2->GetSTEPattribute( attrNm ); @@ -198,6 +213,7 @@ void STEPcomplex::AssignDerives() { // increment attr attrPtr = ( AttrDescLinkNode * )attrPtr->NextNode(); } + attrList->mtxP->unlock(); scomp1 = scomp1->sc; } } @@ -213,7 +229,7 @@ void STEPcomplex::AddEntityPart( const char * name ) { scomplex = new STEPcomplex( _registry, STEPfile_id ); scomplex->BuildAttrs( name ); if( scomplex->eDesc ) { - scomplex->head = this; + scomplex->head = this; // no locking here as the only the current thread will have the copy AppendEntity( scomplex ); } else { cout << scomplex->_error.DetailMsg() << endl; @@ -224,14 +240,16 @@ void STEPcomplex::AddEntityPart( const char * name ) { STEPcomplex * STEPcomplex::EntityPart( const char * name, const char * currSch ) { STEPcomplex * scomp = head; + // No locking in this loop as remove insert operaations are not allowed while( scomp ) { if( scomp->eDesc ) { if( scomp->eDesc->CurrName( name, currSch ) ) { return scomp; } - } else + } else { cout << "Bug in STEPcomplex::EntityPart(): entity part has " << "no EntityDescriptor\n"; + } scomp = scomp->sc; } return 0; @@ -266,11 +284,19 @@ Severity STEPcomplex::ValidLevel( ErrorDescriptor * error, InstMgr * im, } void STEPcomplex::AppendEntity( STEPcomplex * stepc ) { - if( sc ) { - sc->AppendEntity( stepc ); - } else { - sc = stepc; + // We use the assumption that no remove / insert operation is there. + // Hence is locking is required only at the last node. + if( !sc ) { + // We use the double checking. This safaly eliminates the locking of internal nodes + mtx.lock(); + if( !sc ) { + sc = stepc; + mtx.unlock(); + return; + } // else another node has just appended a new node + mtx.unlock(); } + sc->AppendEntity( stepc ); } // READ @@ -446,13 +472,13 @@ void STEPcomplex::BuildAttrs( const char * s ) { ////////////////////////////////////////////// STEPattribute * a = 0; - + attrList->mtxP->lock(); AttrDescLinkNode * attrPtr = ( AttrDescLinkNode * )attrList->GetHead(); while( attrPtr != 0 ) { const AttrDescriptor * ad = attrPtr->AttrDesc(); if( ( ad->Derived() ) != LTrue ) { - + mtx.lock(); // To protect _attr_data_list and attributes switch( ad->NonRefType() ) { case INTEGER_TYPE: integer_data = new SDAI_Integer; @@ -533,10 +559,14 @@ void STEPcomplex::BuildAttrs( const char * s ) { } a -> set_null(); + attributes.mtxP->lock(); attributes.push( a ); + attributes.mtxP->unlock(); + mtx.unlock(); } attrPtr = ( AttrDescLinkNode * )attrPtr->NextNode(); } + attrList->mtxP->unlock(); } else { _error.AppendToDetailMsg( "Entity does not exist.\n" ); _error.GreaterSeverity( SEVERITY_INPUT_ERROR ); @@ -590,14 +620,19 @@ void STEPcomplex::WriteExtMapEntities( ostream & out, const char * currSch ) { std::string tmp; out << StrToUpper( EntityName( currSch ), tmp ); out << "("; - int n = attributes.list_length(); + mtx.lock(); // Protects attributes + attributes.mtxP->lock(); + int n = attributes.list_length(); for( int i = 0 ; i < n; i++ ) { ( attributes[i] ).STEPwrite( out, currSch ); if( i < n - 1 ) { out << ","; } } + attributes.mtxP->unlock(); + mtx.unlock(); + out << ")\n"; if( sc ) { sc->WriteExtMapEntities( out, currSch ); @@ -612,14 +647,18 @@ const char * STEPcomplex::WriteExtMapEntities( std::string & buf, const char * c buf.append( tmp ); buf.append( "i" ); + mtx.lock(); + attributes.mtxP->lock(); int n = attributes.list_length(); - for( int i = 0 ; i < n; i++ ) { buf.append( attributes[i].asStr( currSch ) ); if( i < n - 1 ) { buf.append( "," ); } } + attributes.mtxP->unlock(); + mtx.unlock(); + buf.append( ")\n" ); if( sc ) { diff --git a/src/clstepcore/STEPcomplex.h b/src/clstepcore/STEPcomplex.h index 8aff6044d..f073a155f 100644 --- a/src/clstepcore/STEPcomplex.h +++ b/src/clstepcore/STEPcomplex.h @@ -14,12 +14,20 @@ typedef std::list STEPcomplex_attr_data_list; typedef std::list::iterator STEPcomplex_attr_data; class SC_CORE_EXPORT STEPcomplex : public SDAI_Application_instance { + // NOTE: The locking methodology used here assumes that a node (i.e a + // STEPcomplex object) can neither be removed, nor can be inserted + // between two existing nodes. If such APIs are introduced in + // future the STEPcomplex class will no longer be thread safe and can + // crash / deadlock under multithreaded environment. + public: //TODO should this _really_ be public?! STEPcomplex * sc; STEPcomplex * head; Registry * _registry; int visited; ///< used when reading (or as you wish?) STEPcomplex_attr_data_list _attr_data_list; + //mtx will be borrowed from superclass < Each mutex will protect a STEPcomplex object. + public: STEPcomplex( Registry * registry, int fileid ); STEPcomplex( Registry * registry, const std::string ** names, int fileid, From 0a45ce2aa511d800daff292131d0e8f9f35c5027 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sat, 2 Aug 2014 22:32:00 +0530 Subject: [PATCH 078/111] Thread safety in EntList. Under the assumptions that an EntList object cannot be inserted in between two EntList objects and cannot be removed from a list of EntList objects, making this class thread safe became trivially easy. One mutex per EntList object was introduced to support appending of EntList objects. As this feature would be used by its subclass (MultList) --- src/clstepcore/complexSupport.h | 10 ++++++++++ src/clstepcore/entlist.cc | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/src/clstepcore/complexSupport.h b/src/clstepcore/complexSupport.h index cf066c837..d6b96293c 100644 --- a/src/clstepcore/complexSupport.h +++ b/src/clstepcore/complexSupport.h @@ -142,6 +142,12 @@ class SC_CORE_EXPORT EntNode { }; class SC_CORE_EXPORT EntList { + // NOTE: The locking methodology used here assumes that a node (i.e a + // EntList object) can neither be removed, nor can be inserted + // between two existing nodes. If such APIs are introduced in + // future the EntList class (or its subclasses) will no longer be + // thread safe and can crash / deadlock under multithreaded environment. + friend class MultList; friend class JoinList; friend class OrList; @@ -197,6 +203,10 @@ class SC_CORE_EXPORT EntList { return ( join != SIMPLE ); } EntList * next, *prev; + sc_mutex mtx; + /** \var mtx + * Currently only being used by the subclass MultList + */ protected: MatchType viable; diff --git a/src/clstepcore/entlist.cc b/src/clstepcore/entlist.cc index 0dd35803a..3d56fd204 100644 --- a/src/clstepcore/entlist.cc +++ b/src/clstepcore/entlist.cc @@ -24,6 +24,7 @@ int EntList::siblings() { int count; EntList * el; + //No locking here as nodes (i.e. EntList) can be only appended for( count = 1, el = next; el; count++, el = el->next ) { ; } @@ -36,6 +37,7 @@ int EntList::siblings() { EntList * EntList::firstNot( JoinType j ) { EntList * sibling = this; + //No locking here as nodes (i.e. EntList) can be only appended while( sibling != NULL && sibling->join == j ) { sibling = sibling->next; } @@ -48,6 +50,7 @@ EntList * EntList::firstNot( JoinType j ) { EntList * EntList::firstWanted( MatchType match ) { EntList * sibling = this; + //No locking here as nodes (i.e. EntList) can be only appended while( sibling != NULL && sibling->viable != match ) { sibling = sibling->next; } @@ -61,6 +64,7 @@ EntList * EntList::firstWanted( MatchType match ) { EntList * EntList::lastNot( JoinType j ) { EntList * sibling = this; + //No locking here as nodes (i.e. EntList) can be only appended while( sibling != NULL && sibling->join == j ) { sibling = sibling->prev; } @@ -74,6 +78,7 @@ EntList * EntList::lastNot( JoinType j ) { EntList * EntList::lastWanted( MatchType match ) { EntList * sibling = this; + //No locking here as nodes (i.e. EntList) can be only appended while( sibling != NULL && sibling->viable != match ) { sibling = sibling->prev; } From 07448b77d6123215df7141012767cc36ebe12d69 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sat, 2 Aug 2014 23:01:21 +0530 Subject: [PATCH 079/111] Thread Safety in SimpleList Used sharedMtxP defined in EntNode class to protect EntNode list structure which was being accessed in functions of SimpleList class --- src/clstepcore/complexSupport.h | 2 ++ src/clstepcore/entlist.cc | 14 ++++++++++---- src/clstepcore/non-ors.cc | 19 +++++++++++-------- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/clstepcore/complexSupport.h b/src/clstepcore/complexSupport.h index d6b96293c..410718269 100644 --- a/src/clstepcore/complexSupport.h +++ b/src/clstepcore/complexSupport.h @@ -221,6 +221,8 @@ class SC_CORE_EXPORT EntList { }; class SC_CORE_EXPORT SimpleList : public EntList { + // Note: Refer to Note in EntList class + friend class ComplexList; friend ostream & operator<< ( ostream &, SimpleList & ); diff --git a/src/clstepcore/entlist.cc b/src/clstepcore/entlist.cc index 3d56fd204..5a35d1b76 100644 --- a/src/clstepcore/entlist.cc +++ b/src/clstepcore/entlist.cc @@ -98,6 +98,7 @@ void SimpleList::unmarkAll( EntNode * ents ) { return; } + ents->sharedMtxP->lock(); // Locking for EntNode data structure while( eptr != NULL && ( comp = strcmp( eptr->name, name ) ) < 0 ) { eptr = eptr->next; } @@ -106,6 +107,7 @@ void SimpleList::unmarkAll( EntNode * ents ) { // Only unmark if we gave it the strongest mark: eptr->setmark( NOMARK ); } + ents->sharedMtxP->unlock(); // Either way (whether or not another List's mark remains), we no longer // marked: I_marked = NOMARK; @@ -120,7 +122,9 @@ void SimpleList::unmarkAll( EntNode * ents ) { bool SimpleList::acceptChoice( EntNode * ents ) { EntNode * eptr = ents; int comp; + bool result = false; + ents->sharedMtxP->lock(); // Locking for EntNode data structure while( eptr != NULL ) { if( ( comp = strcmp( name, eptr->name ) ) == 0 ) { if( ! eptr->marked() ) { @@ -128,15 +132,17 @@ bool SimpleList::acceptChoice( EntNode * ents ) { I_marked = ORMARK; // Remember that we're the one who marked this. (Nec. in case // we have to unmark later to try out another OR branch.) - return true; + result = true; } - return false; // we didn't mark + // else we didn't mark + break; } if( comp < 0 ) { // We're beyond name in the ents list. No more checking to do. - return false; + break; } eptr = eptr->next; } - return false; + ents->sharedMtxP->unlock(); + return result; } diff --git a/src/clstepcore/non-ors.cc b/src/clstepcore/non-ors.cc index 14607f606..f46717c7e 100644 --- a/src/clstepcore/non-ors.cc +++ b/src/clstepcore/non-ors.cc @@ -22,7 +22,9 @@ MatchType SimpleList::matchNonORs( EntNode * ents ) { EntNode * eptr = ents; int comp; + MatchType result = UNSATISFIED; + ents->sharedMtxP->lock(); // Locking for EntNode data structure while( eptr != NULL ) { if( ( comp = strcmp( name, eptr->name ) ) == 0 ) { if( ! eptr->marked( MARK ) ) { @@ -42,15 +44,15 @@ MatchType SimpleList::matchNonORs( EntNode * ents ) { // branch.) if( ents->allMarked() ) { // If this was the only unmarked left, - viable = MATCHALL; - return MATCHALL; + result = MATCHALL; + break; } } - viable = MATCHSOME; - return MATCHSOME; + result = MATCHSOME; + break; } - viable = SATISFIED; - return SATISFIED; + result = SATISFIED; + break; // Couldn't mark any more, but at least we're not placing a re- // quirement ents couldn't meet. } @@ -63,8 +65,9 @@ MatchType SimpleList::matchNonORs( EntNode * ents ) { // At this point, we went through the list without finding a match. Result // = UNSATISFIED - no match. - viable = UNSATISFIED; - return UNSATISFIED; + viable = result; + ents->sharedMtxP->unlock(); + return result; } /** From 79c990166282a34f2419a7aafad8818813ba049a Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sat, 2 Aug 2014 23:23:54 +0530 Subject: [PATCH 080/111] Thread safety in MultList The mutex defined in the superclass EntList was used in the function appendList. --- src/clstepcore/multlist.cc | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/clstepcore/multlist.cc b/src/clstepcore/multlist.cc index aa0f5e42c..4bf6ed2f5 100644 --- a/src/clstepcore/multlist.cc +++ b/src/clstepcore/multlist.cc @@ -37,6 +37,7 @@ void MultList::setLevel( int l ) { EntList * child = childList; level = l; + //No locking here as nodes (i.e. EntList) can be only appended for( ; child != NULL; child = child->next ) { child->setLevel( l + 1 ); } @@ -48,6 +49,7 @@ void MultList::setLevel( int l ) { bool MultList::contains( char * nm ) { EntList * child = childList; + //No locking here as nodes (i.e. EntList) can be only appended while( child ) { if( child->contains( nm ) ) { return true; @@ -62,6 +64,8 @@ bool MultList::contains( char * nm ) { */ bool MultList::hit( char * nm ) { EntList * child = childList; + + //No locking here as nodes (i.e. EntList) can be only appended while( child ) { if( child->viable > UNSATISFIED && child->hit( nm ) ) { // For most child->join types ruling out UNSATs just saves us @@ -87,6 +91,7 @@ EntList * MultList::getChild( int num ) { // Check for error situations (shouldn't normally occur): return NULL; } + //No locking here as nodes (i.e. EntList) can be only appended for( j = 0; j < num; j++, child = child->next ) { ; } @@ -100,14 +105,28 @@ EntList * MultList::getChild( int num ) { void MultList::appendList( EntList * ent ) { EntList * eprev; + mtx.lock(); // Protects numchildren, childList if( numchildren == 0 ) { childList = ent; } else { eprev = getLast(); + eprev->mtx.lock(); + // In a multithreaded environment It is possible that before locking + // more elements got added into the existing list and eprev is no + // longer the last element. This while loop takes care of that. + while( eprev->next ) { + eprev->mtx.unlock(); + eprev = eprev->next; + eprev->mtx.lock(); + } + // eprev lock is acquired eprev->next = ent; - ent->prev = eprev; + eprev->mtx.unlock(); + + ent->prev = eprev; // ent locking not required } numchildren += ent->siblings(); + mtx.unlock(); } /** @@ -131,7 +150,10 @@ EntList * MultList::copyList( EntList * ent ) { newlist = new AndOrList; break; }; + ent->mtx.lock(); // appendList doesn't lock the EntNode appendList( newlist ); + ent->mtx.unlock(); + if( ent->multiple() ) { // For the multlists, we must recurse for all their children: child = ( dynamic_cast< MultList * >(ent) )->childList; From 3c848a5d2b8d9725926ff7bfe13b19bf274a7922 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sat, 2 Aug 2014 23:36:36 +0530 Subject: [PATCH 081/111] Thread safety in Join-, And-, AndOr- List sharedMtxP of EntNode class was invoked to keep the list of EntNode consistent whenever the EntNode list was being used multiple times in a function --- src/clstepcore/match-ors.cc | 5 +++++ src/clstepcore/multlist.cc | 2 ++ src/clstepcore/non-ors.cc | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/src/clstepcore/match-ors.cc b/src/clstepcore/match-ors.cc index 5f17f7d93..f53b0d22a 100644 --- a/src/clstepcore/match-ors.cc +++ b/src/clstepcore/match-ors.cc @@ -28,6 +28,7 @@ MatchType AndOrList::matchORs( EntNode * ents ) { EntList * child = childList->firstWanted( UNKNOWN ); + ents->sharedMtxP->lock(); // To make the ents consistent in this function while( child != NULL ) { if( ( dynamic_cast< MultList * >(child))->matchORs( ents ) == UNSATISFIED ) { // Unmark whatever we may have marked. (E.g., there may have @@ -43,6 +44,7 @@ MatchType AndOrList::matchORs( EntNode * ents ) { // of those children may become UNSAT later and we'll have to unmark all // its descendants. If so, some of the marks we have now may disappear. setViableVal( ents ); + ents->sharedMtxP->unlock(); return viable; } @@ -55,9 +57,11 @@ MatchType AndOrList::matchORs( EntNode * ents ) { MatchType AndList::matchORs( EntNode * ents ) { EntList * child = childList->firstWanted( UNKNOWN ); + ents->sharedMtxP->lock(); // To make the ents consistent in this function while( child != NULL ) { if( ( dynamic_cast< MultList * >(child) )->matchORs( ents ) == UNSATISFIED ) { viable = UNSATISFIED; + ents->sharedMtxP->unlock(); return UNSATISFIED; // This means the whole AndList has failed, by definition. } @@ -69,6 +73,7 @@ MatchType AndList::matchORs( EntNode * ents ) { // we'll catch it in setViableVal() called below. } setViableVal( ents ); + ents->sharedMtxP->unlock(); return viable; } diff --git a/src/clstepcore/multlist.cc b/src/clstepcore/multlist.cc index 4bf6ed2f5..37d7a0f5a 100644 --- a/src/clstepcore/multlist.cc +++ b/src/clstepcore/multlist.cc @@ -218,6 +218,8 @@ void JoinList::setViableVal( EntNode * ents ) { } child = child->next; } + + // dont need to lock ent as it is being used only one time if( viable == MATCHALL && !ents->allMarked() ) { // There are some situations where this may happen - a child claims // MATCHALL while that is not the case. If child #2 was checked and diff --git a/src/clstepcore/non-ors.cc b/src/clstepcore/non-ors.cc index f46717c7e..a1bc82b4c 100644 --- a/src/clstepcore/non-ors.cc +++ b/src/clstepcore/non-ors.cc @@ -81,10 +81,12 @@ MatchType AndOrList::matchNonORs( EntNode * ents ) { EntList * child = childList->firstNot( OR ); MatchType retval; + ents->sharedMtxP->lock(); // To make the ents consistent in this function while( child != NULL ) { if( ( retval = child->matchNonORs( ents ) ) == MATCHALL ) { if( prevKnown( child ) ) { viable = MATCHALL; + ents->sharedMtxP->unlock(); return MATCHALL; // We found a good solution. Nothing else to do. (Some higher // AND may have some other req's ents can't meet, but that's @@ -119,6 +121,7 @@ MatchType AndOrList::matchNonORs( EntNode * ents ) { child = child->nextNot( OR ); } setViableVal( ents ); + ents->sharedMtxP->unlock(); return viable; } @@ -129,9 +132,11 @@ MatchType AndOrList::matchNonORs( EntNode * ents ) { MatchType AndList::matchNonORs( EntNode * ents ) { EntList * child = childList->firstNot( OR ); + ents->sharedMtxP->lock(); // To make the ents consistent in this function while( child != NULL ) { if( child->matchNonORs( ents ) == UNSATISFIED ) { viable = UNSATISFIED; + ents->sharedMtxP->unlock(); return UNSATISFIED; // This means the whole AndList has failed, by definition. } @@ -143,5 +148,6 @@ MatchType AndList::matchNonORs( EntNode * ents ) { // we'll catch it in setViableVal() called below. } setViableVal( ents ); + ents->sharedMtxP->unlock(); return viable; } From 1095f7346dfbb2cc107fa115a4e72168b45d9a80 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 3 Aug 2014 00:10:18 +0530 Subject: [PATCH 082/111] Thread safety in OrList Similar to AndList. However the mutex belonging to the superclass EntList was used to protect various counters (choiceCount, choice) used by OrList --- src/clstepcore/complexSupport.h | 4 ++++ src/clstepcore/match-ors.cc | 6 ++++++ src/clstepcore/orlist.cc | 3 +++ src/clstepcore/trynext.cc | 23 ++++++++++++++++++----- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/clstepcore/complexSupport.h b/src/clstepcore/complexSupport.h index 410718269..9faddfa98 100644 --- a/src/clstepcore/complexSupport.h +++ b/src/clstepcore/complexSupport.h @@ -346,13 +346,17 @@ class SC_CORE_EXPORT OrList : public MultList { void unmarkAll( EntNode * ); bool acceptChoice( EntNode * ); bool acceptNextChoice( EntNode * ents ) { + mtx.lock(); choice++; + mtx.unlock(); return ( acceptChoice( ents ) ); } void reset() { + mtx.lock(); choice = -1; choice1 = -2; choiceCount = 0; + mtx.unlock(); MultList::reset(); } diff --git a/src/clstepcore/match-ors.cc b/src/clstepcore/match-ors.cc index f53b0d22a..ea914a96c 100644 --- a/src/clstepcore/match-ors.cc +++ b/src/clstepcore/match-ors.cc @@ -90,6 +90,7 @@ MatchType OrList::matchORs( EntNode * ents ) { EntList * child = childList; MatchType retval = UNKNOWN; + ents->sharedMtxP->lock(); // To make the ents consistent in this function for( count = 0; count < numchildren; count++, child = child->next ) { // First call (recursively) matchNonORs() to check off all nodes that @@ -120,7 +121,10 @@ MatchType OrList::matchORs( EntNode * ents ) { if( choice == -1 ) { choice1 = choice = count; } + mtx.lock();// protects choiceCount choiceCount++; + mtx.unlock(); + if( viable < retval ) { viable = retval; } @@ -154,6 +158,8 @@ MatchType OrList::matchORs( EntNode * ents ) { // *actually* marks under the current circumstances. acceptChoice( ents ); } + ents->sharedMtxP->unlock(); + if( viable == MATCHALL ) { return getChild( choice1 )->viable; // viable == MATCHALL because we found a MATCHALL sol'n along the way, diff --git a/src/clstepcore/orlist.cc b/src/clstepcore/orlist.cc index b820bea53..58309e2a5 100644 --- a/src/clstepcore/orlist.cc +++ b/src/clstepcore/orlist.cc @@ -65,6 +65,7 @@ void OrList::unmarkAll( EntNode * ents ) { bool OrList::acceptChoice( EntNode * ents ) { EntList * child; + mtx.lock(); // to proctect choice if( choice == LISTEND ) { choice = choice1; } @@ -72,6 +73,7 @@ bool OrList::acceptChoice( EntNode * ents ) { while( child ) { if( child->viable >= MATCHSOME && child->acceptChoice( ents ) ) { // acceptChoice() returns true if we marked something. + mtx.unlock(); return true; } child = child->next; @@ -80,5 +82,6 @@ bool OrList::acceptChoice( EntNode * ents ) { // If we got here, we must have gotten to the end of the childList without // finding a choice which marks something. choice = LISTEND; + mtx.unlock(); return false; } diff --git a/src/clstepcore/trynext.cc b/src/clstepcore/trynext.cc index 145af7699..e091901d5 100644 --- a/src/clstepcore/trynext.cc +++ b/src/clstepcore/trynext.cc @@ -101,22 +101,27 @@ static EntList * nextCandidate( EntList * child ) { */ MatchType OrList::tryNext( EntNode * ents ) { EntList * child; + MatchType retval; - + mtx.lock(); // For choice if( choice == LISTEND ) { // if we've already exhausted all the choices in this OR, + mtx.unlock(); return NOMORE; } // First try other choices of descendants of current choice: child = getChild( choice ); + + ents->sharedMtxP->lock(); // For EntNode Consistency if( child->multiple() ) { // I.e., if there are (or may be) more choices within the current // choice, try those first. We must be sure to exhaust all choices in // our descendants before moving on. - MatchType retval; retval = ( ( MultList * )child )->tryNext( ents ); if( retval == MATCHALL ) { + mtx.unlock(); + ents->sharedMtxP->unlock(); return MATCHALL; } if( retval == NEWCHOICE ) { @@ -124,6 +129,8 @@ MatchType OrList::tryNext( EntNode * ents ) { // EntLists on the higher levels (if there are) can retry all the // later choices with the new choice we just found. Otherwise, // we'll continue below looking into our next choice. + mtx.unlock(); + ents->sharedMtxP->unlock(); return NEWCHOICE; } } @@ -136,15 +143,19 @@ MatchType OrList::tryNext( EntNode * ents ) { // (Also, it's nec. to unmark now, as we did above before returning and // before the calling tryNext() tries earlier OR's - see notes, 11/12.) choice = LISTEND; + mtx.unlock(); + ents->sharedMtxP->unlock(); return NOMORE; } + mtx.unlock(); // Otherwise, try our next: if( acceptNextChoice( ents ) ) { if( ents->allMarked() ) { - return MATCHALL; + retval = MATCHALL; + } else { + retval = NEWCHOICE; } - return NEWCHOICE; } else { // Must have been no next choice (or none which mark anything new). // acceptNextChoice() has set choice to LISTEND. We leave this OR @@ -153,6 +164,8 @@ MatchType OrList::tryNext( EntNode * ents ) { // their first choices, so that we'll be able to test every possibility // with the new choice. At that time, this OrList will be reset to its // first choice too. - return NOMORE; + retval = NOMORE; } + ents->sharedMtxP->unlock(); + return retval; } From 27f781477c9e9e9f21bd22f08bbb03d8397fd5f4 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 3 Aug 2014 00:19:22 +0530 Subject: [PATCH 083/111] Thread safety in ComplexList Like the classes before, used sharedMtxP to protect the EntNode list whenver it was being iterated upon. Also added a public mutex to protect the public next pointer. Resposibilty of using it will fall to the class which is using next pointer (ComplexCollect) --- src/clstepcore/complexSupport.h | 2 ++ src/clstepcore/complexlist.cc | 31 +++++++++++++++++++++++-------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/clstepcore/complexSupport.h b/src/clstepcore/complexSupport.h index 9faddfa98..2e925ff48 100644 --- a/src/clstepcore/complexSupport.h +++ b/src/clstepcore/complexSupport.h @@ -408,6 +408,8 @@ class SC_CORE_EXPORT ComplexList { */ AndList * head; ComplexList * next; + sc_mutex mtx; ///< For hand over hand locking + int Dependent() { return dependent; } diff --git a/src/clstepcore/complexlist.cc b/src/clstepcore/complexlist.cc index 52eb0a372..7b8b3c4f5 100644 --- a/src/clstepcore/complexlist.cc +++ b/src/clstepcore/complexlist.cc @@ -77,6 +77,8 @@ void ComplexList::buildList() { // Add first node based on supertype: list = new EntNode( ( dynamic_cast< SimpleList * >(head->childList ))->name ); + list->sharedMtxP = new sc_recursive_mutex(); + // Recursively add all descendents: while( sibling ) { addChildren( sibling ); @@ -95,6 +97,8 @@ void ComplexList::buildList() { void ComplexList::addChildren( EntList * ent ) { EntList * child; char * nm; + + list->sharedMtxP->lock(); EntNode * prev = list, *prev2 = NULL, *newnode; int comp = 0; @@ -116,6 +120,7 @@ void ComplexList::addChildren( EntList * ent ) { // prev. prev or prev2 may = NULL if newnode belongs at the end // of the list or before the beginning, respectively. newnode = new EntNode( nm ); + newnode->sharedMtxP = list->sharedMtxP; newnode->next = prev; if( prev2 == NULL ) { // This will be the case if the inner while was never entered. @@ -127,6 +132,7 @@ void ComplexList::addChildren( EntList * ent ) { } } } + list->sharedMtxP->unlock(); } /** @@ -134,10 +140,14 @@ void ComplexList::addChildren( EntList * ent ) { * EntNode list. If not, there's no way this will match ents. If so, * we'll have to run matches() (below) to check more closely. This func- * tion is simplified greatly because both EntNodes are ordered alphabeti- - * cally. + * cally. Two contains can cause a deadlock if ours of one is is theirs of + * another. */ bool ComplexList::contains( EntNode * ents ) { + ents->sharedMtxP->lock(); // First external + list->sharedMtxP->lock(); // then mine EntNode * ours = list, *theirs = ents; + bool result = true; while( theirs != NULL ) { while( ours != NULL && *ours < *theirs ) { @@ -146,14 +156,15 @@ bool ComplexList::contains( EntNode * ents ) { if( ours == NULL || *ours > *theirs ) { // If either of these occured, we couldn't find one of ours which // matched the current "theirs". - return false; + result = false; + break; } theirs = theirs->next; ours = ours->next; } - // At this point we must have matched them all. (We may have extra, but - // there's nothing wrong with that.) - return true; + ents->sharedMtxP->unlock(); + list->sharedMtxP->unlock(); + return result; } /** @@ -233,6 +244,8 @@ bool ComplexList::hitMultNodes( EntNode * ents ) { return true; } + bool result = true; + ents->sharedMtxP->lock(); for( node = ents; node != NULL; node = node->next ) { if( node->multSuprs() ) { child = head->childList->next; @@ -246,7 +259,8 @@ bool ComplexList::hitMultNodes( EntNode * ents ) { // below. if( child->contains( node->name ) ) { if( ! child->hit( node->name ) ) { - return false; + result = false; + break; } } child = child->next; @@ -258,6 +272,7 @@ bool ComplexList::hitMultNodes( EntNode * ents ) { } } } - return true; - // If we got here, we didn't find any unmatched complex subtypes. + ents->sharedMtxP->unlock(); + return result; + // Will return true if we didn't find any unmatched complex subtypes. } From dc5a00f0ea45fc57cee3dbe6b93545a9554b1fda Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 3 Aug 2014 00:51:47 +0530 Subject: [PATCH 084/111] Thread Safety in ComplexCollect A mutex was introduced to proctect the counter and the pointer to clists. The insert and remove functions were tricky to make thread safe as clists may or may-not have been initialized. Hand-over-hand locking was used. --- src/clstepcore/collect.cc | 192 +++++++++++++++++++++++++------- src/clstepcore/complexSupport.h | 5 + 2 files changed, 157 insertions(+), 40 deletions(-) diff --git a/src/clstepcore/collect.cc b/src/clstepcore/collect.cc index 08f2131bb..39faa3688 100644 --- a/src/clstepcore/collect.cc +++ b/src/clstepcore/collect.cc @@ -19,23 +19,62 @@ * supertype name. Increments count. */ void ComplexCollect::insert( ComplexList * c ) { + mtx.lock(); ComplexList * prev = NULL, *cl = clists; - while( cl && *cl < *c ) { - prev = cl; - cl = cl->next; - } - if( prev == NULL ) { - // I.e., c belongs before the first cl so the above loop was never - // entered. (This may also be the case if there's nothing in the - // collect yet and cl also = NULL.) + if( !cl ) { + // checking if cl is NULL. + c->mtx.lock(); + c->next = NULL; clists = c; - c->next = cl; + c->mtx.unlock(); } else { - prev->next = c; + // hand over hand locking. + // Our aim will be to lock the element before the insert slot + cl->mtx.lock(); + while( *cl < *c ) { + if( prev ) { + // Except for the first iteration will execute everytime + prev->mtx.unlock(); + } + + prev = cl; + cl = cl->next; + if( !cl ) { + // If cl has become null exit. This means we have reached + // the end of the list. Only the last element has been locked + break; + } + cl->mtx.lock(); + } + + // At this point EITHER we have locked the first element (cl locked, + // prev = NULL) OR we have locked the last element i.e (prev locked, + // cl == NULL) or we have locked both cl & prev. The element will be + // inserted between prev & cl + + if( prev == NULL ) { + // I.e., c belongs before the first cl so the above loop was never + // entered. + clists = c; + } else { + prev->next = c; + } + + c->mtx.lock(); c->next = cl; + c->mtx.unlock(); + + if( prev ) { + prev->mtx.unlock(); + } + + if( cl ) { + cl->mtx.unlock(); + } } count++; + mtx.unlock(); } /** @@ -47,40 +86,93 @@ void ComplexCollect::insert( ComplexList * c ) { * remove it from the Collect. */ void ComplexCollect::remove( ComplexList * c ) { + mtx.lock(); ComplexList * cl = clists, *prev = NULL; - while( cl && *cl < *c ) { - prev = cl; - cl = cl->next; + if( cl ) { + cl->mtx.lock(); + // Our strategy will be to lock the element which is to be deleted + // and the element before that + while( *cl < *c ) { + // Below if is required to deal with the first iteration. + if( prev ) { + prev->mtx.unlock(); + } + prev = cl; + cl = cl->next; + + if( !cl ) { + // We arrived at the end of the list + prev->mtx.unlock(); + break; + } + cl->mtx.lock(); + } } + + // At this stage we have no ComplexList locks if we have transversed + // theentire clists without finding c (including the case when clists + // is NULL). In case the first ComplexList matches (i.e. prev = NULL) + // the only lock acquired will be cl. In rest of the cases (where a + // ComplexList bigger or equal to is encountered in an iteration the + // locks held would be cl and prev. + if( cl == NULL || cl != c ) { // Just in case c isn't in the list. + if( cl != c ) { + // Below if condition avoids the special case in which the + // first ComplexList element is bigger then c + if( prev ) { + prev->mtx.unlock(); + } + + cl->mtx.unlock(); + } + mtx.unlock(); return; } + if( prev == NULL ) { // c is the first thing in clists (so prev while loop never entered) clists = c->next; } else { prev->next = cl->next; + prev->mtx.unlock(); } + cl->next = NULL; + cl->mtx.unlock();// cannot do it after cl->remove as it invokes the destructor cl->remove(); count--; + mtx.unlock(); } /** * Searches for and returns the ComplexList whose supertype name = name. */ ComplexList * ComplexCollect::find( char * name ) { - ComplexList * cl = clists; + ComplexList * cl = clists, *prev = NULL, *retval = NULL; - while( cl && *cl < name ) { - cl = cl->next; - } - if( cl && *cl == name ) { - return cl; + if( cl ) { + cl->mtx.lock(); + while( *cl < name ) { + prev = cl; + cl = cl->next; + if( !cl ) { + // We have reached the end without success + prev->mtx.unlock(); + return NULL; + } + + cl->mtx.lock(); + prev->mtx.unlock(); + } + + // At this point we only hold the lock for cl + retval = ( *cl == name ) ? cl : NULL; + cl->mtx.unlock(); } - return NULL; + return retval; } /** @@ -92,10 +184,11 @@ ComplexList * ComplexCollect::find( char * name ) { * to match it, as described in the commenting. */ bool ComplexCollect::supports( EntNode * ents ) const { + ents->sharedMtxP->lock(); EntNode * node = ents, *nextnode; AndList * alist = 0; - ComplexList * clist = clists, *cl = NULL, *current; - bool retval; + ComplexList * clist = clists, *cl = NULL, *current, *prev; + bool retval = false; EntList * elist, *next; // Loop through the nodes of ents. If 1+ of them have >1 supertype, build @@ -112,19 +205,27 @@ bool ComplexCollect::supports( EntNode * ents ) const { cl = new ComplexList( alist ); } current = clists; - while( current ) { - if( current->contains( node ) ) { - // Must add current CList to new CList. First check if we - // added current already (while testing an earlier node). - if( ! cl->toplevel( current->supertype() ) ) { - // Below line adds current to cl. "current->head-> - // childList" points to the EntLists directly under the - // top-level AND. We'll add that list right under the - // new AND we created at cl's top level. - alist->appendList( current->head->childList ); + if( current ) { + current->mtx.lock(); + while( current ) { + if( current->contains( node ) ) { + // Must add current CList to new CList. First check if we + // added current already (while testing an earlier node). + if( ! cl->toplevel( current->supertype() ) ) { + // Below line adds current to cl. "current->head-> + // childList" points to the EntLists directly under the + // top-level AND. We'll add that list right under the + // new AND we created at cl's top level. + alist->appendList( current->head->childList ); + } + } + prev = current; + current = current->next; + if( current ) { + current->mtx.lock(); } + prev->mtx.unlock(); } - current = current->next; } node->next = nextnode; } @@ -136,14 +237,23 @@ bool ComplexCollect::supports( EntNode * ents ) const { if( !cl ) { // If we never built up cl in the above loop, there were no entities // which had mult supers. Simply go through each CList separately: - while( clist != NULL ) { - if( clist->matches( ents ) ) { - return true; + if( clist != NULL ) { + clist->mtx.lock(); + while( clist != NULL ) { + if( clist->matches( ents ) ) { + clist->mtx.unlock(); + retval = true; + break; + } + prev = clist; + clist = clist->next; + if( clist ) { + clist->mtx.lock(); + } + prev->mtx.unlock(); } - clist = clist->next; + // retval will be false if the loop went through whole list without match } - // Went through whole list without match: - return false; } else { // Use cl to test that the conditions of all supertypes are met: cl->multSupers = true; @@ -155,6 +265,7 @@ bool ComplexCollect::supports( EntNode * ents ) const { // to make cl: elist = cl->head->childList; while( elist ) { + // No mutexes are used here since cl has been created and build locally elist->prev = NULL; elist = elist->next; next = elist->next; @@ -165,6 +276,7 @@ bool ComplexCollect::supports( EntNode * ents ) const { // Separate the childList from head. We don't want to delete any of the // sublists when we delete cl - they still belong to other sublists. delete cl; - return retval; } + ents->sharedMtxP->unlock(); + return retval; } diff --git a/src/clstepcore/complexSupport.h b/src/clstepcore/complexSupport.h index 2e925ff48..fc6222ee8 100644 --- a/src/clstepcore/complexSupport.h +++ b/src/clstepcore/complexSupport.h @@ -440,6 +440,11 @@ class SC_CORE_EXPORT ComplexCollect { private: int count; ///< # of clist children + sc_mutex mtx; ///< protects clists and count + /// TODO figure out whether either the above mtx or the mutex defined in + /// ComplexList can be completely removed. Another option is to reduce + /// locking granuality (as only assignments to clists and count need to be + /// protected) }; #endif From 0fe8bc3a91f40cf7e1b4cce3b39d3c7b04f144fe Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 6 Aug 2014 20:31:25 +0530 Subject: [PATCH 085/111] Made ReplicateList in cleditor thread safe Used mtxP of the superclass SingleLinkList to ensure thread safety --- src/cleditor/cmdmgr.cc | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/cleditor/cmdmgr.cc b/src/cleditor/cmdmgr.cc index 7c015ce47..d3a420145 100644 --- a/src/cleditor/cmdmgr.cc +++ b/src/cleditor/cmdmgr.cc @@ -14,15 +14,19 @@ #include "sc_memmgr.h" ReplicateLinkNode * ReplicateList::FindNode( MgrNode * mn ) { + mtxP->lock(); //mtxP belongs to the superclass SingleLinkList ReplicateLinkNode * rln = ( ReplicateLinkNode * )GetHead(); + ReplicateLinkNode * retrln = 0; int numEntries = EntryCount(); while( numEntries-- ) { if( rln->ReplicateNode() == mn ) { - return rln; + retrln = rln; + break; } rln = ( ReplicateLinkNode * )rln->NextNode(); } - return 0; + mtxP->unlock(); + return retrln; } bool ReplicateList::IsOnList( MgrNode * mn ) { @@ -33,28 +37,30 @@ bool ReplicateList::IsOnList( MgrNode * mn ) { // returns true if it could delete the node /////////////////////////////////////////////////////////////////////////////// bool ReplicateList::Remove( ReplicateLinkNode * rln ) { + mtxP->lock(); + bool retval = false; ReplicateLinkNode * rnFollow = ( ReplicateLinkNode * )GetHead(); - if( !rnFollow || !rln ) { - return false; - } else { + if( rnFollow && rln ) { if( rnFollow == rln ) { head = rln->NextNode(); delete rln; - return true; + retval = true; } else { ReplicateLinkNode * rn = ( ReplicateLinkNode * )rnFollow->NextNode(); while( rn ) { if( rn == rln ) { rnFollow->next = ( SingleLinkNode * )rln->NextNode(); delete rln; - return true; + retval = true; + break; } rnFollow = rn; rn = ( ReplicateLinkNode * )rn->NextNode(); } // end while(rn) } // end else } // end else - return false; + mtxP->unlock(); + return retval; } bool ReplicateList::Remove( MgrNode * rn ) { From 376dc4a4826640a8d87ebb1b4a4e4a63b08513ea Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 6 Aug 2014 20:32:52 +0530 Subject: [PATCH 086/111] Thread safety in CmdMgr of cleditor --- src/cleditor/cmdmgr.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cleditor/cmdmgr.cc b/src/cleditor/cmdmgr.cc index d3a420145..204024705 100644 --- a/src/cleditor/cmdmgr.cc +++ b/src/cleditor/cmdmgr.cc @@ -79,9 +79,11 @@ CmdMgr::CmdMgr() { } void CmdMgr::ReplicateCmdList( MgrNode * mn ) { + replicateList->mtxP->lock(); // To prevent double appending of mn if( !( replicateList->IsOnList( mn ) ) ) { replicateList->AddNode( mn ); } + replicateList->mtxP->unlock(); } void CmdMgr::ClearInstances() { From 3c616f1455e27980d8a5faf8ebb08b3ec14f2a04 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 6 Aug 2014 20:36:25 +0530 Subject: [PATCH 087/111] Made DirObj of clutils thread safe This was achieved introducing a mutex in the DirObj class. Course-Level (fat) Locking was done only in publically accessed function. --- src/clutils/dirobj.cc | 16 ++++++++++++---- src/clutils/dirobj.h | 9 ++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/clutils/dirobj.cc b/src/clutils/dirobj.cc index 162beada8..3f224f201 100644 --- a/src/clutils/dirobj.cc +++ b/src/clutils/dirobj.cc @@ -111,11 +111,15 @@ const char * DirObj::RealPath( const char * path ) { /////////////////////////////////////////////////////////////////////////////// bool DirObj::LoadDirectory( const std::string & name ) { + bool retval; + mtx.lock(); if( name.empty() ) { - return Reset( "./" ); + retval = Reset( "./" ); } else { - return Reset( name ); + retval = Reset( name ); } + mtx.unlock(); + return retval; } //////////////////////////////// Index() ////////////////////////////////////// @@ -126,12 +130,16 @@ bool DirObj::LoadDirectory( const std::string & name ) { /////////////////////////////////////////////////////////////////////////////// int DirObj::Index( const char * name ) { + int index = -1; + mtx.lock(); for( int i = 0; i < fileCount; ++i ) { if( strcmp( fileList[i], name ) == 0 ) { - return i; + index = i; + break; } } - return -1; + mtx.unlock(); + return index; } //////////////////////////////// Reset() ////////////////////////////////////// diff --git a/src/clutils/dirobj.h b/src/clutils/dirobj.h index a89e28dad..a4bac6383 100644 --- a/src/clutils/dirobj.h +++ b/src/clutils/dirobj.h @@ -43,6 +43,7 @@ #endif #include +#include /*****************************************************************************/ @@ -83,6 +84,9 @@ class SC_UTILS_EXPORT DirObj { char ** fileList; int fileCount; int fileListSize; + // Our strategy for locking is to only lock the public + // functions. Thus we will not need a recursive mutex + sc_mutex mtx; }; // Return the number of files in the loaded directory. @@ -97,7 +101,10 @@ inline void DirObj::AppendFile( const char * s ) { // Return the file at the given index (starting at 0) in the fileList inline const char * DirObj::File( int index ) { - return ( 0 <= index && index < fileCount ) ? fileList[index] : 0; + mtx.lock(); + const char * fn = ( 0 <= index && index < fileCount ) ? fileList[index] : 0; + mtx.unlock(); + return fn; } #endif From 7f653188c4b99eb077a86b8f1378d42151b11002 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 8 Aug 2014 11:04:21 +0530 Subject: [PATCH 088/111] Converted GetKeyword to FillKeyword In the original function a static string was being used. The dependency on the static string was removed by passing a string as a parameter from the caller to callee, so that the function could operate without worrying about thread safety. The function name change mimics the change in the semantics of the function. --- src/cleditor/STEPfile.cc | 15 ++++++++------- src/cllazyfile/sectionReader.cc | 2 +- src/clstepcore/read_func.cc | 14 +++++--------- src/clstepcore/read_func.h | 2 +- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/cleditor/STEPfile.cc b/src/cleditor/STEPfile.cc index 4e35c4b09..723101638 100644 --- a/src/cleditor/STEPfile.cc +++ b/src/cleditor/STEPfile.cc @@ -149,7 +149,7 @@ Severity STEPfile::ReadHeader( istream & in ) { } //get the entity keyword - keywd = GetKeyword( in, ";( /\\", _error ); + FillKeyword( in, ";( /\\", _error, keywd ); ReadTokenSeparator( in, &cmtStr ); //check for "ENDSEC" @@ -913,7 +913,7 @@ Severity STEPfile::CreateScopeInstances( istream & in, SDAI_Application_instance std::vector< SDAI_Application_instance_ptr > inscope; std::string keywd; - keywd = GetKeyword( in, " \n\t/\\#;", _error ); + FillKeyword( in, " \n\t/\\#;", _error, keywd ); if( strncmp( const_cast( keywd.c_str() ), "&SCOPE", 6 ) ) { //ERROR: "&SCOPE" expected //TODO: should attempt to recover by reading through ENDSCOPE @@ -955,7 +955,7 @@ Severity STEPfile::CreateScopeInstances( istream & in, SDAI_Application_instance } //check for "ENDSCOPE" - keywd = GetKeyword( in, " \t\n/\\#;", _error ); + FillKeyword( in, " \t\n/\\#;", _error, keywd ); if( strncmp( const_cast( keywd.c_str() ), "ENDSCOPE", 8 ) ) { //ERROR: "ENDSCOPE" expected SkipInstance( in, tmpbuf ); @@ -1071,7 +1071,7 @@ Severity STEPfile::ReadScopeInstances( istream & in ) { std::string keywd; std::string cmtStr; - keywd = GetKeyword( in, " \n\t/\\#;", _error ); + FillKeyword( in, " \n\t/\\#;", _error, keywd ); if( strncmp( const_cast( keywd.c_str() ), "&SCOPE", 6 ) ) { //ERROR: "&SCOPE" expected SkipInstance( in, tmpbuf ); @@ -1099,7 +1099,7 @@ Severity STEPfile::ReadScopeInstances( istream & in ) { in.putback( c ); //check for "ENDSCOPE" - keywd = GetKeyword( in, " \t\n/\\#;", _error ); + FillKeyword( in, " \t\n/\\#;", _error, keywd ); if( strncmp( const_cast( keywd.c_str() ), "ENDSCOPE", 8 ) ) { //ERROR: "ENDSCOPE" expected SkipInstance( in, tmpbuf ); @@ -1609,7 +1609,8 @@ Severity STEPfile::AppendFile( istream * in, bool useTechCor ) { int total_insts = 0, valid_insts = 0; ReadTokenSeparator( *in ); - std::string keywd = GetKeyword( *in, "; #", _error ); + std::string keywd; + FillKeyword( *in, "; #", _error, keywd ); // get the delimiter off the istream char c; in->get( c ); @@ -1730,7 +1731,7 @@ Severity STEPfile::AppendFile( istream * in, bool useTechCor ) { if( in2 -> good() ) { ReadTokenSeparator( *in2 ); - keywd = GetKeyword( *in2, ";", _error ); + FillKeyword( *in2, ";", _error, keywd ); //yank the ";" from the istream //if (';' == in2->peek()) in2->get(); char ch; diff --git a/src/cllazyfile/sectionReader.cc b/src/cllazyfile/sectionReader.cc index 57badcbf1..ccd34eab5 100644 --- a/src/cllazyfile/sectionReader.cc +++ b/src/cllazyfile/sectionReader.cc @@ -81,7 +81,7 @@ std::streampos sectionReader::findNormalString( const std::string & str, bool se } -//NOTE different behavior than const char * GetKeyword( istream & in, const char * delims, ErrorDescriptor & err ) in read_func.cc +//NOTE different behavior than const char * FillKeyword( istream & in, const char * delims, ErrorDescriptor & err, std::string & str ) in read_func.cc void sectionReader::fillDelimitedKeyword( const char * delimiters, std::string &str ) { char c, firstSpaceDelimeter; str.clear(); diff --git a/src/clstepcore/read_func.cc b/src/clstepcore/read_func.cc index 395e52cfd..499f97e63 100644 --- a/src/clstepcore/read_func.cc +++ b/src/clstepcore/read_func.cc @@ -671,23 +671,20 @@ const char * ReadStdKeyword( istream & in, std::string & buf, int skipInitWS ) { } /*************************** -This function returns a null terminated const char* for the +This function fills str with a null terminated const char* for the characters read from the istream up to, but not including the first character found in the set of delimiters, or the whitespace character. It leaves the delimiter on the istream. -The string is returned in a static buffer, so it will change -the next time the function is called. - Keywords are special strings of characters indicating the instance of an entity of a specific type. They shall consist of uppercase letters, digits, underscore characters, and possibly an exclamation mark. The "!" shall appear only once, and only as the first character. ***************************/ -const char * GetKeyword( istream & in, const char * delims, ErrorDescriptor & err ) { +void FillKeyword( istream & in, const char * delims, ErrorDescriptor & err, std::string & str ) { char c; int sz = 1; - static std::string str; + str.clear(); str = ""; in.get( c ); @@ -699,10 +696,10 @@ const char * GetKeyword( istream & in, const char * delims, ErrorDescriptor & er ( c == '-' ) || //for reading 'ISO-10303-21' ( ( c == '!' ) && ( sz == 1 ) ) ) ) { cerr << "Error: Invalid character \'" << c << - "\' in GetKeyword.\nkeyword was: " << str << "\n"; + "\' in FillKeyword.\nkeyword was: " << str << "\n"; err.GreaterSeverity( SEVERITY_WARNING ); in.putback( c ); - return const_cast( str.c_str() ); + return; } if( !in.good() ) { break; //BUG: should do something on eof() @@ -712,7 +709,6 @@ const char * GetKeyword( istream & in, const char * delims, ErrorDescriptor & er in.get( c ); } in.putback( c ); - return const_cast( str.c_str() ); } /** diff --git a/src/clstepcore/read_func.h b/src/clstepcore/read_func.h index 92cff5705..103cf398f 100644 --- a/src/clstepcore/read_func.h +++ b/src/clstepcore/read_func.h @@ -67,7 +67,7 @@ extern SC_CORE_EXPORT const char * SkipSimpleRecord( istream & in, std::string & /// this includes entity names extern SC_CORE_EXPORT const char * ReadStdKeyword( istream & in, std::string & buf, int skipInitWS = 1 ); -extern SC_CORE_EXPORT const char * GetKeyword( istream & in, const char * delims, ErrorDescriptor & err ); +extern SC_CORE_EXPORT void FillKeyword( istream & in, const char * delims, ErrorDescriptor & err, std::string & str ); extern SC_CORE_EXPORT int FoundEndSecKywd( istream& in ); From 9f24e3ef6470b12e2cf12c672ac4105df100f108 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 8 Aug 2014 20:10:05 +0530 Subject: [PATCH 089/111] Optimized ReadReal Replaced calls to input stream peek & get with judicious use of get. --- src/clstepcore/read_func.cc | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/clstepcore/read_func.cc b/src/clstepcore/read_func.cc index 499f97e63..a46315964 100644 --- a/src/clstepcore/read_func.cc +++ b/src/clstepcore/read_func.cc @@ -224,11 +224,12 @@ int ReadReal( SDAI_Real & val, istream & in, ErrorDescriptor * err, in >> ws; // skip white space // read optional sign - c = in.peek(); + c = in.get(); if( c == '+' || c == '-' ) { - in.get( buf[i++] ); - c = in.peek(); + buf[i++] = c; + c = in.get(); } + //in is at the character next to c // check for required initial decimal digit if( !isdigit( c ) ) { @@ -237,26 +238,29 @@ int ReadReal( SDAI_Real & val, istream & in, ErrorDescriptor * err, } // read one or more decimal digits while( isdigit( c ) ) { - in.get( buf[i++] ); - c = in.peek(); + buf[i++] = c; + c = in.get(); } + //in is at the character next to c // read Part 21 required decimal point if( c == '.' ) { - in.get( buf[i++] ); - c = in.peek(); + buf[i++] = c; + c = in.get(); } else { // It may be the number they wanted but it is incompletely specified // without a decimal and thus it is an error e.GreaterSeverity( SEVERITY_WARNING ); e.AppendToDetailMsg( "Reals are required to have a decimal point.\n" ); } + //in is at the character next to c // read optional decimal digits while( isdigit( c ) ) { - in.get( buf[i++] ); - c = in.peek(); + buf[i++] = c; + c = in.get(); } + //in is at the character next to c // try to read an optional E for scientific notation if( ( c == 'e' ) || ( c == 'E' ) ) { @@ -266,13 +270,13 @@ int ReadReal( SDAI_Real & val, istream & in, ErrorDescriptor * err, e.AppendToDetailMsg( "Reals using scientific notation must use upper case E.\n" ); } - in.get( buf[i++] ); // read the E - c = in.peek(); + buf[i++] = c; // read the E + c = in.get(); // read optional sign if( c == '+' || c == '-' ) { - in.get( buf[i++] ); - c = in.peek(); + buf[i++] = c; + c = in.get(); } // read required decimal digit (since it has an E) @@ -283,10 +287,13 @@ int ReadReal( SDAI_Real & val, istream & in, ErrorDescriptor * err, } // read one or more decimal digits while( isdigit( c ) ) { - in.get( buf[i++] ); - c = in.peek(); + buf[i++] = c; + c = in.get(); } + //in is at the character next to c } + + in.unget(); //in is now at c buf[i] = '\0'; istringstream in2( ( char * )buf ); From e3fbc142824311b5f88fcf927584ed4e2c1a5d08 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 10 Aug 2014 22:44:11 +0530 Subject: [PATCH 090/111] Removed istream *in2 from STEPfile::AppendFile Originally For the second pass a new istream (in2) was being created and the .step file was being opened again. This was prevented by directing the original istream (in) to the beggining of the .step file. --- src/cleditor/STEPfile.cc | 39 ++++++++++----------------------------- 1 file changed, 10 insertions(+), 29 deletions(-) diff --git a/src/cleditor/STEPfile.cc b/src/cleditor/STEPfile.cc index 723101638..ce3d327ab 100644 --- a/src/cleditor/STEPfile.cc +++ b/src/cleditor/STEPfile.cc @@ -1673,26 +1673,11 @@ Severity STEPfile::AppendFile( istream * in, bool useTechCor ) { cout << errbuf; // PASS 2 - // This would be nicer if you didn't actually have to close the - // file but could just reposition the pointer back to the - // beginning of the data section. It looks like you can do this - // with the GNU File class, but that class doesn't have the - // operator >> overloaded which is used to do the rest of the - // parsing. SO we are using istreams and this works, but could - // be better. - // reset the error count so you're not counting things twice: _errorCount = 0; - istream * in2; - if( !( ( in2 = OpenInputFile() ) && ( in2 -> good() ) ) ) { - // if the stream is not readable, there's an error - _error.AppendToUserMsg( "Cannot open file for 2nd pass -- No data read.\n" ); - CloseInputFile( in2 ); - return SEVERITY_INPUT_ERROR; - } - if( !FindDataSection( *in2 ) ) { + in->seekg( 0, std::ifstream::beg ); + if( !FindDataSection( *in ) ) { _error.AppendToUserMsg( "Error: Unable to find DATA section delimiter in second pass. \nData section not read. Rest of file ignored.\n" ); - CloseInputFile( in2 ); return SEVERITY_INPUT_ERROR; } @@ -1700,21 +1685,19 @@ Severity STEPfile::AppendFile( istream * in, bool useTechCor ) { case VERSION_CURRENT: case VERSION_UNKNOWN: case WORKING_SESSION: - valid_insts = ReadData2( *in2, useTechCor ); + valid_insts = ReadData2( *in, useTechCor ); break; default: _error.AppendToUserMsg( "STEPfile::AppendFile: STEP file version set to unrecognized value.\n" ); - CloseInputFile( in2 ); return SEVERITY_BUG; } //check for "ENDSEC;" - ReadTokenSeparator( *in2 ); + ReadTokenSeparator( *in ); if( total_insts != valid_insts ) { sprintf( errbuf, "%d invalid instances in file: %s\n", total_insts - valid_insts, ( ( FileName().compare( "-" ) == 0 ) ? "standard input" : FileName().c_str() ) ); _error.AppendToUserMsg( errbuf ); - CloseInputFile( in2 ); return _error.GreaterSeverity( SEVERITY_WARNING ); } @@ -1729,25 +1712,23 @@ Severity STEPfile::AppendFile( istream * in, bool useTechCor ) { //check for "ENDSTEP;" || "END-ISO-10303-21;" - if( in2 -> good() ) { - ReadTokenSeparator( *in2 ); - FillKeyword( *in2, ";", _error, keywd ); + if( in -> good() ) { + ReadTokenSeparator( *in ); + FillKeyword( *in, ";", _error, keywd ); //yank the ";" from the istream - //if (';' == in2->peek()) in2->get(); + //if (';' == in->peek()) in->get(); char ch; - in2->get( ch ); + in->get( ch ); if( ch != ';' ) { std::cerr << __FILE__ << ":" << __LINE__ << " - Expected ';' at Part 21 EOF, found '" << c << "'." << std::endl; } } - if( ( !keywd.compare( 0, keywd.size(), END_FILE_DELIM ) ) || !( in2 -> good() ) ) { + if( ( !keywd.compare( 0, keywd.size(), END_FILE_DELIM ) ) || !( in -> good() ) ) { _error.AppendToUserMsg( END_FILE_DELIM ); _error.AppendToUserMsg( " missing at end of file.\n" ); - CloseInputFile( in2 ); return _error.GreaterSeverity( SEVERITY_WARNING ); } - CloseInputFile( in2 ); cout << "Finished reading file.\n\n"; return SEVERITY_NULL; } From a3ce139347324ffa68defc0d7dbba7043d48b66a Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 13 Aug 2014 10:07:32 +0530 Subject: [PATCH 091/111] Protected _headerId in STEPfile (cleditor) _headerId is a counter used in STEPfile class. Its value can change in ReadHeader and ReadExchangeFile methods. Hence a mutex was introduced in order to protect it. --- src/cleditor/STEPfile.cc | 6 +++++- src/cleditor/STEPfile.h | 2 ++ src/cleditor/STEPfile.inline.cc | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/cleditor/STEPfile.cc b/src/cleditor/STEPfile.cc index ce3d327ab..40966e342 100644 --- a/src/cleditor/STEPfile.cc +++ b/src/cleditor/STEPfile.cc @@ -1480,7 +1480,11 @@ int STEPfile::HeaderId( const char * name ) { if( tmp == "FILE_SCHEMA" ) { return 3; } - return ++_headerId; + + _headerIdMtx.lock(); + int myHeaderId = ++_headerId; + _headerIdMtx.unlock(); + return myHeaderId; } /*************************** diff --git a/src/cleditor/STEPfile.h b/src/cleditor/STEPfile.h index 124795539..1392e8d0d 100644 --- a/src/cleditor/STEPfile.h +++ b/src/cleditor/STEPfile.h @@ -23,6 +23,7 @@ #include #include +#include //error reporting level #define READ_COMPLETE 10 @@ -55,6 +56,7 @@ class SC_EDITOR_EXPORT STEPfile { Registry * _headerRegistry; int _headerId; ///< STEPfile_id given to SDAI_Application_instance from header section + sc_mutex _headerIdMtx; ///< Protects the _headerId //file information DirObj * _currentDir; diff --git a/src/cleditor/STEPfile.inline.cc b/src/cleditor/STEPfile.inline.cc index 2d4e6d9dd..5faf8fa59 100644 --- a/src/cleditor/STEPfile.inline.cc +++ b/src/cleditor/STEPfile.inline.cc @@ -113,7 +113,9 @@ Severity STEPfile::ReadExchangeFile( const std::string filename, bool useTechCor if( _headerInstances ) { _headerInstances->ClearInstances(); } + _headerIdMtx.lock(); _headerId = 5; + _headerIdMtx.unlock(); Severity rval = AppendFile( in, useTechCor ); CloseInputFile( in ); return rval; From 9cbe6d1dd9827403bae89781c2f06aa11cdcbe71 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 13 Aug 2014 10:19:24 +0530 Subject: [PATCH 092/111] GetApplication_instanceFromFileId in InstMgr class The SDAI_Application_instance * GetApplication_instance( MgrNode * ) and MgrNode * FindFileId( int ) methods of class InstMgr were often being used together in the class STEPfile. Hence a special function was created in class InstMgr of the form SDAI_Application_instance * GetApplication_instanceFromFileId( int ) which would take care of locking and consistency issues. This function was then used in STEPfile. --- src/cleditor/STEPfile.cc | 18 +++++++++--------- src/clstepcore/instmgr.cc | 14 ++++++++++++++ src/clstepcore/instmgr.h | 3 +++ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/cleditor/STEPfile.cc b/src/cleditor/STEPfile.cc index 40966e342..96cf6214d 100644 --- a/src/cleditor/STEPfile.cc +++ b/src/cleditor/STEPfile.cc @@ -367,9 +367,9 @@ void STEPfile::HeaderMergeInstances( InstMgr * im ) { //checking for _headerInstances::FILE_NAME idnum = HeaderId( "File_Name" ); - se = _headerInstances->GetApplication_instance( _headerInstances->FindFileId( idnum ) ); + se = _headerInstances->GetApplication_instanceFromFileId( idnum ); if( se ) { - from = im->GetApplication_instance( im->FindFileId( idnum ) ); + from = im->GetApplication_instanceFromFileId( idnum ); // name: // time_stamp: keep the newer time_stamp @@ -379,33 +379,33 @@ void STEPfile::HeaderMergeInstances( InstMgr * im ) { // originating_system: // authorization: } else { // No current File_Name instance - from = im->GetApplication_instance( im->FindFileId( idnum ) ); + from = im->GetApplication_instanceFromFileId( idnum ); _headerInstances->Append( from, completeSE ); } //checking for _headerInstances::FILE_DESCRIPTION idnum = HeaderId( "File_Description" ); - se = _headerInstances->GetApplication_instance( _headerInstances->FindFileId( idnum ) ); + se = _headerInstances->GetApplication_instanceFromFileId( idnum ); if( se ) { - from = im->GetApplication_instance( im->FindFileId( idnum ) ); + from = im->GetApplication_instanceFromFileId( idnum ); //description //implementation_level } else { - from = im->GetApplication_instance( im->FindFileId( idnum ) ); + from = im->GetApplication_instanceFromFileId( idnum ); _headerInstances->Append( from, completeSE ); } //checking for _headerInstances::FILE_SCHEMA idnum = HeaderId( "File_Schema" ); - se = _headerInstances->GetApplication_instance( _headerInstances->FindFileId( idnum ) ); + se = _headerInstances->GetApplication_instanceFromFileId( idnum ); if( se ) { - from = im->GetApplication_instance( im->FindFileId( idnum ) ); + from = im->GetApplication_instanceFromFileId( idnum ); //description //implementation_level } else { - from = im->GetApplication_instance( im->FindFileId( idnum ) ); + from = im->GetApplication_instanceFromFileId( idnum ); _headerInstances->Append( from, completeSE ); } diff --git a/src/clstepcore/instmgr.cc b/src/clstepcore/instmgr.cc index b5644011b..93fb73555 100644 --- a/src/clstepcore/instmgr.cc +++ b/src/clstepcore/instmgr.cc @@ -424,3 +424,17 @@ InstMgr::GetSEE( int index ) { return 0; } } + +/////////////////////////////////////////////////////////////////////////////// +/******************************************************* + description: + This function returns the SDAI_Application_instance + with the given fileId. +********************************************************/ + +SDAI_Application_instance * InstMgr::GetApplication_instanceFromFileId( int fileId ) { + masterMtx.lock(); + SDAI_Application_instance * se = GetApplication_instance( FindFileId( fileId ) ); + masterMtx.unlock(); + return se; +} diff --git a/src/clstepcore/instmgr.h b/src/clstepcore/instmgr.h index aa638028d..2ad674030 100644 --- a/src/clstepcore/instmgr.h +++ b/src/clstepcore/instmgr.h @@ -112,6 +112,9 @@ class SC_CORE_EXPORT InstMgr { return node->GetApplication_instance(); } + // Returns a SDAI_Application_instance from the fileId in an thread safe manner + SDAI_Application_instance * GetApplication_instanceFromFileId( int fileId ); + void * GetSEE( int index ); void * GetSEE( MgrNode * node ) { return node->SEE(); From 02b41416fbaf7e7160dbdde911c4e64de3570862 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 13 Aug 2014 10:44:34 +0530 Subject: [PATCH 093/111] Safe InstMgr iteration in STEPfile Variables of class InstMgr were being iterated upon in class STEPfile through the variables _instances (including its get function instances()) and _headerInstances. The mtx defined in InstMgr was invoked to make them safe. --- src/cleditor/STEPfile.cc | 9 +++++++++ src/cleditor/STEPfile.inline.cc | 2 ++ src/clstepcore/instmgr.h | 3 ++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/cleditor/STEPfile.cc b/src/cleditor/STEPfile.cc index 96cf6214d..6a6cae1c1 100644 --- a/src/cleditor/STEPfile.cc +++ b/src/cleditor/STEPfile.cc @@ -1498,6 +1498,7 @@ void STEPfile::WriteHeader( ostream & out ) { // Write the rest of the header instances SDAI_Application_instance * se; + _headerInstances->masterMtx.lock(); int n = _headerInstances->InstanceCount(); for( int i = 0; i < n; ++i ) { se = _headerInstances->GetMgrNode( i ) ->GetApplication_instance(); @@ -1509,6 +1510,7 @@ void STEPfile::WriteHeader( ostream & out ) { WriteHeaderInstance( _headerInstances->GetMgrNode( i )->GetApplication_instance(), out ); } + _headerInstances->masterMtx.unlock(); out << "ENDSEC;\n"; } @@ -1588,21 +1590,25 @@ void STEPfile::WriteData( ostream & out, int writeComments ) { std::string currSch = schemaName(); out << "DATA;\n"; + instances().masterMtx.lock(); int n = instances().InstanceCount(); for( int i = 0; i < n; ++i ) { instances().GetMgrNode( i )->GetApplication_instance()->STEPwrite( out, currSch.c_str(), writeComments ); _oFileInstsWritten++; } + instances().masterMtx.unlock(); out << "ENDSEC;\n"; } void STEPfile::WriteValuePairsData( ostream & out, int writeComments, int mixedCase ) { std::string currSch = schemaName(); + instances().masterMtx.lock(); int n = instances().InstanceCount(); for( int i = 0; i < n; ++i ) { instances().GetMgrNode( i )->GetApplication_instance()->WriteValuePairs( out, currSch.c_str(), writeComments, mixedCase ); } + instances().masterMtx.unlock(); } Severity STEPfile::AppendFile( istream * in, bool useTechCor ) { @@ -1776,6 +1782,8 @@ Severity STEPfile::WriteWorkingFile( const std::string filename, int clearError, void STEPfile::WriteWorkingData( ostream & out, int writeComments ) { std::string currSch = schemaName(); out << "DATA;\n"; + + instances().masterMtx.lock(); int n = instances().InstanceCount(); for( int i = 0; i < n; ++i ) { @@ -1805,6 +1813,7 @@ void STEPfile::WriteWorkingData( ostream & out, int writeComments ) { break; } } + instances().masterMtx.unlock(); out << "ENDSEC;\n"; } diff --git a/src/cleditor/STEPfile.inline.cc b/src/cleditor/STEPfile.inline.cc index 5faf8fa59..99667debd 100644 --- a/src/cleditor/STEPfile.inline.cc +++ b/src/cleditor/STEPfile.inline.cc @@ -264,11 +264,13 @@ int STEPfile::IncrementFileId( int fileid ) { void STEPfile::SetFileIdIncrement() { + instances().masterMtx.lock(); if( instances().MaxFileId() < 0 ) { _fileIdIncr = 0; } else { _fileIdIncr = ( int )( ( ceil( ( instances().MaxFileId() + 99.0 ) / 1000.0 ) + 1.0 ) * 1000.0 ); } + instances().masterMtx.unlock(); } /** diff --git a/src/clstepcore/instmgr.h b/src/clstepcore/instmgr.h index 2ad674030..9d7eea271 100644 --- a/src/clstepcore/instmgr.h +++ b/src/clstepcore/instmgr.h @@ -48,9 +48,10 @@ class SC_CORE_EXPORT InstMgr { // this corresponds to the display list object by index MgrNodeArraySorted * sortedMaster; // master array sorted by fileId // StateList *master; // this will be an sorted array of ptrs to MgrNodes - sc_recursive_mutex masterMtx; public: + sc_recursive_mutex masterMtx; // is public as it is used in STEPfile + InstMgr( int ownsInstances = 0 ); virtual ~InstMgr(); From 91efe7c0e57ecf30a376e9cd6c818441079beba4 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 13 Aug 2014 10:55:12 +0530 Subject: [PATCH 094/111] Safe attributes iteration in STEPfile --- src/cleditor/STEPfile.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/cleditor/STEPfile.cc b/src/cleditor/STEPfile.cc index 6a6cae1c1..843093b08 100644 --- a/src/cleditor/STEPfile.cc +++ b/src/cleditor/STEPfile.cc @@ -1522,6 +1522,8 @@ void STEPfile::WriteHeaderInstance( SDAI_Application_instance * obj, ostream & o out << obj->P21Comment(); } out << StrToUpper( obj->EntityName(), tmp ) << "("; + obj->mtx.lock(); + obj->attributes.mtxP->lock(); int n = obj->attributes.list_length(); for( int i = 0; i < n; ++i ) { ( obj->attributes[i] ).STEPwrite( out ); @@ -1529,6 +1531,8 @@ void STEPfile::WriteHeaderInstance( SDAI_Application_instance * obj, ostream & o out << ","; } } + obj->attributes.mtxP->unlock(); + obj->mtx.unlock(); out << ");\n"; } From e9412446170ecac1983a5226fc9c517e8a2fe008 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 13 Aug 2014 11:15:41 +0530 Subject: [PATCH 095/111] Added a comment about thread safety in STEPfile --- src/cleditor/STEPfile.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/cleditor/STEPfile.h b/src/cleditor/STEPfile.h index 1392e8d0d..3e3f3c651 100644 --- a/src/cleditor/STEPfile.h +++ b/src/cleditor/STEPfile.h @@ -37,6 +37,11 @@ enum FileTypeCode { }; class SC_EDITOR_EXPORT STEPfile { + /// hoiji09: As this class is a parser, the locking in this class is dependent upon how it is + /// being used in a multithreaded way. Example: The variable llke _fileName restricts + /// this class to parse only one file at a time. If we want to parse more then one + /// then this will have to change. + protected: //data members From 731673f8270d1ff48c5a9b47f192dcf76c5fbe22 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Wed, 13 Aug 2014 21:06:26 +0530 Subject: [PATCH 096/111] Thread safety in SDAI_Application_instance__set Done by introducing a recursive_mutex in the SDAI_Application_instance__set class. --- src/cldai/sdaiApplication_instance_set.cc | 25 ++++++++++++++++++++--- src/cldai/sdaiApplication_instance_set.h | 3 +++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/cldai/sdaiApplication_instance_set.cc b/src/cldai/sdaiApplication_instance_set.cc index c50fdc0e8..5c9fbfb24 100644 --- a/src/cldai/sdaiApplication_instance_set.cc +++ b/src/cldai/sdaiApplication_instance_set.cc @@ -54,6 +54,7 @@ SDAI_Application_instance__set::~SDAI_Application_instance__set() { void SDAI_Application_instance__set::Check( int index ) { SDAI_Application_instance_ptr * newbuf; + mtx.lock(); if( index >= _bufsize ) { _bufsize = ( index + 1 ) * 2; newbuf = new SDAI_Application_instance_ptr[_bufsize]; @@ -61,10 +62,12 @@ void SDAI_Application_instance__set::Check( int index ) { delete _buf; _buf = newbuf; } + mtx.unlock(); } void SDAI_Application_instance__set::Insert( SDAI_Application_instance_ptr v, int index ) { SDAI_Application_instance_ptr * spot; + mtx.lock(); index = ( index < 0 ) ? _count : index; if( index < _count ) { @@ -78,9 +81,11 @@ void SDAI_Application_instance__set::Insert( SDAI_Application_instance_ptr v, in } *spot = v; ++_count; + mtx.unlock(); } void SDAI_Application_instance__set::Append( SDAI_Application_instance_ptr v ) { + mtx.lock(); int index = _count; SDAI_Application_instance_ptr * spot; @@ -95,37 +100,49 @@ void SDAI_Application_instance__set::Append( SDAI_Application_instance_ptr v ) { } *spot = v; ++_count; + mtx.unlock(); } void SDAI_Application_instance__set::Remove( int index ) { + mtx.lock(); if( 0 <= index && index < _count ) { --_count; SDAI_Application_instance_ptr * spot = &_buf[index]; memmove( spot, spot + 1, ( _count - index )*sizeof( SDAI_Application_instance_ptr ) ); } + mtx.unlock(); } void SDAI_Application_instance__set::Remove( SDAI_Application_instance_ptr a ) { + mtx.lock(); int index = Index( a ); if( !( index < 0 ) ) { Remove( index ); } + mtx.unlock(); } int SDAI_Application_instance__set::Index( SDAI_Application_instance_ptr v ) { + int retval = -1; + mtx.lock(); for( int i = 0; i < _count; ++i ) { if( _buf[i] == v ) { - return i; + retval = i; + break; } } - return -1; + mtx.unlock(); + return retval; } SDAI_Application_instance_ptr & SDAI_Application_instance__set::operator[]( int index ) { + mtx.lock(); Check( index ); // _count = max(_count, index+1); _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); - return _buf[index]; + SDAI_Application_instance_ptr saip = _buf[index]; + mtx.unlock(); + return saip; } int @@ -135,5 +152,7 @@ SDAI_Application_instance__set::Count() { void SDAI_Application_instance__set::Clear() { + mtx.lock(); _count = 0; + mtx.unlock(); } diff --git a/src/cldai/sdaiApplication_instance_set.h b/src/cldai/sdaiApplication_instance_set.h index 378e65443..567afaa7e 100644 --- a/src/cldai/sdaiApplication_instance_set.h +++ b/src/cldai/sdaiApplication_instance_set.h @@ -31,6 +31,7 @@ #define SDAI_APPLICATION_INSTANCE_SET_h #include +#include class SDAI_Application_instance; class SDAI_Application_instance__set; @@ -57,6 +58,8 @@ class SC_DAI_EXPORT SDAI_Application_instance__set { SDAI_Application_instance ** _buf; int _bufsize; int _count; + sc_recursive_mutex mtx; // A recursive mutex was needed as there is an + // interdependency between various public APIs }; #endif From b17bcbdaf02f66d2f7867d9c01f53cbb630d179e Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 15 Aug 2014 20:41:30 +0530 Subject: [PATCH 097/111] Removed warning from SDAI_instance__set commit --- src/cldai/sdaiApplication_instance_set.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cldai/sdaiApplication_instance_set.cc b/src/cldai/sdaiApplication_instance_set.cc index 5c9fbfb24..32bcd2c04 100644 --- a/src/cldai/sdaiApplication_instance_set.cc +++ b/src/cldai/sdaiApplication_instance_set.cc @@ -140,7 +140,7 @@ SDAI_Application_instance_ptr & SDAI_Application_instance__set::operator[]( int Check( index ); // _count = max(_count, index+1); _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); - SDAI_Application_instance_ptr saip = _buf[index]; + SDAI_Application_instance_ptr & saip = _buf[index]; mtx.unlock(); return saip; } From fa75e8ceddeb5c8cb0891873fe4fefcf122ae818 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 15 Aug 2014 21:41:50 +0530 Subject: [PATCH 098/111] Added class sdaiSet in cldai library This class will act as a superclass of few other classes in the same library, hence will contain the common logic of its subclasses. --- src/cldai/CMakeLists.txt | 2 + src/cldai/sdaiSet.cc | 119 +++++++++++++++++++++++++++++++++++++++ src/cldai/sdaiSet.h | 38 +++++++++++++ src/clstepcore/sdai.h | 2 + 4 files changed, 161 insertions(+) create mode 100644 src/cldai/sdaiSet.cc create mode 100644 src/cldai/sdaiSet.h diff --git a/src/cldai/CMakeLists.txt b/src/cldai/CMakeLists.txt index f466d043a..6c72d3cda 100644 --- a/src/cldai/CMakeLists.txt +++ b/src/cldai/CMakeLists.txt @@ -10,6 +10,7 @@ set(LIBSTEPDAI_SRCS sdaiModel_contents_list.cc sdaiObject.cc sdaiSession_instance.cc + sdaiSet.cc sdaiString.cc ) @@ -24,6 +25,7 @@ SET(SC_CLDAI_HDRS sdaiModel_contents_list.h sdaiObject.h sdaiSession_instance.h + sdaiSet.h sdaiString.h ) diff --git a/src/cldai/sdaiSet.cc b/src/cldai/sdaiSet.cc new file mode 100644 index 000000000..7d467ca5d --- /dev/null +++ b/src/cldai/sdaiSet.cc @@ -0,0 +1,119 @@ +#include +#include + +#include +#include "sc_memmgr.h" + +#ifndef HAVE_MEMMOVE +extern "C" +{ + void * memmove( void * __s1, const void * __s2, size_t __n ); +} +#endif + +/*****************************************************************************/ + +SDAI__set::SDAI__set( int defaultSize ) { + _bufsize = defaultSize; + _buf = new SDAI_ptr[_bufsize]; + _count = 0; +} + +SDAI__set::~SDAI__set() { + delete _buf; +} + +void SDAI__set::Check( int index ) { + SDAI_ptr * newbuf; + + if( index >= _bufsize ) { + _bufsize = ( index + 1 ) * 2; + newbuf = new SDAI_ptr[_bufsize]; + memmove( newbuf, _buf, _count * sizeof( SDAI_ptr ) ); + delete _buf; + _buf = newbuf; + } +} + +void +SDAI__set::Insert( SDAI_ptr v, int index ) { + + SDAI_ptr * spot; + index = ( index < 0 ) ? _count : index; + + if( index < _count ) { + Check( _count + 1 ); + spot = &_buf[index]; + memmove( spot + 1, spot, ( _count - index )*sizeof( SDAI_ptr ) ); + + } else { + Check( index ); + spot = &_buf[index]; + } + *spot = v; + ++_count; +} + +void SDAI__set::Append( SDAI_ptr v ) { + + int index = _count; + SDAI_ptr * spot; + + if( index < _count ) { + Check( _count + 1 ); + spot = &_buf[index]; + memmove( spot + 1, spot, ( _count - index )*sizeof( SDAI_ptr ) ); + + } else { + Check( index ); + spot = &_buf[index]; + } + *spot = v; + ++_count; +} + +void SDAI__set::Remove( int index ) { + + if( 0 <= index && index < _count ) { + --_count; + SDAI_ptr * spot = &_buf[index]; + memmove( spot, spot + 1, ( _count - index )*sizeof( SDAI_ptr ) ); + } +} + +int SDAI__set::Index( SDAI_ptr v ) { + + for( int i = 0; i < _count; ++i ) { + if( _buf[i] == v ) { + return i; + } + } + return -1; +} + +SDAI_ptr +SDAI__set::retrieve( int index ) { + return operator[]( index ); +} + +SDAI_ptr & SDAI__set::operator[]( int index ) { + + Check( index ); + _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); + return _buf[index]; +} + +int +SDAI__set::Count() { + return _count; +} + +int +SDAI__set::is_empty() { + return _count; +} + +void +SDAI__set::Clear() { + _count = 0; +} diff --git a/src/cldai/sdaiSet.h b/src/cldai/sdaiSet.h new file mode 100644 index 000000000..0ce84a77c --- /dev/null +++ b/src/cldai/sdaiSet.h @@ -0,0 +1,38 @@ +#ifndef SDAISET_H +#define SDAISET_H 1 + +#include + +typedef void * SDAI_ptr; + +class SC_DAI_EXPORT SDAI__set { + public: + SDAI__set( int = 16 ); + ~SDAI__set(); + + SDAI_ptr retrieve( int index ); + int is_empty(); + + SDAI_ptr & operator[]( int index ); + + void Insert( SDAI_ptr, int index ); + void Append( SDAI_ptr ); + void Remove( int index ); + + int Index( SDAI_ptr ); + + void Clear(); + int Count(); + + private: + void Check( int index ); + private: + SDAI_ptr * _buf; + int _bufsize; + int _count; + + public: + +}; + +#endif diff --git a/src/clstepcore/sdai.h b/src/clstepcore/sdai.h index c47a8ad51..eaeada754 100644 --- a/src/clstepcore/sdai.h +++ b/src/clstepcore/sdai.h @@ -154,6 +154,8 @@ typedef char * SDAI_Time_stamp; typedef char * SDAI_Entity_name; typedef char * SDAI_Schema_name; +#include //A superclass for many of the *__set classes + #include #include From 40c3a1c33b362e7f2a0412a41ba3a0a121690b9e Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 15 Aug 2014 21:46:48 +0530 Subject: [PATCH 099/111] Made use of sdaiSet The classes in cldai which were chosen to inherit from sdaiSet were: SDAI_DAObject__set, SDAI_Entity_extent__set and SDAI_Model_contents__list. --- src/cldai/sdaiDaObject.cc | 96 +--------------------------- src/cldai/sdaiDaObject.h | 23 +------ src/cldai/sdaiEntity_extent_set.cc | 95 +-------------------------- src/cldai/sdaiEntity_extent_set.h | 20 +----- src/cldai/sdaiModel_contents_list.cc | 96 +--------------------------- src/cldai/sdaiModel_contents_list.h | 19 +----- 6 files changed, 9 insertions(+), 340 deletions(-) diff --git a/src/cldai/sdaiDaObject.cc b/src/cldai/sdaiDaObject.cc index 2f43ab284..7f0cc0a2a 100644 --- a/src/cldai/sdaiDaObject.cc +++ b/src/cldai/sdaiDaObject.cc @@ -78,83 +78,10 @@ SDAI_DAObject_SDAI::~SDAI_DAObject_SDAI() { /*****************************************************************************/ -SDAI_DAObject__set::SDAI_DAObject__set( int defaultSize ) { - _bufsize = defaultSize; - _buf = new SDAI_DAObject_ptr[_bufsize]; - _count = 0; +SDAI_DAObject__set::SDAI_DAObject__set( int defaultSize ) : SDAI__set( defaultSize ){ } SDAI_DAObject__set::~SDAI_DAObject__set() { - delete _buf; -} - -void SDAI_DAObject__set::Check( int index ) { - - SDAI_DAObject_ptr * newbuf; - - if( index >= _bufsize ) { - _bufsize = ( index + 1 ) * 2; - newbuf = new SDAI_DAObject_ptr[_bufsize]; - memmove( newbuf, _buf, _count * sizeof( SDAI_DAObject_ptr ) ); - delete _buf; - _buf = newbuf; - } -} - -void -SDAI_DAObject__set::Insert( SDAI_DAObject_ptr v, int index ) { - - SDAI_DAObject_ptr * spot; - index = ( index < 0 ) ? _count : index; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( SDAI_DAObject_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void SDAI_DAObject__set::Append( SDAI_DAObject_ptr v ) { - - int index = _count; - SDAI_DAObject_ptr * spot; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( SDAI_DAObject_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void SDAI_DAObject__set::Remove( int index ) { - - if( 0 <= index && index < _count ) { - --_count; - SDAI_DAObject_ptr * spot = &_buf[index]; - memmove( spot, spot + 1, ( _count - index )*sizeof( SDAI_DAObject_ptr ) ); - } -} - -int SDAI_DAObject__set::Index( SDAI_DAObject_ptr v ) { - - for( int i = 0; i < _count; ++i ) { - if( _buf[i] == v ) { - return i; - } - } - return -1; } SDAI_DAObject_ptr @@ -163,24 +90,5 @@ SDAI_DAObject__set::retrieve( int index ) { } SDAI_DAObject_ptr & SDAI_DAObject__set::operator[]( int index ) { - - Check( index ); -// _count = max(_count, index+1); - _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); - return _buf[index]; -} - -int -SDAI_DAObject__set::Count() { - return _count; -} - -int -SDAI_DAObject__set::is_empty() { - return _count; -} - -void -SDAI_DAObject__set::Clear() { - _count = 0; + return ( SDAI_DAObject_ptr & )SDAI__set::operator[]( index ); } diff --git a/src/cldai/sdaiDaObject.h b/src/cldai/sdaiDaObject.h index 6798ff1f1..1035d6286 100644 --- a/src/cldai/sdaiDaObject.h +++ b/src/cldai/sdaiDaObject.h @@ -489,34 +489,13 @@ class SC_DAI_EXPORT SDAI_DAObject_SDAI : public SDAI_DAObject { typedef SDAI_DAObject_SDAI * SDAI_DAObject_SDAI_ptr; typedef SDAI_DAObject_SDAI_ptr SDAI_DAObject_SDAI_var; -class SC_DAI_EXPORT SDAI_DAObject__set { +class SC_DAI_EXPORT SDAI_DAObject__set : public SDAI__set { public: SDAI_DAObject__set( int = 16 ); ~SDAI_DAObject__set(); SDAI_DAObject_ptr retrieve( int index ); - int is_empty(); - SDAI_DAObject_ptr & operator[]( int index ); - - void Insert( SDAI_DAObject_ptr, int index ); - void Append( SDAI_DAObject_ptr ); - void Remove( int index ); - - int Index( SDAI_DAObject_ptr ); - - void Clear(); - int Count(); - - private: - void Check( int index ); - private: - SDAI_DAObject_ptr * _buf; - int _bufsize; - int _count; - - public: - }; typedef SDAI_DAObject__set * SDAI_DAObject__set_ptr; diff --git a/src/cldai/sdaiEntity_extent_set.cc b/src/cldai/sdaiEntity_extent_set.cc index af3658222..885b00b32 100644 --- a/src/cldai/sdaiEntity_extent_set.cc +++ b/src/cldai/sdaiEntity_extent_set.cc @@ -44,83 +44,10 @@ extern "C" /*****************************************************************************/ -SDAI_Entity_extent__set::SDAI_Entity_extent__set( int defaultSize ) { - _bufsize = defaultSize; - _buf = new SDAI_Entity_extent_ptr[_bufsize]; - _count = 0; +SDAI_Entity_extent__set::SDAI_Entity_extent__set( int defaultSize ) : SDAI__set( defaultSize ) { } SDAI_Entity_extent__set::~SDAI_Entity_extent__set() { - delete _buf; -} - -void SDAI_Entity_extent__set::Check( int index ) { - - SDAI_Entity_extent_ptr * newbuf; - - if( index >= _bufsize ) { - _bufsize = ( index + 1 ) * 2; - newbuf = new SDAI_Entity_extent_ptr[_bufsize]; - memmove( newbuf, _buf, _count * sizeof( SDAI_Entity_extent_ptr ) ); - delete _buf; - _buf = newbuf; - } -} - -void -SDAI_Entity_extent__set::Insert( SDAI_Entity_extent_ptr v, int index ) { - - SDAI_Entity_extent_ptr * spot; - index = ( index < 0 ) ? _count : index; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( SDAI_Entity_extent_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void SDAI_Entity_extent__set::Append( SDAI_Entity_extent_ptr v ) { - - int index = _count; - SDAI_Entity_extent_ptr * spot; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( SDAI_Entity_extent_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void SDAI_Entity_extent__set::Remove( int index ) { - - if( 0 <= index && index < _count ) { - --_count; - SDAI_Entity_extent_ptr * spot = &_buf[index]; - memmove( spot, spot + 1, ( _count - index )*sizeof( SDAI_Entity_extent_ptr ) ); - } -} - -int SDAI_Entity_extent__set::Index( SDAI_Entity_extent_ptr v ) { - - for( int i = 0; i < _count; ++i ) { - if( _buf[i] == v ) { - return i; - } - } - return -1; } SDAI_Entity_extent_ptr @@ -129,25 +56,7 @@ SDAI_Entity_extent__set::retrieve( int index ) { } SDAI_Entity_extent_ptr & SDAI_Entity_extent__set::operator[]( int index ) { - Check( index ); -// _count = max(_count, index+1); - _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); - return _buf[index]; -} - -int -SDAI_Entity_extent__set::Count() { - return _count; -} - -int -SDAI_Entity_extent__set::is_empty() { - return _count; -} - -void -SDAI_Entity_extent__set::Clear() { - _count = 0; + return ( SDAI_Entity_extent_ptr & )SDAI__set::operator[]( index ); } /*****************************************************************************/ diff --git a/src/cldai/sdaiEntity_extent_set.h b/src/cldai/sdaiEntity_extent_set.h index b6b893078..3f8bccbc1 100644 --- a/src/cldai/sdaiEntity_extent_set.h +++ b/src/cldai/sdaiEntity_extent_set.h @@ -37,32 +37,14 @@ //#include */ -class SC_DAI_EXPORT SDAI_Entity_extent__set { +class SC_DAI_EXPORT SDAI_Entity_extent__set : public SDAI__set { public: SDAI_Entity_extent__set( int = 16 ); ~SDAI_Entity_extent__set(); SDAI_Entity_extent_ptr retrieve( int index ); - int is_empty(); - SDAI_Entity_extent_ptr & operator[]( int index ); - - void Insert( SDAI_Entity_extent_ptr, int index ); - void Append( SDAI_Entity_extent_ptr ); - void Remove( int index ); - int Index( SDAI_Entity_extent_ptr ); - - void Clear(); - int Count(); - - private: - void Check( int index ); - private: - SDAI_Entity_extent_ptr * _buf; - int _bufsize; - int _count; - }; typedef SDAI_Entity_extent__set * SDAI_Entity_extent__set_ptr; diff --git a/src/cldai/sdaiModel_contents_list.cc b/src/cldai/sdaiModel_contents_list.cc index 8f6440e8e..d3535139d 100644 --- a/src/cldai/sdaiModel_contents_list.cc +++ b/src/cldai/sdaiModel_contents_list.cc @@ -36,83 +36,10 @@ extern "C" /*****************************************************************************/ -SDAI_Model_contents__list::SDAI_Model_contents__list( int defaultSize ) { - _bufsize = defaultSize; - _buf = new SDAI_Model_contents_ptr[_bufsize]; - _count = 0; +SDAI_Model_contents__list::SDAI_Model_contents__list( int defaultSize ) : SDAI__set( defaultSize ){ } SDAI_Model_contents__list::~SDAI_Model_contents__list() { - delete _buf; -} - -void SDAI_Model_contents__list::Check( int index ) { - - SDAI_Model_contents_ptr * newbuf; - - if( index >= _bufsize ) { - _bufsize = ( index + 1 ) * 2; - newbuf = new SDAI_Model_contents_ptr[_bufsize]; - memmove( newbuf, _buf, _count * sizeof( SDAI_Model_contents_ptr ) ); - delete _buf; - _buf = newbuf; - } -} - -void -SDAI_Model_contents__list::Insert( SDAI_Model_contents_ptr v, int index ) { - - SDAI_Model_contents_ptr * spot; - index = ( index < 0 ) ? _count : index; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( SDAI_Model_contents_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void SDAI_Model_contents__list::Append( SDAI_Model_contents_ptr v ) { - - int index = _count; - SDAI_Model_contents_ptr * spot; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( SDAI_Model_contents_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; -} - -void SDAI_Model_contents__list::Remove( int index ) { - - if( 0 <= index && index < _count ) { - --_count; - SDAI_Model_contents_ptr * spot = &_buf[index]; - memmove( spot, spot + 1, ( _count - index )*sizeof( SDAI_Model_contents_ptr ) ); - } -} - -int SDAI_Model_contents__list::Index( SDAI_Model_contents_ptr v ) { - - for( int i = 0; i < _count; ++i ) { - if( _buf[i] == v ) { - return i; - } - } - return -1; } SDAI_Model_contents_ptr @@ -122,25 +49,6 @@ SDAI_Model_contents__list::retrieve( int index ) { SDAI_Model_contents_ptr & SDAI_Model_contents__list::operator[]( int index ) { - - Check( index ); -// _count = max(_count, index+1); - _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); - return _buf[index]; -} - -int -SDAI_Model_contents__list::Count() { - return _count; -} - -int -SDAI_Model_contents__list::is_empty() { - return _count; -} - -void -SDAI_Model_contents__list::Clear() { - _count = 0; + return ( SDAI_Model_contents_ptr & )SDAI__set::operator[]( index ); } diff --git a/src/cldai/sdaiModel_contents_list.h b/src/cldai/sdaiModel_contents_list.h index 47e98a072..e2a4f8db2 100644 --- a/src/cldai/sdaiModel_contents_list.h +++ b/src/cldai/sdaiModel_contents_list.h @@ -3,30 +3,13 @@ #include -class SC_DAI_EXPORT SDAI_Model_contents__list { +class SC_DAI_EXPORT SDAI_Model_contents__list : public SDAI__set { public: SDAI_Model_contents__list( int = 16 ); ~SDAI_Model_contents__list(); SDAI_Model_contents_ptr retrieve( int index ); - int is_empty(); - SDAI_Model_contents_ptr & operator[]( int index ); - - void Insert( SDAI_Model_contents_ptr, int index ); - void Append( SDAI_Model_contents_ptr ); - void Remove( int index ); - int Index( SDAI_Model_contents_ptr ); - - void Clear(); - int Count(); - - private: - void Check( int index ); - private: - SDAI_Model_contents_ptr * _buf; - int _bufsize; - int _count; }; typedef SDAI_Model_contents__list * From 42d71188fcff0590ce406969edb1ad0379ed84ed Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 15 Aug 2014 22:20:09 +0530 Subject: [PATCH 100/111] Made SDAI__set thread safe This was done by introducing a mutex in the SDAI__set class. --- src/cldai/sdaiSet.cc | 26 +++++++++++++++++++++++--- src/cldai/sdaiSet.h | 7 +++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/cldai/sdaiSet.cc b/src/cldai/sdaiSet.cc index 7d467ca5d..14a33e34e 100644 --- a/src/cldai/sdaiSet.cc +++ b/src/cldai/sdaiSet.cc @@ -17,13 +17,18 @@ SDAI__set::SDAI__set( int defaultSize ) { _bufsize = defaultSize; _buf = new SDAI_ptr[_bufsize]; _count = 0; + mtxP = new sc_mutex(); } SDAI__set::~SDAI__set() { delete _buf; + delete mtxP; } void SDAI__set::Check( int index ) { + // No locking as it is a private function. + // i.e. The caller will have to take the responsibilty. + SDAI_ptr * newbuf; if( index >= _bufsize ) { @@ -37,6 +42,7 @@ void SDAI__set::Check( int index ) { void SDAI__set::Insert( SDAI_ptr v, int index ) { + mtxP->lock(); SDAI_ptr * spot; index = ( index < 0 ) ? _count : index; @@ -52,9 +58,11 @@ SDAI__set::Insert( SDAI_ptr v, int index ) { } *spot = v; ++_count; + mtxP->unlock(); } void SDAI__set::Append( SDAI_ptr v ) { + mtxP->lock(); int index = _count; SDAI_ptr * spot; @@ -70,25 +78,32 @@ void SDAI__set::Append( SDAI_ptr v ) { } *spot = v; ++_count; + mtxP->unlock(); } void SDAI__set::Remove( int index ) { + mtxP->lock(); if( 0 <= index && index < _count ) { --_count; SDAI_ptr * spot = &_buf[index]; memmove( spot, spot + 1, ( _count - index )*sizeof( SDAI_ptr ) ); } + mtxP->unlock(); } int SDAI__set::Index( SDAI_ptr v ) { + mtxP->lock(); + int index = -1; for( int i = 0; i < _count; ++i ) { if( _buf[i] == v ) { - return i; + index = i; + break; } } - return -1; + mtxP->unlock(); + return index; } SDAI_ptr @@ -97,10 +112,13 @@ SDAI__set::retrieve( int index ) { } SDAI_ptr & SDAI__set::operator[]( int index ) { + mtxP->lock(); Check( index ); _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); - return _buf[index]; + SDAI_ptr & sp = _buf[index]; + mtxP->unlock(); + return sp; } int @@ -115,5 +133,7 @@ SDAI__set::is_empty() { void SDAI__set::Clear() { + mtxP->lock(); _count = 0; + mtxP->unlock(); } diff --git a/src/cldai/sdaiSet.h b/src/cldai/sdaiSet.h index 0ce84a77c..3905b24bf 100644 --- a/src/cldai/sdaiSet.h +++ b/src/cldai/sdaiSet.h @@ -1,6 +1,7 @@ #ifndef SDAISET_H #define SDAISET_H 1 +#include #include typedef void * SDAI_ptr; @@ -30,6 +31,12 @@ class SC_DAI_EXPORT SDAI__set { SDAI_ptr * _buf; int _bufsize; int _count; + sc_mutex * mtxP; + // The above function is declared as a pointer to prevent + // 'use of deleted function' compilation error as the + // assignment operator '=' is being in the function + // 'SDAI_Entity_extent::owned_by_' for a subclass of + // SDAI__set: 'SDAI_Model_contents__list' public: From f26cb0457dd71f7fb61415d1063dd15ed531c16b Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 15 Aug 2014 22:56:49 +0530 Subject: [PATCH 101/111] Added SDAI__set::Remove( SDAI_ptr ) function The semantics of this function would be similar to SDAI__set::Remove( SDAI__set::Index( SDAI_ptr ) ). The only difference would be that in the new function both the operations are done under a single lock. Wherever the old Remove( Index( SDAI_ptr ) ) code snippet was found, it was replaced by the new Remove( SDAI_ptr ) function. --- src/cldai/sdaiEntity_extent.cc | 2 +- src/cldai/sdaiModel_contents.cc | 2 +- src/cldai/sdaiSet.cc | 14 ++++++++++++++ src/cldai/sdaiSet.h | 1 + 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/cldai/sdaiEntity_extent.cc b/src/cldai/sdaiEntity_extent.cc index f98d5d279..e6b480f3b 100644 --- a/src/cldai/sdaiEntity_extent.cc +++ b/src/cldai/sdaiEntity_extent.cc @@ -114,7 +114,7 @@ SDAI_Entity_extent::AddInstance( const SDAI_DAObject_ptr & appInst ) { void SDAI_Entity_extent::RemoveInstance( const SDAI_DAObject_ptr & appInst ) { - _instances.Remove( _instances.Index( appInst ) ); + _instances.Remove( appInst ); } ///////// END_ENTITY SDAI_Entity_extent diff --git a/src/cldai/sdaiModel_contents.cc b/src/cldai/sdaiModel_contents.cc index 67140916a..6552a57da 100644 --- a/src/cldai/sdaiModel_contents.cc +++ b/src/cldai/sdaiModel_contents.cc @@ -73,7 +73,7 @@ void SDAI_Model_contents::AddInstance( const SDAI_DAObject_SDAI_ptr & appInst ) } void SDAI_Model_contents::RemoveInstance( SDAI_DAObject_SDAI_ptr & appInst ) { - _instances.contents_()->Remove( _instances.contents_()->Index( appInst ) ); + _instances.contents_()->Remove( appInst ); } diff --git a/src/cldai/sdaiSet.cc b/src/cldai/sdaiSet.cc index 14a33e34e..784c927fa 100644 --- a/src/cldai/sdaiSet.cc +++ b/src/cldai/sdaiSet.cc @@ -92,6 +92,20 @@ void SDAI__set::Remove( int index ) { mtxP->unlock(); } +// First find the index of v and then remove v. +void SDAI__set::Remove( SDAI_ptr v ) { + mtxP->lock(); + + for( int i = 0; i < _count; ++i ) { + if( _buf[i] == v ) { + --_count; + SDAI_ptr * spot = &_buf[i]; + memmove( spot, spot + 1, ( _count - i )*sizeof( SDAI_ptr ) ); + } + } + mtxP->unlock(); +} + int SDAI__set::Index( SDAI_ptr v ) { mtxP->lock(); int index = -1; diff --git a/src/cldai/sdaiSet.h b/src/cldai/sdaiSet.h index 3905b24bf..66e8b0b6c 100644 --- a/src/cldai/sdaiSet.h +++ b/src/cldai/sdaiSet.h @@ -19,6 +19,7 @@ class SC_DAI_EXPORT SDAI__set { void Insert( SDAI_ptr, int index ); void Append( SDAI_ptr ); void Remove( int index ); + void Remove( SDAI_ptr ); int Index( SDAI_ptr ); From 03981d27e003904583688cf694523b92f82917e3 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Fri, 15 Aug 2014 23:25:32 +0530 Subject: [PATCH 102/111] One more subclass of SDAI__set Adding the Remove( SDAI_ptr ) API to SDAI__set made SDAI_Application_instance__set a candidate for inheriting common logic from SDAI__set. Note: This class was already made thread safe in one of the previous commits. This commit only removes the now apparent duplicate code. --- src/cldai/sdaiApplication_instance_set.cc | 109 +--------------------- src/cldai/sdaiApplication_instance_set.h | 19 +--- 2 files changed, 3 insertions(+), 125 deletions(-) diff --git a/src/cldai/sdaiApplication_instance_set.cc b/src/cldai/sdaiApplication_instance_set.cc index 32bcd2c04..91110cf1f 100644 --- a/src/cldai/sdaiApplication_instance_set.cc +++ b/src/cldai/sdaiApplication_instance_set.cc @@ -41,118 +41,13 @@ extern "C" /*****************************************************************************/ -SDAI_Application_instance__set::SDAI_Application_instance__set( int defaultSize ) { - _bufsize = defaultSize; - _buf = new SDAI_Application_instance_ptr[_bufsize]; - _count = 0; +SDAI_Application_instance__set::SDAI_Application_instance__set( int defaultSize ) : SDAI__set( defaultSize ) { } SDAI_Application_instance__set::~SDAI_Application_instance__set() { - delete _buf; -} - -void SDAI_Application_instance__set::Check( int index ) { - SDAI_Application_instance_ptr * newbuf; - - mtx.lock(); - if( index >= _bufsize ) { - _bufsize = ( index + 1 ) * 2; - newbuf = new SDAI_Application_instance_ptr[_bufsize]; - memmove( newbuf, _buf, _count * sizeof( SDAI_Application_instance_ptr ) ); - delete _buf; - _buf = newbuf; - } - mtx.unlock(); -} - -void SDAI_Application_instance__set::Insert( SDAI_Application_instance_ptr v, int index ) { - SDAI_Application_instance_ptr * spot; - mtx.lock(); - index = ( index < 0 ) ? _count : index; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( SDAI_Application_instance_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; - mtx.unlock(); -} - -void SDAI_Application_instance__set::Append( SDAI_Application_instance_ptr v ) { - mtx.lock(); - int index = _count; - SDAI_Application_instance_ptr * spot; - - if( index < _count ) { - Check( _count + 1 ); - spot = &_buf[index]; - memmove( spot + 1, spot, ( _count - index )*sizeof( SDAI_Application_instance_ptr ) ); - - } else { - Check( index ); - spot = &_buf[index]; - } - *spot = v; - ++_count; - mtx.unlock(); -} - -void SDAI_Application_instance__set::Remove( int index ) { - mtx.lock(); - if( 0 <= index && index < _count ) { - --_count; - SDAI_Application_instance_ptr * spot = &_buf[index]; - memmove( spot, spot + 1, ( _count - index )*sizeof( SDAI_Application_instance_ptr ) ); - } - mtx.unlock(); -} - -void SDAI_Application_instance__set::Remove( SDAI_Application_instance_ptr a ) { - mtx.lock(); - int index = Index( a ); - if( !( index < 0 ) ) { - Remove( index ); - } - mtx.unlock(); -} - -int SDAI_Application_instance__set::Index( SDAI_Application_instance_ptr v ) { - int retval = -1; - mtx.lock(); - for( int i = 0; i < _count; ++i ) { - if( _buf[i] == v ) { - retval = i; - break; - } - } - mtx.unlock(); - return retval; } SDAI_Application_instance_ptr & SDAI_Application_instance__set::operator[]( int index ) { - mtx.lock(); - Check( index ); -// _count = max(_count, index+1); - _count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) ); - SDAI_Application_instance_ptr & saip = _buf[index]; - mtx.unlock(); - return saip; + return ( SDAI_Application_instance_ptr & )SDAI__set::operator[]( index ); } -int -SDAI_Application_instance__set::Count() { - return _count; -} - -void -SDAI_Application_instance__set::Clear() { - mtx.lock(); - _count = 0; - mtx.unlock(); -} diff --git a/src/cldai/sdaiApplication_instance_set.h b/src/cldai/sdaiApplication_instance_set.h index 567afaa7e..42006a654 100644 --- a/src/cldai/sdaiApplication_instance_set.h +++ b/src/cldai/sdaiApplication_instance_set.h @@ -31,35 +31,18 @@ #define SDAI_APPLICATION_INSTANCE_SET_h #include -#include class SDAI_Application_instance; class SDAI_Application_instance__set; typedef SDAI_Application_instance__set * SDAI_Application_instance__set_ptr; typedef SDAI_Application_instance__set_ptr SDAI_Application_instance__set_var; -class SC_DAI_EXPORT SDAI_Application_instance__set { +class SC_DAI_EXPORT SDAI_Application_instance__set : public SDAI__set { public: SDAI_Application_instance__set( int = 16 ); ~SDAI_Application_instance__set(); SDAI_Application_instance *& operator[]( int index ); - void Insert( SDAI_Application_instance *, int index ); - void Append( SDAI_Application_instance * ); - void Remove( int index ); - void Remove( SDAI_Application_instance * ); - int Index( SDAI_Application_instance * ); - - int Count(); - void Clear(); - private: - void Check( int index ); - private: - SDAI_Application_instance ** _buf; - int _bufsize; - int _count; - sc_recursive_mutex mtx; // A recursive mutex was needed as there is an - // interdependency between various public APIs }; #endif From 85a248a50aba3cdad0962fdd246d8a2180e38abf Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 18 Aug 2014 11:57:17 +0530 Subject: [PATCH 103/111] Added NO_REGISTRY Macro to lazy_thread_safety_test lazy_thread_safety_test had 2 checks which were schema dependent. These checks are now wrapped in NO_REGISTRY macro. --- src/cllazyfile/CMakeLists.txt | 4 ++-- src/cllazyfile/lazy_thread_safety_test.cc | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/cllazyfile/CMakeLists.txt b/src/cllazyfile/CMakeLists.txt index 6260f95dd..432a68ad7 100644 --- a/src/cllazyfile/CMakeLists.txt +++ b/src/cllazyfile/CMakeLists.txt @@ -45,8 +45,8 @@ if(HAVE_STD_THREAD) ) SC_ADDEXEC(lazy_thread_safety_test "lazy_thread_safety_test.cc" "steplazyfile;stepeditor" ) - set_target_properties(lazy_thread_safety_test PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD") - target_link_libraries(lazy_thread_safety_test sdai_cd209 "pthread" ) + set_target_properties(lazy_thread_safety_test PROPERTIES COMPILE_FLAGS "-pthread -std=c++0x -DHAVE_STD_THREAD -DNO_REGISTRY") + target_link_libraries(lazy_thread_safety_test sdai_cd209 "pthread" ) #sdai_cd209 in causes schema dependency endif(HAVE_STD_THREAD) SC_ADDEXEC(lazy_test "lazy_test.cc" "steplazyfile;stepeditor" ) diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index ba05c44a6..8cb80821d 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -3,7 +3,11 @@ #include "SdaiSchemaInit.h" #include "instMgrHelper.h" -#include "schema.h" +// Registry will be needed for checkLazyLoadingSafety & checkLazyLoadingSafetyWithAdapter checks. +#ifndef NO_REGISTRY +# include "schema.h" +#endif //NO_REGISTRY + #include #ifdef HAVE_STD_THREAD @@ -258,6 +262,7 @@ bool compareLoadedInstances( instanceRefs * toBeLoadedOnT1, instancesLoaded_t * return true; } +#ifndef NO_REGISTRY //checks thread safety of loadInstance. (Also of instMgrAdapter if useAdapter is TRUE) void checkLazyLoadingSafety( char * fileName, bool useAdapter=false ) { @@ -321,6 +326,7 @@ void checkLazyLoadingSafety( char * fileName, bool useAdapter=false ) { void checkLazyLoadingSafetyWithAdapter( char * fileName ) { checkLazyLoadingSafety( fileName, true ); } +#endif //NO_REGISTRY /// enum elements represent the status used checking thread safety of openFile enum lazyInstMgrStatus { @@ -562,8 +568,10 @@ int main( int argc, char ** argv ) { checkTypeInstancesSafety( argv[1] ); +#ifndef NO_REGISTRY checkLazyLoadingSafety( argv[1] ); checkLazyLoadingSafetyWithAdapter( argv[1] ); +#endif //NO_REGISTRY checkOpenFileSafety( argv[1], argv[2] ); } From 2aa936b601bcea0579d4e8f220f8c07bed0c9990 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 18 Aug 2014 14:08:18 +0530 Subject: [PATCH 104/111] Corrected a coment sc_mutex.h --- src/clutils/sc_mutex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clutils/sc_mutex.h b/src/clutils/sc_mutex.h index 90a70be76..f2fb72a1c 100644 --- a/src/clutils/sc_mutex.h +++ b/src/clutils/sc_mutex.h @@ -7,7 +7,7 @@ #endif //HAVE_STD_THREAD /* This class is a wrapper to std::mutex. - It does nothing if HAVE_STD_MUTEX is not defined. + It does nothing if HAVE_STD_THREAD is not defined. */ class sc_mutex { protected: From 54457e567a35cf64a68d6df6434fe3f59877ff71 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 18 Aug 2014 16:56:06 +0530 Subject: [PATCH 105/111] Utilized sc_mutex in cllazyfile Earlier std::mutex was being used. It was replaces with sc_mutex which acts like a wrapper to std::mutex --- src/cllazyfile/instMgrHelper.h | 4 ++-- src/cllazyfile/lazyInstMgr.h | 27 +++++---------------------- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/src/cllazyfile/instMgrHelper.h b/src/cllazyfile/instMgrHelper.h index 05e86e8dc..c25f6507d 100644 --- a/src/cllazyfile/instMgrHelper.h +++ b/src/cllazyfile/instMgrHelper.h @@ -7,9 +7,9 @@ #ifdef HAVE_STD_THREAD # include -# include #endif //HAVE_STD_THREAD +#include /** * \file instMgrHelper.h helper classes for the lazyInstMgr. Allows use of SDAI_Application_instance class @@ -64,7 +64,7 @@ class instMgrAdapter: public InstMgr { //map between threadID and the thread's local copy of mgrNodeHelper. Each thread has zero or one copy //of mgrNodeHelper assigned to it. This _map holds the pointer to that mgrNodeHelper. idNodeMap_t _map; - std::mutex _mapMtx; + sc_mutex _mapMtx; #endif //HAVE_STD_THREAD public: diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index 07d32ae12..d052e6556 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -9,9 +9,7 @@ #include "lazyFileReader.h" #include "lazyTypes.h" -#ifdef HAVE_STD_THREAD -# include -#endif //HAVE_STD_THREAD +#include "sc_mutex.h" #include "Registry.h" #include "sc_memmgr.h" @@ -66,13 +64,8 @@ class lazyInstMgr { instMgrAdapter * _ima; -#ifdef HAVE_STD_THREAD /** mutexes for mutual exclusion */ - std::mutex fwdRefsMtx, revRefsMtx, instanceTypesMtx, loadInstanceMtx, instanceStreamPosMtx, dataSectionsMtx, filesMtx; -#else - /** Dummy variables **/ - int fwdRefsMtx, revRefsMtx, instanceTypesMtx, loadInstanceMtx, instanceStreamPosMtx, dataSectionsMtx, filesMtx; -#endif //HAVE_STD_THREAD + sc_mutex fwdRefsMtx, revRefsMtx, instanceTypesMtx, loadInstanceMtx, instanceStreamPosMtx, dataSectionsMtx, filesMtx; public: lazyInstMgr(); @@ -192,25 +185,15 @@ class lazyInstMgr { /// Thread safe counterpart of instanceDependencies( instanceID ) instanceSet * instanceDependenciesSafely( instanceID id ); +#endif //HAVE_STD_THREAD - void mtxLock( std::mutex &mtx ) { + void mtxLock( sc_mutex &mtx ) { mtx.lock(); } - void mtxUnlock( std::mutex &mtx ) { + void mtxUnlock( sc_mutex &mtx ) { mtx.unlock(); } -#else - /// dummy counterpart of mtxLock - void mtxLock( int dummy ) { - ( void )dummy; - } - - /// dummy counterpart of mtxUnlock - void mtxUnlock( int dummy ) { - ( void )dummy; - } -#endif //HAVE_STD_THREAD /// unloads all instances. (For testing purpose, not thread safe) void unloadAllInstances() { From bac1435936926c2b8cf4ba019ac13bbe12120b36 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 18 Aug 2014 17:00:01 +0530 Subject: [PATCH 106/111] Added sc_thread.h in clutils This acts like a wrapper to some of the thread functionalities (like get_id()) which is being used in stepcode. If the compiler does not supports thread functionalities then this class provides dummy types and functionalities. --- src/clutils/CMakeLists.txt | 1 + src/clutils/sc_thread.h | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/clutils/sc_thread.h diff --git a/src/clutils/CMakeLists.txt b/src/clutils/CMakeLists.txt index c020525cc..4a00585a0 100644 --- a/src/clutils/CMakeLists.txt +++ b/src/clutils/CMakeLists.txt @@ -18,6 +18,7 @@ set(SC_CLUTILS_HDRS sc_hash.h Str.h sc_mutex.h + sc_thread.h ) include_directories( diff --git a/src/clutils/sc_thread.h b/src/clutils/sc_thread.h new file mode 100644 index 000000000..45306e07c --- /dev/null +++ b/src/clutils/sc_thread.h @@ -0,0 +1,24 @@ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#ifdef HAVE_STD_THREAD +# include +#endif //HAVE_STD_THREAD + +#ifdef HAVE_STD_THREAD + typedef std::thread::id thread_id_t; + + static thread_id_t sc_getthread_id() { + return std::this_thread::get_id(); + } + +#else //dummy equivalent + typedef int thread_id_t; + + static thread_id_t sc_getthread_id() { + return 0; + } + +#endif //HAVE_STD_THREAD + +#endif //SC_THREAD_H From f0fdfd706f7e648f5739bdfbe8353b9de2856e6d Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 18 Aug 2014 17:19:09 +0530 Subject: [PATCH 107/111] Added class sc_thread in sc_thread.h --- src/clutils/sc_thread.h | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/clutils/sc_thread.h b/src/clutils/sc_thread.h index 45306e07c..0968b6725 100644 --- a/src/clutils/sc_thread.h +++ b/src/clutils/sc_thread.h @@ -7,18 +7,28 @@ #ifdef HAVE_STD_THREAD typedef std::thread::id thread_id_t; - - static thread_id_t sc_getthread_id() { - return std::this_thread::get_id(); - } - #else //dummy equivalent typedef int thread_id_t; +#endif //HAVE_STD_THREAD - static thread_id_t sc_getthread_id() { - return 0; - } +/* + This class is a wrapper to std::thread. + It will have wrapper functions of different functionalities + provided by the std::thread class. + It does nothing if HAVE_STD_THREAD is not defined. +*/ +class sc_thread { + public: + static thread_id_t getthread_id() { + +#ifdef HAVE_STD_THREAD + return std::this_thread::get_id(); +#else + return 0; #endif //HAVE_STD_THREAD + } +}; + #endif //SC_THREAD_H From e73ad4df1c716d2cc883cd271d02702ad35a7ba1 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 18 Aug 2014 17:28:30 +0530 Subject: [PATCH 108/111] instMgrAdapter took dependency on sc_thread lazyTypes.h was also modified. HAVE_STD_THREAD macros were removed from cllazyfile library *.cc and *.h since classes sc_thread and sc_mutex internally handles the macros. --- src/cllazyfile/instMgrHelper.h | 18 ++---------------- src/cllazyfile/lazyInstMgr.cc | 4 ---- src/cllazyfile/lazyInstMgr.h | 2 -- src/cllazyfile/lazyTypes.h | 10 +++------- 4 files changed, 5 insertions(+), 29 deletions(-) diff --git a/src/cllazyfile/instMgrHelper.h b/src/cllazyfile/instMgrHelper.h index c25f6507d..1855611ac 100644 --- a/src/cllazyfile/instMgrHelper.h +++ b/src/cllazyfile/instMgrHelper.h @@ -5,11 +5,8 @@ #include #include -#ifdef HAVE_STD_THREAD -# include -#endif //HAVE_STD_THREAD - #include +#include /** * \file instMgrHelper.h helper classes for the lazyInstMgr. Allows use of SDAI_Application_instance class @@ -38,12 +35,10 @@ class mgrNodeHelper: protected MgrNode { return _lim->loadInstance( _id ); } -#ifdef HAVE_STD_THREAD ///Thread safe counterpart of GetSTEPentity() inline SDAI_Application_instance * GetSTEPentitySafely() { return _lim->loadInstanceSafely( _id ); } -#endif //HAVE_STD_THREAD }; @@ -59,23 +54,18 @@ class instMgrAdapter: public InstMgr { protected: mgrNodeHelper _mn; //Used in single threaded operations -#ifdef HAVE_STD_THREAD lazyInstMgr * _lim; //Used in multi threaded operations //map between threadID and the thread's local copy of mgrNodeHelper. Each thread has zero or one copy //of mgrNodeHelper assigned to it. This _map holds the pointer to that mgrNodeHelper. idNodeMap_t _map; sc_mutex _mapMtx; -#endif //HAVE_STD_THREAD public: instMgrAdapter( lazyInstMgr * lim ): InstMgr( 0 ), _mn( lim ) { -#ifdef HAVE_STD_THREAD _lim = lim; _map.clear(); -#endif //HAVE_STD_THREAD } -#ifdef HAVE_STD_THREAD //In case of multiple threads an explicit destructor is needed to free each threads mgrNodeHelper copy ~instMgrAdapter() { if( _map.empty() ) { @@ -86,19 +76,16 @@ class instMgrAdapter: public InstMgr { delete it->second; } } -#endif //HAVE_STD_THREAD inline mgrNodeHelper * FindFileId( int fileId ) { _mn.setInstance( fileId ); return &_mn; } - -#ifdef HAVE_STD_THREAD ///Thread-safe counterpart of FindFileId( fileId ). It protects the state of mgrNodeHelper. inline mgrNodeHelper * FindFileIdSafely( int fileId ) { mgrNodeHelper * _myMN; - std::thread::id tid = std::this_thread::get_id(); + thread_id_t tid = sc_thread::getthread_id(); _mapMtx.lock(); idNodeMap_t::iterator it = _map.find( tid ); @@ -117,7 +104,6 @@ class instMgrAdapter: public InstMgr { _myMN->setInstance( fileId ); return _myMN; } -#endif //HAVE_STD_THREAD }; diff --git a/src/cllazyfile/lazyInstMgr.cc b/src/cllazyfile/lazyInstMgr.cc index 367548090..96c4846f2 100644 --- a/src/cllazyfile/lazyInstMgr.cc +++ b/src/cllazyfile/lazyInstMgr.cc @@ -206,8 +206,6 @@ instanceSet * lazyInstMgr::instanceDependencies( instanceID id ) { return instanceDependenciesHelper( id, getFwdRefs() ); } -#ifdef HAVE_STD_THREAD - void lazyInstMgr::openFileSafely( std::string fname ) { filesMtx.lock(); size_t size = _files.size(); @@ -275,5 +273,3 @@ instanceSet * lazyInstMgr::instanceDependenciesSafely( instanceID id ) { return instanceDependenciesHelper( id, getFwdRefsSafely() ); } -#endif //HAVE_STD_THREAD - diff --git a/src/cllazyfile/lazyInstMgr.h b/src/cllazyfile/lazyInstMgr.h index d052e6556..3729a0a67 100644 --- a/src/cllazyfile/lazyInstMgr.h +++ b/src/cllazyfile/lazyInstMgr.h @@ -164,7 +164,6 @@ class lazyInstMgr { instanceSet * instanceDependencies( instanceID id ); instanceSet * instanceDependenciesHelper( instanceID id, instanceRefs_t * _fwdRefs ); -#ifdef HAVE_STD_THREAD /// thread safe counterpart of openFile(); void openFileSafely( std::string fname ); @@ -185,7 +184,6 @@ class lazyInstMgr { /// Thread safe counterpart of instanceDependencies( instanceID ) instanceSet * instanceDependenciesSafely( instanceID id ); -#endif //HAVE_STD_THREAD void mtxLock( sc_mutex &mtx ) { mtx.lock(); diff --git a/src/cllazyfile/lazyTypes.h b/src/cllazyfile/lazyTypes.h index c62dae304..d69840c1b 100644 --- a/src/cllazyfile/lazyTypes.h +++ b/src/cllazyfile/lazyTypes.h @@ -7,9 +7,7 @@ #include #include -#ifdef HAVE_STD_THREAD -# include -#endif //HAVE_STD_THREAD +# include #include "judyLArray.h" #include "judySArray.h" @@ -85,13 +83,11 @@ typedef std::vector< lazyDataSectionReader * > dataSectionReaderVec_t; // files typedef std::vector< lazyFileReader * > lazyFileReaderVec_t; -#ifdef HAVE_STD_THREAD //map thread id to mgrNodeHelper. Each thread will have only one mgrNodeHelper value. -typedef std::map< std::thread::id, mgrNodeHelper * > idNodeMap_t; +typedef std::map< thread_id_t, mgrNodeHelper * > idNodeMap_t; //thread id - mgrNodeHelper pointer pair to be used while using the above map -typedef std::pair< std::thread::id, mgrNodeHelper * > idNodePair_t; -#endif //HAVE_STD_THREAD +typedef std::pair< thread_id_t, mgrNodeHelper * > idNodePair_t; // type for performing actions on multiple instances // NOTE not useful? typedef std::vector< lazyInstance > lazyInstanceVec_t; From 1265e0c11067553694b7ce33f39d99a2b2c76e81 Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Mon, 18 Aug 2014 17:45:31 +0530 Subject: [PATCH 109/111] Added exit(success/fail) in thread-safety test --- src/cllazyfile/lazy_thread_safety_test.cc | 55 ++++++++----- src/clstepcore/InstMgr_thread_safety_test.cc | 34 +++++--- src/clstepcore/Registry_thread_safety_test.cc | 78 +++++++++++-------- 3 files changed, 104 insertions(+), 63 deletions(-) diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index 8cb80821d..cb7087beb 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -70,7 +70,7 @@ void iterateOverRefs ( lazyInstMgr *mgr, instanceRefs &realRefs, bool forward, b } /// Checks the thread safety of _fwdRefs (_revRefs) when the forward value provided to it is true (false). -void checkRefsSafety( char * fileName, bool forward ) { +bool checkRefsSafety( char * fileName, bool forward ) { instanceRefs realRefs; lazyInstMgr * mgr = new lazyInstMgr; mgr->openFile( fileName ); @@ -90,7 +90,8 @@ void checkRefsSafety( char * fileName, bool forward ) { first.join(); second.join(); - if( success[0] && success[1] ) { + bool pass = ( success[0] && success[1] ); + if( pass ) { std::cout << "..PASS!" << std::endl; } else { std::cout << "...FAIL!" << std::endl; @@ -106,16 +107,17 @@ void checkRefsSafety( char * fileName, bool forward ) { std::cout << std::endl; delete mgr; + return pass; } /// Checks thread safety of getFwdRefs(); -void checkFwdRefsSafety( char * fileName ) { - checkRefsSafety( fileName, true ); +bool checkFwdRefsSafety( char * fileName ) { + return checkRefsSafety( fileName, true ); } /// Checks thread safety of getFwdRefs(); -void checkRevRefsSafety( char * fileName ) { - checkRefsSafety( fileName, false ); +bool checkRevRefsSafety( char * fileName ) { + return checkRefsSafety( fileName, false ); } /// A vector of some common types which are present in most step files. The types persent in this vector are used to check for thread safety. @@ -162,7 +164,7 @@ void iterateTypeLists( lazyInstMgr * mgr, std::vector< const instanceRefs * > &s } /// checks the thread safety of getInstances(); -void checkTypeInstancesSafety( char * fileName ) { +bool checkTypeInstancesSafety( char * fileName ) { lazyInstMgr * mgr = new lazyInstMgr; mgr->openFile( fileName ); @@ -178,7 +180,8 @@ void checkTypeInstancesSafety( char * fileName ) { first.join(); second.join(); - if( success[0] && success[1] ) { + bool pass = ( success[0] && success[1] ); + if( pass ) { std::cout << "..PASS!" << std::endl; } else { std::cout << "...FAIL!" << std::endl; @@ -199,6 +202,7 @@ void checkTypeInstancesSafety( char * fileName ) { std::cout << std::endl << std::endl; delete mgr; + return pass; } /// load instances found in _refs into the instancesLoaded. After doing this once, it iterates over the _refs and reports any changes in loaded value. @@ -264,7 +268,7 @@ bool compareLoadedInstances( instanceRefs * toBeLoadedOnT1, instancesLoaded_t * #ifndef NO_REGISTRY //checks thread safety of loadInstance. (Also of instMgrAdapter if useAdapter is TRUE) -void checkLazyLoadingSafety( char * fileName, bool useAdapter=false ) { +bool checkLazyLoadingSafety( char * fileName, bool useAdapter=false ) { instanceRefs instancesToBeLoadedFwd, instancesToBeLoadedRev; instanceRefs * toBeLoadedOnT1, * toBeLoadedOnT2; @@ -300,7 +304,8 @@ void checkLazyLoadingSafety( char * fileName, bool useAdapter=false ) { loadedOnT2.clear(); } - if( intraThreadSuccess[0] && intraThreadSuccess[1] && interThreadSuccess ) { + bool pass = ( intraThreadSuccess[0] && intraThreadSuccess[1] && interThreadSuccess ); + if( pass ) { std::cout << "..PASS!" << std::endl; } else { std::cout << "...FAIL!" << std::endl; @@ -320,11 +325,12 @@ void checkLazyLoadingSafety( char * fileName, bool useAdapter=false ) { std::cout << std::endl; delete mgr; + return pass; } //checks thread safety of lazyloading along with that of instMgrAdapter -void checkLazyLoadingSafetyWithAdapter( char * fileName ) { - checkLazyLoadingSafety( fileName, true ); +bool checkLazyLoadingSafetyWithAdapter( char * fileName ) { + return checkLazyLoadingSafety( fileName, true ); } #endif //NO_REGISTRY @@ -516,7 +522,7 @@ void openFile( lazyInstMgr * mgr, char * fileName ) { } /// checks the thread safety by opening multiple files in parallel -void checkOpenFileSafety( char * file1, char * file2 ) { +bool checkOpenFileSafety( char * file1, char * file2 ) { lazyInstMgr * e_mgr = new lazyInstMgr; //expected lazyInstMgr std::cout << "Checking thread safety while opening multiple files in parallel..."; @@ -544,7 +550,8 @@ void checkOpenFileSafety( char * file1, char * file2 ) { } } - if( compareResult == OK ) { + bool pass = ( compareResult == OK ); + if( pass ) { std::cout << "..PASS!" << std::endl; } else { std::cout << "...FAIL!" << std::endl; @@ -553,6 +560,7 @@ void checkOpenFileSafety( char * file1, char * file2 ) { std::cout << std::endl; delete e_mgr; + return pass; } @@ -563,16 +571,23 @@ int main( int argc, char ** argv ) { exit( EXIT_FAILURE ); } - checkFwdRefsSafety( argv[1] ); - checkRevRefsSafety( argv[1] ); + bool pass = true; - checkTypeInstancesSafety( argv[1] ); + pass &= checkFwdRefsSafety( argv[1] ); + pass &= checkRevRefsSafety( argv[1] ); + + pass &= checkTypeInstancesSafety( argv[1] ); #ifndef NO_REGISTRY - checkLazyLoadingSafety( argv[1] ); - checkLazyLoadingSafetyWithAdapter( argv[1] ); + pass &= checkLazyLoadingSafety( argv[1] ); + pass &= checkLazyLoadingSafetyWithAdapter( argv[1] ); #endif //NO_REGISTRY - checkOpenFileSafety( argv[1], argv[2] ); + pass &= checkOpenFileSafety( argv[1], argv[2] ); + + if( pass ) { + exit( EXIT_SUCCESS ); + } + exit( EXIT_FAILURE ); } diff --git a/src/clstepcore/InstMgr_thread_safety_test.cc b/src/clstepcore/InstMgr_thread_safety_test.cc index bcae26a8b..6096fbe31 100644 --- a/src/clstepcore/InstMgr_thread_safety_test.cc +++ b/src/clstepcore/InstMgr_thread_safety_test.cc @@ -74,7 +74,7 @@ bool compareInstMgr( InstMgr * mgr1, InstMgr * mgr2 ) { } /// Performs addition of different instances to the same InstMgr simultaneosly. -void checkInstMgrAppendOnlyThreadSafety() { +bool checkInstMgrAppendOnlyThreadSafety() { InstMgr * imExpected = new InstMgr( 0 ); int size = dummyEDescNames.size(); @@ -104,20 +104,22 @@ void checkInstMgrAppendOnlyThreadSafety() { } } - if( i == iterations ) { + bool pass = ( i = iterations ); + if( pass ) { std::cout << "...PASS!" << std::endl; } else { std::cout << "...FAIL!" << std::endl; } std::cout << std::endl; - delete imExpected; deleteSdaiVec( sdaiVecOld ); + + return pass; } /// Performs deletion of different instances to the same InstMgr simultaneosly. -void checkInstMgrDeleteOnlyThreadSafety() { +bool checkInstMgrDeleteOnlyThreadSafety() { InstMgr * imExpected = new InstMgr( 0 ); int size = dummyEDescNames.size(); //simulate the work done by two threads @@ -149,7 +151,8 @@ void checkInstMgrDeleteOnlyThreadSafety() { } } - if( i == iterations ) { + bool pass = ( i = iterations ); + if( pass ) { std::cout << "...PASS!" << std::endl; } else { std::cout << "...FAIL!" << std::endl; @@ -158,10 +161,12 @@ void checkInstMgrDeleteOnlyThreadSafety() { std::cout << std::endl; delete imExpected; deleteSdaiVec( sdaiVecOld ); + + return pass; } /// Performs addition and deletion of different instances to the same InstMgr simultaneosly. -void checkInstMgrAppendDeleteThreadSafety() { +bool checkInstMgrAppendDeleteThreadSafety() { InstMgr * imExpected = new InstMgr( 0 ); int size = dummyEDescNames.size(); //simulate the work done by two threads @@ -193,7 +198,8 @@ void checkInstMgrAppendDeleteThreadSafety() { } } - if( i == iterations ) { + bool pass = ( i == iterations ); + if( pass ) { std::cout << "...PASS!" << std::endl; } else { std::cout << "...FAIL!" << std::endl; @@ -202,14 +208,22 @@ void checkInstMgrAppendDeleteThreadSafety() { std::cout << std::endl; delete imExpected; deleteSdaiVec( sdaiVecOld ); + + return pass; } int main( int , char ** ) { + bool pass = true; assert( dummyEDescNames.size() % 4 == 0 && "dummyEDescNames should be a multiple of 4 "); - checkInstMgrAppendOnlyThreadSafety(); - checkInstMgrDeleteOnlyThreadSafety(); - checkInstMgrAppendDeleteThreadSafety(); + pass &= checkInstMgrAppendOnlyThreadSafety(); + pass &= checkInstMgrDeleteOnlyThreadSafety(); + pass &= checkInstMgrAppendDeleteThreadSafety(); + + if( pass ) { + exit( EXIT_SUCCESS ); + } + exit( EXIT_FAILURE ); } diff --git a/src/clstepcore/Registry_thread_safety_test.cc b/src/clstepcore/Registry_thread_safety_test.cc index ed0fe6b64..8f713989a 100644 --- a/src/clstepcore/Registry_thread_safety_test.cc +++ b/src/clstepcore/Registry_thread_safety_test.cc @@ -129,7 +129,7 @@ bool compareRegistry( Registry * reg1, Registry * reg2 ) { /// For a particular mode adds elements to one Registry serially and to another Registry parallely. /// It then compares the two Registry and reports any disparity. -void checkRegistryAddOnlyThreadSafety( Mode mode ) { +bool checkRegistryAddOnlyThreadSafety( Mode mode ) { int size = names.size(); Registry * regExpected = new Registry( dummyInit ); @@ -156,7 +156,8 @@ void checkRegistryAddOnlyThreadSafety( Mode mode ) { } } - if( i == iterations ) { + bool pass = ( i == iterations ); + if( pass ) { std::cout << "...PASS!" << std::endl; } else { std::cout << "...FAIL!" << std::endl; @@ -165,11 +166,12 @@ void checkRegistryAddOnlyThreadSafety( Mode mode ) { std::cout << std::endl; delete regExpected; + return pass; } /// For a particular mode removes elements to one Registry serially and to another Registry parallely. /// It then compares the two Registry and reports any disparity. -void checkRegistryRemoveOnlyThreadSafety( Mode mode ) { +bool checkRegistryRemoveOnlyThreadSafety( Mode mode ) { int size = names.size(); Registry * regExpected = new Registry( dummyInit ); @@ -198,7 +200,8 @@ void checkRegistryRemoveOnlyThreadSafety( Mode mode ) { } } - if( i == iterations ) { + bool pass = ( i == iterations ); + if( pass ) { std::cout << "...PASS!" << std::endl; } else { std::cout << "...FAIL!" << std::endl; @@ -207,11 +210,12 @@ void checkRegistryRemoveOnlyThreadSafety( Mode mode ) { std::cout << std::endl; delete regExpected; + return pass; } /// For a particular mode adds and removes elements to one Registry serially and to ther Registry parallely. /// It then compares the two Registry and reports any disparity. -void checkRegistryAddRemoveThreadSafety( Mode mode ) { +bool checkRegistryAddRemoveThreadSafety( Mode mode ) { int size = names.size(); Registry * regExpected = new Registry( dummyInit ); @@ -240,7 +244,8 @@ void checkRegistryAddRemoveThreadSafety( Mode mode ) { } } - if( i == iterations ) { + bool pass = ( i == iterations ); + if( pass ) { std::cout << "...PASS!" << std::endl; } else { std::cout << "...FAIL!" << std::endl; @@ -249,42 +254,43 @@ void checkRegistryAddRemoveThreadSafety( Mode mode ) { std::cout << std::endl; delete regExpected; + return pass; } -void checkRegistryEntityAddOnlyThreadSafety() { - checkRegistryAddOnlyThreadSafety( ENTITY ); +bool checkRegistryEntityAddOnlyThreadSafety() { + return checkRegistryAddOnlyThreadSafety( ENTITY ); } -void checkRegistrySchemaAddOnlyThreadSafety() { - checkRegistryAddOnlyThreadSafety( SCHEMA ); +bool checkRegistrySchemaAddOnlyThreadSafety() { + return checkRegistryAddOnlyThreadSafety( SCHEMA ); } -void checkRegistryTypeAddOnlyThreadSafety() { - checkRegistryAddOnlyThreadSafety( TYPE ); +bool checkRegistryTypeAddOnlyThreadSafety() { + return checkRegistryAddOnlyThreadSafety( TYPE ); } -void checkRegistryEntityRemoveOnlyThreadSafety() { - checkRegistryRemoveOnlyThreadSafety( ENTITY ); +bool checkRegistryEntityRemoveOnlyThreadSafety() { + return checkRegistryRemoveOnlyThreadSafety( ENTITY ); } -void checkRegistrySchemaRemoveOnlyThreadSafety() { - checkRegistryRemoveOnlyThreadSafety( SCHEMA ); +bool checkRegistrySchemaRemoveOnlyThreadSafety() { + return checkRegistryRemoveOnlyThreadSafety( SCHEMA ); } -void checkRegistryTypeRemoveOnlyThreadSafety() { - checkRegistryRemoveOnlyThreadSafety( TYPE ); +bool checkRegistryTypeRemoveOnlyThreadSafety() { + return checkRegistryRemoveOnlyThreadSafety( TYPE ); } -void checkRegistryEntityAddRemoveThreadSafety() { - checkRegistryAddRemoveThreadSafety( ENTITY ); +bool checkRegistryEntityAddRemoveThreadSafety() { + return checkRegistryAddRemoveThreadSafety( ENTITY ); } -void checkRegistrySchemaAddRemoveThreadSafety() { - checkRegistryAddRemoveThreadSafety( SCHEMA ); +bool checkRegistrySchemaAddRemoveThreadSafety() { + return checkRegistryAddRemoveThreadSafety( SCHEMA ); } -void checkRegistryTypeAddRemoveThreadSafety() { - checkRegistryAddRemoveThreadSafety( TYPE ); +bool checkRegistryTypeAddRemoveThreadSafety() { + return checkRegistryAddRemoveThreadSafety( TYPE ); } // populates the vector names[] with string of the form [A-Z]/[a-z]/[a-z] @@ -312,15 +318,21 @@ void populateNamesVector() { int main( int , char ** ) { populateNamesVector(); - checkRegistryEntityAddOnlyThreadSafety(); - checkRegistryEntityRemoveOnlyThreadSafety(); - checkRegistryEntityAddRemoveThreadSafety(); + bool pass = true; + pass &= checkRegistryEntityAddOnlyThreadSafety(); + pass &= checkRegistryEntityRemoveOnlyThreadSafety(); + pass &= checkRegistryEntityAddRemoveThreadSafety(); - checkRegistrySchemaAddOnlyThreadSafety(); - checkRegistrySchemaRemoveOnlyThreadSafety(); - checkRegistrySchemaAddRemoveThreadSafety(); + pass &= checkRegistrySchemaAddOnlyThreadSafety(); + pass &= checkRegistrySchemaRemoveOnlyThreadSafety(); + pass &= checkRegistrySchemaAddRemoveThreadSafety(); - checkRegistryTypeAddOnlyThreadSafety(); - checkRegistryTypeRemoveOnlyThreadSafety(); - checkRegistryTypeAddRemoveThreadSafety(); + pass &= checkRegistryTypeAddOnlyThreadSafety(); + pass &= checkRegistryTypeRemoveOnlyThreadSafety(); + pass &= checkRegistryTypeAddRemoveThreadSafety(); + + if( pass ) { + exit( EXIT_SUCCESS ); + } + exit( EXIT_FAILURE ); } From ba74c53ca01d6da0b8647a8bd2bfd79284a6cb75 Mon Sep 17 00:00:00 2001 From: Mark Pictor Date: Thu, 21 Aug 2014 20:27:28 -0400 Subject: [PATCH 110/111] for std::thread, change reference args to pointers I ran into an error "...error: no type named 'type' in class std::result_of..." Google led me to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57716 and I eliminated the error by changing references to pointers as described at http://stackoverflow.com/questions/15235885/invalid-initialization-of-non-const-reference-with-c11-thread --- src/cllazyfile/lazy_thread_safety_test.cc | 18 ++++---- src/clstepcore/InstMgr_thread_safety_test.cc | 42 +++++++++---------- ...Application_instance_thread_safety_test.cc | 22 +++++----- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/cllazyfile/lazy_thread_safety_test.cc b/src/cllazyfile/lazy_thread_safety_test.cc index cb7087beb..a38032c3d 100644 --- a/src/cllazyfile/lazy_thread_safety_test.cc +++ b/src/cllazyfile/lazy_thread_safety_test.cc @@ -46,9 +46,9 @@ void prepareRealRefsFromStreamPos ( instanceStreamPos_t * _spos, instanceRefs &r /// Used by an individual thread to iterate over the keys of the _fwdRefs / _revRefs multiple times. For each iteration it expects the order of the keys to be the same as dictated by realRefs. -void iterateOverRefs ( lazyInstMgr *mgr, instanceRefs &realRefs, bool forward, bool * success ) { +void iterateOverRefs ( lazyInstMgr *mgr, instanceRefs * realRefs, bool forward, bool * success ) { const int iterations = 1000; - int i, k, instances = realRefs.size(); + int i, k, instances = realRefs->size(); instanceID current; instanceRefs_t * _refs; @@ -58,7 +58,7 @@ void iterateOverRefs ( lazyInstMgr *mgr, instanceRefs &realRefs, bool forward, b current = _refs->begin().key; for( i = 0; i < instances; i++ ) { - if( current != realRefs[i] ) { + if( current != (*realRefs)[i] ) { break; } @@ -84,8 +84,8 @@ bool checkRefsSafety( char * fileName, bool forward ) { } bool success[2] = { true, true }; - std::thread first( iterateOverRefs, mgr, realRefs, forward, &success[0] ); - std::thread second( iterateOverRefs, mgr, realRefs, forward, &success[1] ); + std::thread first( iterateOverRefs, mgr, &realRefs, forward, &success[0] ); + std::thread second( iterateOverRefs, mgr, &realRefs, forward, &success[1] ); first.join(); second.join(); @@ -144,7 +144,7 @@ bool compareTypeLists( const instanceRefs * v1, const instanceRefs * v2 ) { } /// compares the original instances lists with the thread's own view of instances list. -void iterateTypeLists( lazyInstMgr * mgr, std::vector< const instanceRefs * > &sameTypeInstances, bool * success ) { +void iterateTypeLists( lazyInstMgr * mgr, std::vector< const instanceRefs * > * sameTypeInstances, bool * success ) { const int iterations = 100000; const instanceRefs * refs; int i, k, instances = commonTypes.size(); @@ -154,7 +154,7 @@ void iterateTypeLists( lazyInstMgr * mgr, std::vector< const instanceRefs * > &s refs = mgr->getInstancesSafely( commonTypes[i] ); - if( !compareTypeLists( refs, sameTypeInstances[i] ) ) { + if( !compareTypeLists( refs, (*sameTypeInstances)[i] ) ) { break; } } @@ -174,8 +174,8 @@ bool checkTypeInstancesSafety( char * fileName ) { prepareSameTypeInstances( mgr, sameTypeInstances ); bool success[2] = { true, true }; - std::thread first( iterateTypeLists, mgr, sameTypeInstances, &success[0] ); - std::thread second( iterateTypeLists, mgr, sameTypeInstances, &success[1] ); + std::thread first( iterateTypeLists, mgr, &sameTypeInstances, &success[0] ); + std::thread second( iterateTypeLists, mgr, &sameTypeInstances, &success[1] ); first.join(); second.join(); diff --git a/src/clstepcore/InstMgr_thread_safety_test.cc b/src/clstepcore/InstMgr_thread_safety_test.cc index 6096fbe31..c186df80a 100644 --- a/src/clstepcore/InstMgr_thread_safety_test.cc +++ b/src/clstepcore/InstMgr_thread_safety_test.cc @@ -23,20 +23,20 @@ void deleteSdaiVec( sdaiVec_t &sdaiVec ) { } } -void appendInstances( InstMgr * im, sdaiVec_t &sdaiVec, int offset, int stride, int limit ) { +void appendInstances( InstMgr * im, sdaiVec_t * sdaiVec, int offset, int stride, int limit ) { SDAI_Application_instance * sai; for( int i = offset; i < limit; i+=stride ) { sai = new SDAI_Application_instance( i+1 ); sai->eDesc = new EntityDescriptor( dummyEDescNames[i].c_str(), ( Schema * ) NULL, LTrue, LFalse ); - sdaiVec[i] = sai; + (*sdaiVec)[i] = sai; im->Append( sai, completeSE ); } } -void deleteInstances( InstMgr * im, sdaiVec_t &sdaiVec, int offset, int stride, int limit ) { +void deleteInstances( InstMgr * im, sdaiVec_t * sdaiVec, int offset, int stride, int limit ) { for( int i = offset; i < limit; i+=stride ) { - im->Delete( sdaiVec[i] ); - sdaiVec[i] = 0; + im->Delete( (*sdaiVec)[i] ); + (*sdaiVec)[i] = 0; } } @@ -80,8 +80,8 @@ bool checkInstMgrAppendOnlyThreadSafety() { //simulate the work done by two threads sdaiVec_t sdaiVecOld( size ); - appendInstances( imExpected, sdaiVecOld, 0, 2, size ); - appendInstances( imExpected, sdaiVecOld, 1, 2, size ); + appendInstances( imExpected, &sdaiVecOld, 0, 2, size ); + appendInstances( imExpected, &sdaiVecOld, 1, 2, size ); std::cout << "Checking thread safety of InstMgr in Append Operation..." ; int i, iterations = 1000; @@ -89,8 +89,8 @@ bool checkInstMgrAppendOnlyThreadSafety() { InstMgr * imActual = new InstMgr( 0 ); sdaiVec_t sdaiVecNew( size ); - std::thread first( appendInstances, imActual, sdaiVecNew, 0, 2, size ); - std::thread second( appendInstances, imActual, sdaiVecNew, 1, 2, size ); + std::thread first( appendInstances, imActual, &sdaiVecNew, 0, 2, size ); + std::thread second( appendInstances, imActual, &sdaiVecNew, 1, 2, size ); first.join(); second.join(); @@ -125,9 +125,9 @@ bool checkInstMgrDeleteOnlyThreadSafety() { //simulate the work done by two threads sdaiVec_t sdaiVecOld( size ); - appendInstances( imExpected, sdaiVecOld, 0, 1, size ); - deleteInstances( imExpected, sdaiVecOld, 0, 2, size ); - deleteInstances( imExpected, sdaiVecOld, 1, 2, size ); + appendInstances( imExpected, &sdaiVecOld, 0, 1, size ); + deleteInstances( imExpected, &sdaiVecOld, 0, 2, size ); + deleteInstances( imExpected, &sdaiVecOld, 1, 2, size ); std::cout << "Checking thread safety of InstMgr in Delete Operation..." ; int i, iterations = 1000; @@ -135,9 +135,9 @@ bool checkInstMgrDeleteOnlyThreadSafety() { InstMgr * imActual = new InstMgr( 0 ); sdaiVec_t sdaiVecNew( size ); - appendInstances( imActual, sdaiVecNew, 0, 1, size ); //Preparetion - std::thread first( deleteInstances, imActual, sdaiVecNew, 0, 2, size ); - std::thread second( deleteInstances, imActual, sdaiVecNew, 1, 2, size ); + appendInstances( imActual, &sdaiVecNew, 0, 1, size ); //Preparetion + std::thread first( deleteInstances, imActual, &sdaiVecNew, 0, 2, size ); + std::thread second( deleteInstances, imActual, &sdaiVecNew, 1, 2, size ); first.join(); second.join(); @@ -172,9 +172,9 @@ bool checkInstMgrAppendDeleteThreadSafety() { //simulate the work done by two threads sdaiVec_t sdaiVecOld( size ); - appendInstances( imExpected, sdaiVecOld, 0, 2, size ); - appendInstances( imExpected, sdaiVecOld, 1, 2, size ); - deleteInstances( imExpected, sdaiVecOld, 0, 2, size ); + appendInstances( imExpected, &sdaiVecOld, 0, 2, size ); + appendInstances( imExpected, &sdaiVecOld, 1, 2, size ); + deleteInstances( imExpected, &sdaiVecOld, 0, 2, size ); std::cout << "Checking thread safety of InstMgr in Append-Delete Operation..." ; int i, iterations = 1000; @@ -182,9 +182,9 @@ bool checkInstMgrAppendDeleteThreadSafety() { InstMgr * imActual = new InstMgr( 0 ); sdaiVec_t sdaiVecNew( size ); - appendInstances( imActual, sdaiVecNew, 0, 2, size ); //Preparation - std::thread first( appendInstances, imActual, sdaiVecNew, 1, 2, size ); - std::thread second( deleteInstances, imActual, sdaiVecNew, 0, 2, size ); + appendInstances( imActual, &sdaiVecNew, 0, 2, size ); //Preparation + std::thread first( appendInstances, imActual, &sdaiVecNew, 1, 2, size ); + std::thread second( deleteInstances, imActual, &sdaiVecNew, 0, 2, size ); first.join(); second.join(); diff --git a/src/clstepcore/sdaiApplication_instance_thread_safety_test.cc b/src/clstepcore/sdaiApplication_instance_thread_safety_test.cc index fac9c4bc7..1f815fff1 100644 --- a/src/clstepcore/sdaiApplication_instance_thread_safety_test.cc +++ b/src/clstepcore/sdaiApplication_instance_thread_safety_test.cc @@ -66,19 +66,19 @@ void deleteInstanceList( sdaiVec_t & sdaiVec ) { } // appends the sdaiApplication_instances from a certain section of the list to sai. (upper and lower limits are inclusive) -void appendListTo( SDAI_Application_instance * sai, sdaiVec_t & sdaiVec, int llimit, int ulimit ) { +void appendListTo( SDAI_Application_instance * sai, sdaiVec_t * sdaiVec, int llimit, int ulimit ) { for( int i = llimit; i <= ulimit; i++ ) { - sai->AppendMultInstance( sdaiVec[i] ); + sai->AppendMultInstance( (*sdaiVec)[i] ); } } // searches for the sdaiApplication_instances belonging to ahe certain section of the list from sai. (upper and lower limits are inclusive) // nullAllowedIndex marks the index after which GetMiEntity is allowed to return a NULL value -void searchForElements( SDAI_Application_instance * sai, sdaiVec_t & sdaiVec, int llimit, int ulimit, int nullAllowedIndex, bool * errorInFinding ) { +void searchForElements( SDAI_Application_instance * sai, sdaiVec_t * sdaiVec, int llimit, int ulimit, int nullAllowedIndex, bool * errorInFinding ) { SDAI_Application_instance * saiFound; for( int i = llimit; i <= ulimit; i++ ) { saiFound = sai->GetMiEntity( EntityNames[i].c_str() ); - if( saiFound != sdaiVec[i] ) { + if( saiFound != (*sdaiVec)[i] ) { if( saiFound == NULL && i >= nullAllowedIndex ) { continue; } else if( i < nullAllowedIndex ) { @@ -129,10 +129,10 @@ bool checkAddAddInstance() { createInstanceList( sdaiVec ); size = sdaiVec.size(); - appendListTo( sdaiVec[0], sdaiVec, 1, 4 ); //Initializing List before test + appendListTo( sdaiVec[0], &sdaiVec, 1, 4 ); //Initializing List before test - std::thread first( appendListTo, sdaiVec[0], sdaiVec, 5, size/2 ); - std::thread second( appendListTo, sdaiVec[4], sdaiVec, ( size/2 )+1 , size-1 ); + std::thread first( appendListTo, sdaiVec[0], &sdaiVec, 5, size/2 ); + std::thread second( appendListTo, sdaiVec[4], &sdaiVec, ( size/2 )+1 , size-1 ); first.join(); second.join(); @@ -163,17 +163,17 @@ bool checkAddAddGetInstance() { createInstanceList( sdaiVec ); size = sdaiVec.size(); - appendListTo( sdaiVec[0], sdaiVec, 1, 4 ); //Initializing List before test + appendListTo( sdaiVec[0], &sdaiVec, 1, 4 ); //Initializing List before test // The elements added by the two threads are in the ratio 1:3 - std::thread first( appendListTo, sdaiVec[0], sdaiVec, 5, size/4 ); - std::thread second( appendListTo, sdaiVec[4], sdaiVec, ( size/4 )+1 , size-1 ); + std::thread first( appendListTo, sdaiVec[0], &sdaiVec, 5, size/4 ); + std::thread second( appendListTo, sdaiVec[4], &sdaiVec, ( size/4 )+1 , size-1 ); first.join(); bool errorInFinding; //search for first half of the sdaiApplication_instances. 1/4 elements will be present. rest 1/4 elements may / may not be present - std::thread third( searchForElements, sdaiVec[0], sdaiVec, 0, size/2, size/4, &errorInFinding ); + std::thread third( searchForElements, sdaiVec[0], &sdaiVec, 0, size/2, size/4, &errorInFinding ); second.join(); third.join(); From e9d878edaeeb595b9cc8d0d2033c7389c617646d Mon Sep 17 00:00:00 2001 From: hoiji09 Date: Sun, 5 Oct 2014 21:15:24 +0530 Subject: [PATCH 111/111] Simplified Locking in MultList This was done by moving the mutex from EntList to MultList. --- src/clstepcore/complexSupport.h | 27 ++++++++++++--------------- src/clstepcore/match-ors.cc | 4 ++-- src/clstepcore/multlist.cc | 20 +++----------------- src/clstepcore/orlist.cc | 6 +++--- src/clstepcore/trynext.cc | 12 ++++++------ 5 files changed, 26 insertions(+), 43 deletions(-) diff --git a/src/clstepcore/complexSupport.h b/src/clstepcore/complexSupport.h index fc6222ee8..36e89de33 100644 --- a/src/clstepcore/complexSupport.h +++ b/src/clstepcore/complexSupport.h @@ -142,12 +142,6 @@ class SC_CORE_EXPORT EntNode { }; class SC_CORE_EXPORT EntList { - // NOTE: The locking methodology used here assumes that a node (i.e a - // EntList object) can neither be removed, nor can be inserted - // between two existing nodes. If such APIs are introduced in - // future the EntList class (or its subclasses) will no longer be - // thread safe and can crash / deadlock under multithreaded environment. - friend class MultList; friend class JoinList; friend class OrList; @@ -203,10 +197,6 @@ class SC_CORE_EXPORT EntList { return ( join != SIMPLE ); } EntList * next, *prev; - sc_mutex mtx; - /** \var mtx - * Currently only being used by the subclass MultList - */ protected: MatchType viable; @@ -269,7 +259,7 @@ class SC_CORE_EXPORT MultList : public EntList { public: MultList( JoinType j ) : EntList( j ), supertype( 0 ), numchildren( 0 ), - childList( 0 ) {} + childList( 0 ), mtxP( new sc_mutex() ) {;} ~MultList(); void setLevel( int ); bool contains( char * ); @@ -301,6 +291,13 @@ class SC_CORE_EXPORT MultList : public EntList { * The children may be SIMPLE EntLists (contain entity names) or may * themselves be And-, Or-, or AndOrLists. */ + + mutable sc_mutex * mtxP; + /** \var mtxP + * Protects childList, numchildren and the counters in subclass + * OrList. NOTE: The locking methodology assumes that a childList + * will have a unique parent. + */ }; /** \class JoinList @@ -346,17 +343,17 @@ class SC_CORE_EXPORT OrList : public MultList { void unmarkAll( EntNode * ); bool acceptChoice( EntNode * ); bool acceptNextChoice( EntNode * ents ) { - mtx.lock(); + mtxP->lock(); choice++; - mtx.unlock(); + mtxP->unlock(); return ( acceptChoice( ents ) ); } void reset() { - mtx.lock(); + mtxP->lock(); choice = -1; choice1 = -2; choiceCount = 0; - mtx.unlock(); + mtxP->unlock(); MultList::reset(); } diff --git a/src/clstepcore/match-ors.cc b/src/clstepcore/match-ors.cc index ea914a96c..34182d5d2 100644 --- a/src/clstepcore/match-ors.cc +++ b/src/clstepcore/match-ors.cc @@ -121,9 +121,9 @@ MatchType OrList::matchORs( EntNode * ents ) { if( choice == -1 ) { choice1 = choice = count; } - mtx.lock();// protects choiceCount + mtxP->lock();// protects choiceCount choiceCount++; - mtx.unlock(); + mtxP->unlock(); if( viable < retval ) { viable = retval; diff --git a/src/clstepcore/multlist.cc b/src/clstepcore/multlist.cc index 37d7a0f5a..da08c5114 100644 --- a/src/clstepcore/multlist.cc +++ b/src/clstepcore/multlist.cc @@ -27,6 +27,7 @@ MultList::~MultList() { delete child; child = cnext; } + delete mtxP; } /** @@ -104,29 +105,16 @@ EntList * MultList::getChild( int num ) { */ void MultList::appendList( EntList * ent ) { EntList * eprev; - - mtx.lock(); // Protects numchildren, childList + mtxP->lock(); // Protects numchildren, childList if( numchildren == 0 ) { childList = ent; } else { eprev = getLast(); - eprev->mtx.lock(); - // In a multithreaded environment It is possible that before locking - // more elements got added into the existing list and eprev is no - // longer the last element. This while loop takes care of that. - while( eprev->next ) { - eprev->mtx.unlock(); - eprev = eprev->next; - eprev->mtx.lock(); - } - // eprev lock is acquired eprev->next = ent; - eprev->mtx.unlock(); - ent->prev = eprev; // ent locking not required } numchildren += ent->siblings(); - mtx.unlock(); + mtxP->unlock(); } /** @@ -150,9 +138,7 @@ EntList * MultList::copyList( EntList * ent ) { newlist = new AndOrList; break; }; - ent->mtx.lock(); // appendList doesn't lock the EntNode appendList( newlist ); - ent->mtx.unlock(); if( ent->multiple() ) { // For the multlists, we must recurse for all their children: diff --git a/src/clstepcore/orlist.cc b/src/clstepcore/orlist.cc index 58309e2a5..653b2a217 100644 --- a/src/clstepcore/orlist.cc +++ b/src/clstepcore/orlist.cc @@ -65,7 +65,7 @@ void OrList::unmarkAll( EntNode * ents ) { bool OrList::acceptChoice( EntNode * ents ) { EntList * child; - mtx.lock(); // to proctect choice + mtxP->lock(); // to proctect choice if( choice == LISTEND ) { choice = choice1; } @@ -73,7 +73,7 @@ bool OrList::acceptChoice( EntNode * ents ) { while( child ) { if( child->viable >= MATCHSOME && child->acceptChoice( ents ) ) { // acceptChoice() returns true if we marked something. - mtx.unlock(); + mtxP->unlock(); return true; } child = child->next; @@ -82,6 +82,6 @@ bool OrList::acceptChoice( EntNode * ents ) { // If we got here, we must have gotten to the end of the childList without // finding a choice which marks something. choice = LISTEND; - mtx.unlock(); + mtxP->unlock(); return false; } diff --git a/src/clstepcore/trynext.cc b/src/clstepcore/trynext.cc index e091901d5..63146aa52 100644 --- a/src/clstepcore/trynext.cc +++ b/src/clstepcore/trynext.cc @@ -103,10 +103,10 @@ MatchType OrList::tryNext( EntNode * ents ) { EntList * child; MatchType retval; - mtx.lock(); // For choice + mtxP->lock(); // For choice if( choice == LISTEND ) { // if we've already exhausted all the choices in this OR, - mtx.unlock(); + mtxP->unlock(); return NOMORE; } @@ -120,7 +120,7 @@ MatchType OrList::tryNext( EntNode * ents ) { // our descendants before moving on. retval = ( ( MultList * )child )->tryNext( ents ); if( retval == MATCHALL ) { - mtx.unlock(); + mtxP->unlock(); ents->sharedMtxP->unlock(); return MATCHALL; } @@ -129,7 +129,7 @@ MatchType OrList::tryNext( EntNode * ents ) { // EntLists on the higher levels (if there are) can retry all the // later choices with the new choice we just found. Otherwise, // we'll continue below looking into our next choice. - mtx.unlock(); + mtxP->unlock(); ents->sharedMtxP->unlock(); return NEWCHOICE; } @@ -143,11 +143,11 @@ MatchType OrList::tryNext( EntNode * ents ) { // (Also, it's nec. to unmark now, as we did above before returning and // before the calling tryNext() tries earlier OR's - see notes, 11/12.) choice = LISTEND; - mtx.unlock(); + mtxP->unlock(); ents->sharedMtxP->unlock(); return NOMORE; } - mtx.unlock(); + mtxP->unlock(); // Otherwise, try our next: if( acceptNextChoice( ents ) ) {