Compare commits

...

111 commits

Author SHA1 Message Date
Mark Pictor
ba74c53ca0 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
2014-08-21 20:27:36 -04:00
hoiji09
5dc00ba03f Merge remote-tracking branch 'origin/master' into hj/thread-safety
Conflicts:
	src/clstepcore/instmgr.cc
2014-08-18 19:37:13 +05:30
hoiji09
1265e0c110 Added exit(success/fail) in thread-safety test 2014-08-18 17:45:31 +05:30
hoiji09
e73ad4df1c 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.
2014-08-18 17:28:30 +05:30
hoiji09
f0fdfd706f Added class sc_thread in sc_thread.h 2014-08-18 17:25:58 +05:30
hoiji09
bac1435936 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.
2014-08-18 17:00:01 +05:30
hoiji09
54457e567a 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
2014-08-18 16:56:06 +05:30
hoiji09
2aa936b601 Corrected a coment sc_mutex.h 2014-08-18 14:08:18 +05:30
hoiji09
85a248a50a 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.
2014-08-18 11:57:17 +05:30
hoiji09
03981d27e0 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.
2014-08-15 23:25:32 +05:30
hoiji09
f26cb0457d 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.
2014-08-15 22:56:49 +05:30
hoiji09
42d71188fc Made SDAI__set thread safe
This was done by introducing a mutex in the SDAI__set class.
2014-08-15 22:20:09 +05:30
hoiji09
40c3a1c33b 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.
2014-08-15 21:46:48 +05:30
hoiji09
fa75e8cedd 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.
2014-08-15 21:41:50 +05:30
hoiji09
b17bcbdaf0 Removed warning from SDAI_instance__set commit 2014-08-15 20:41:30 +05:30
hoiji09
731673f827 Thread safety in SDAI_Application_instance__set
Done by introducing a recursive_mutex in the SDAI_Application_instance__set class.
2014-08-13 21:06:26 +05:30
hoiji09
e941244617 Added a comment about thread safety in STEPfile 2014-08-13 11:15:41 +05:30
hoiji09
91efe7c0e5 Safe attributes iteration in STEPfile 2014-08-13 10:55:12 +05:30
hoiji09
02b41416fb 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.
2014-08-13 10:44:34 +05:30
hoiji09
9cbe6d1dd9 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.
2014-08-13 10:19:24 +05:30
hoiji09
a3ce139347 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.
2014-08-13 10:07:32 +05:30
hoiji09
e3fbc14282 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.
2014-08-10 22:44:11 +05:30
hoiji09
9f24e3ef64 Optimized ReadReal
Replaced calls to input stream peek & get with judicious use of get.
2014-08-08 20:10:05 +05:30
hoiji09
7f653188c4 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.
2014-08-08 11:04:21 +05:30
hoiji09
3c616f1455 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.
2014-08-06 20:36:25 +05:30
hoiji09
376dc4a482 Thread safety in CmdMgr of cleditor 2014-08-06 20:32:52 +05:30
hoiji09
0fe8bc3a91 Made ReplicateList in cleditor thread safe
Used mtxP of the superclass SingleLinkList to ensure thread safety
2014-08-06 20:31:25 +05:30
hoiji09
dc5a00f0ea 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.
2014-08-03 00:51:47 +05:30
hoiji09
27f781477c 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)
2014-08-03 00:19:22 +05:30
hoiji09
1095f7346d 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
2014-08-03 00:10:18 +05:30
hoiji09
3c848a5d2b 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
2014-08-02 23:36:36 +05:30
hoiji09
79c9901662 Thread safety in MultList
The mutex defined in the superclass EntList was used in the function appendList.
2014-08-02 23:23:54 +05:30
hoiji09
07448b77d6 Thread Safety in SimpleList
Used sharedMtxP defined in EntNode class to protect EntNode list structure which was being accessed in functions of SimpleList class
2014-08-02 23:01:21 +05:30
hoiji09
0a45ce2aa5 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)
2014-08-02 22:32:00 +05:30
hoiji09
3fdbe460f1 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.
2014-07-24 23:06:21 +05:30
hoiji09
2cabefa944 Minor STEPcomplex optimization
Collapsed an if condition into a while condition without changing the semantics
2014-07-24 22:47:23 +05:30
hoiji09
7233d604a1 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.
2014-07-24 22:31:26 +05:30
hoiji09
06b7ee5823 Made sdaiSelect::CanBe( BASE_TYPE ) thread safe. 2014-07-22 11:03:32 +05:30
hoiji09
36d4876333 Locking in ExpDict.cc
There were some functions in ExpDict.cc that were not properly locked before. Locking was done in them
2014-07-22 10:54:10 +05:30
hoiji09
cdede9ee27 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.
2014-07-18 20:49:02 +05:30
hoiji09
66999c76aa 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)
2014-07-18 16:02:12 +05:30
hoiji09
62761ceba8 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.
2014-07-18 15:00:28 +05:30
hoiji09
1aa1ed110f Redefined GetMiEntity API
GetMiEntity function is a part of SDAI_Application_instance class. The function now accepts const char * (instead of char *) as parameter.
2014-07-18 14:54:19 +05:30
hoiji09
10f041c779 Made STEPattributeList thread safe
Couple of functions were identified as vulnerable. The mutex defined in the superclass SingleLinkList was used.
2014-07-18 14:46:45 +05:30
hoiji09
25081dfa0e Removed the infinite recursion bug in STEPattribute
The bug would surface if a STEPattribute instance which has been redefined, has its ShallowCopy function invoked.
2014-07-18 14:35:31 +05:30
hoiji09
ca7594bd75 Removed garbage characters 2014-07-13 22:43:40 +05:30
hoiji09
b7cc806a57 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.
2014-07-12 18:55:33 +05:30
hoiji09
cb1f402b15 Made STEPaggregrate thread safe.
This was done by relying on the mtx used by its superclass: SingleLinkList.
2014-07-12 16:40:46 +05:30
hoiji09
25ec194b33 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
2014-07-12 13:52:33 +05:30
hoiji09
832154ae44 Made SubSuperIterators.h thread safe
This was done by introducing a recursive mutex meant to protect the std::deque 'q' and unsigned integer 'position'
2014-07-10 17:04:37 +05:30
hoiji09
6e5475e37d Removed duplicated code in SubSuperIterators.cc 2014-07-10 16:33:23 +05:30
hoiji09
529d3a0ca0 Duplicate code was removed in STEPaggregrate
STEPaggregrate and its superclass SingleLinkList.cc had the same destructor.
2014-07-10 11:18:38 +05:30
hoiji09
d169a58ec5 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.
2014-07-09 22:02:34 +05:30
hoiji09
e951c2c71a Corrected SingleLinkedList mtx bug
The mtx is converted into sc_recursive_mtx deleted in the destructor
2014-07-09 21:12:16 +05:30
hoiji09
077633aa77 Made Registry Schema and Type operations thread safe
All the checks in Registry_thread_safety_test now pass
2014-06-25 22:26:17 +05:30
hoiji09
58ca507d13 Made the Registry entity operation thread safe
The checks related entity operations in Registry_thread_safety_test now pass.
2014-06-25 22:15:00 +05:30
hoiji09
738d1820df 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.
2014-06-25 12:05:20 +05:30
hoiji09
391180bc2d 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.
2014-06-25 11:56:11 +05:30
hoiji09
fe33e5d5cb 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
2014-06-25 11:51:09 +05:30
hoiji09
cf9a203988 Made Dictionary_instance__set thread safe. 2014-06-25 11:45:08 +05:30
hoiji09
6b97cbe906 Made SingleLinkList class thread safe
This was done by adding a mutex. Also a cmake file was modified inorder to compile the above changes.
2014-06-25 11:37:10 +05:30
hoiji09
643da31f92 Added a missing return statement 2014-06-23 17:26:34 +05:30
hoiji09
e02ce60f9d Made Where_rule__list a subclass.
The superclass was Dictionary_instance__set
2014-06-22 22:11:31 +05:30
hoiji09
3db2ab29c0 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
2014-06-22 21:56:39 +05:30
hoiji09
dc8e00b794 Added Dictionary_instance__set
This class is intended to be a superclass of all the *__set classes. This will help to removve duplicate code
2014-06-22 21:52:15 +05:30
hoiji09
2a4d42e596 Added std_recursive_mutex in GenNodeArray.
Also modified classes which inherit the above accordingly
2014-06-18 22:43:31 +05:30
hoiji09
29ec4e33e1 Minor refractoring in MgrNodeArray
This will be helpful when we introduce a mutex in GenNodeArray.
2014-06-18 22:34:02 +05:30
hoiji09
d0e9aa9dfb 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.
2014-06-18 22:26:42 +05:30
hoiji09
d6c133f805 Introduced recursive_mutex in gennodelist
mgrnodelist which inherits gennodelist was also changed
2014-06-18 22:08:39 +05:30
hoiji09
ad6752a80f Used containingList to remove duplicate code. 2014-06-18 22:00:48 +05:30
hoiji09
f89e3c4999 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.
2014-06-18 21:51:28 +05:30
hoiji09
17c720206a Added another occurance of containingList 2014-06-18 21:49:32 +05:30
hoiji09
05360da87c 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.
2014-06-18 21:41:39 +05:30
hoiji09
d6ad56ee6c Locked more potentially thread-unsafe functions. 2014-06-18 11:51:18 +05:30
hoiji09
79f9473d01 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.
2014-06-18 11:44:54 +05:30
hoiji09
f6b92019b1 Corrected locking in getApplication_Instance 2014-06-18 11:41:26 +05:30
hoiji09
65f767aa7b Increasing the number of iterations.
A print statement is also corrected.
2014-06-18 11:30:41 +05:30
hoiji09
164c0651e1 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.
2014-06-15 14:40:41 +05:30
hoiji09
485fad46ca Removed duplicate code 2014-06-15 14:34:23 +05:30
hoiji09
d990137d1b Modified CMakeLists.txt to include HAVE_STD_THREAD defs.
The cmake files of cldai, cleditor & clstepcore libraries have been changed.
2014-06-15 14:27:23 +05:30
hoiji09
5cba5e6a8a 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.
2014-06-15 14:21:16 +05:30
hoiji09
e67a5f51d1 Added sc_mutex.h to src/clutils
It is wrapper to std::mutex. It does nothing if HAVE_STD_MUTEX is not defined.
2014-06-15 13:32:17 +05:30
hoiji09
7981d8835b Function comments 2014-06-08 11:23:09 +05:30
hoiji09
0972caa573 Function comments made to follow conventions 2014-06-08 11:21:23 +05:30
hoiji09
313e99c7f3 Finer grain locking in loadInstance
Also doing double checking in the thread safe version for better performance in case of many threads.
2014-06-02 23:03:01 +05:30
hoiji09
b20c9860a3 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.
2014-06-02 22:52:28 +05:30
hoiji09
5558c7f0b1 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
2014-06-02 22:37:31 +05:30
hoiji09
1700288489 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
2014-06-02 22:23:28 +05:30
hoiji09
0e2ab604e9 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.
2014-06-02 22:17:08 +05:30
hoiji09
22a6b9014f 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.
2014-06-02 22:08:33 +05:30
hoiji09
b865666b55 Added test for opening multiple files in parallel
The test fails with a string error
2014-06-02 22:01:25 +05:30
hoiji09
343c9c54e2 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.
2014-05-28 21:02:04 +05:30
hoiji09
21aa179953 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
2014-05-28 20:54:45 +05:30
hoiji09
80d021e4cb Added thread safe loadInstanceSafely( instanceID )
It passes the test added earlier
2014-05-28 20:49:58 +05:30
hoiji09
5f38d1bd93 Added test for checking thread safety of loadInstance
The check fails with a abort comming from the parser as loadInstance is not thread safe
2014-05-28 20:46:47 +05:30
hoiji09
c6800fc9b4 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 );
2014-05-28 20:31:56 +05:30
hoiji09
4bd2682b51 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
2014-05-28 20:17:02 +05:30
hoiji09
e357da8a75 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.
2014-05-28 20:09:26 +05:30
hoiji09
97e6b9b3c6 Explicit HAVE_STD_THREAD decleration through CMake 2014-05-28 19:34:00 +05:30
hoiji09
14107427b9 Added thread-safe instance dependencies counterpart 2014-05-27 22:13:16 +05:30
hoiji09
c2aecfb649 Added HAVE_STD_THREAD on mutex declerations also. 2014-05-27 19:22:58 +05:30
hoiji09
f511696c5d 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
2014-05-27 18:45:38 +05:30
hoiji09
705483d0ab Catered to unsigned-signed overflow 2014-05-27 17:28:54 +05:30
hoiji09
ab3c2d4717 Commented on which step file was used in the test 2014-05-23 11:27:03 +05:30
hoiji09
88545df537 Added thread safe count and getInstances function
The functions are countInstancesSafely( string type ) and getInstancesSafely( string type )
2014-05-23 11:18:48 +05:30
hoiji09
cc3c4ec705 Added test for checking thread safety.
The test checks for thread safety in retrieving the list of instances of a particular type.
2014-05-23 11:04:17 +05:30
hoiji09
8a528de01c Removed Redundant Code and better formatting. 2014-05-23 10:44:52 +05:30
hoiji09
c0e26cda16 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.
2014-05-19 19:08:50 +05:30
hoiji09
a47447a7f9 Improved thread safety test
Moved mgr->getFwdRefs() inside the thread workload
2014-05-19 10:18:22 +05:30
hoiji09
8b8cde064f Added Test for checking thread safety
Currently it only checks whether concurrent read accesses to _fwdInstanceRefs & _revInstanceRefs are thread safe our not.
2014-05-19 09:33:05 +05:30
hoiji09
025ffba8fd Removed signed-unsigned comparison warning 2014-05-13 17:53:42 +05:30
86 changed files with 3308 additions and 1401 deletions

View file

@ -29,9 +29,15 @@ 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)
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
@ -99,6 +105,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})

View file

@ -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
)
@ -35,6 +37,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)

View file

@ -41,99 +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;
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;
}
}
void SDAI_Application_instance__set::Insert( SDAI_Application_instance_ptr v, int index ) {
SDAI_Application_instance_ptr * spot;
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;
}
void SDAI_Application_instance__set::Append( SDAI_Application_instance_ptr v ) {
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;
}
void SDAI_Application_instance__set::Remove( int index ) {
if( 0 <= index && index < _count ) {
--_count;
SDAI_Application_instance_ptr * spot = &_buf[index];
memmove( spot, spot + 1, ( _count - index )*sizeof( SDAI_Application_instance_ptr ) );
}
}
void SDAI_Application_instance__set::Remove( SDAI_Application_instance_ptr a ) {
int index = Index( a );
if( !( index < 0 ) ) {
Remove( index );
}
}
int SDAI_Application_instance__set::Index( SDAI_Application_instance_ptr v ) {
for( int i = 0; i < _count; ++i ) {
if( _buf[i] == v ) {
return i;
}
}
return -1;
}
SDAI_Application_instance_ptr & SDAI_Application_instance__set::operator[]( int index ) {
Check( index );
// _count = max(_count, index+1);
_count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) );
return _buf[index];
return ( SDAI_Application_instance_ptr & )SDAI__set::operator[]( index );
}
int
SDAI_Application_instance__set::Count() {
return _count;
}
void
SDAI_Application_instance__set::Clear() {
_count = 0;
}

View file

@ -37,26 +37,12 @@ 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;
};
#endif

View file

@ -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 );
}

View file

@ -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;

View file

@ -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

View file

@ -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 );
}
/*****************************************************************************/

View file

@ -37,32 +37,14 @@
//#include <EntityExtent.h>
*/
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;

View file

@ -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 );
}

View file

@ -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 );
}

View file

@ -3,30 +3,13 @@
#include <sc_export.h>
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 *

153
src/cldai/sdaiSet.cc Normal file
View file

@ -0,0 +1,153 @@
#include <memory.h>
#include <math.h>
#include <sdai.h>
#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;
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 ) {
_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 ) {
mtxP->lock();
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;
mtxP->unlock();
}
void SDAI__set::Append( SDAI_ptr v ) {
mtxP->lock();
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;
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();
}
// 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;
for( int i = 0; i < _count; ++i ) {
if( _buf[i] == v ) {
index = i;
break;
}
}
mtxP->unlock();
return index;
}
SDAI_ptr
SDAI__set::retrieve( int index ) {
return operator[]( index );
}
SDAI_ptr & SDAI__set::operator[]( int index ) {
mtxP->lock();
Check( index );
_count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) );
SDAI_ptr & sp = _buf[index];
mtxP->unlock();
return sp;
}
int
SDAI__set::Count() {
return _count;
}
int
SDAI__set::is_empty() {
return _count;
}
void
SDAI__set::Clear() {
mtxP->lock();
_count = 0;
mtxP->unlock();
}

46
src/cldai/sdaiSet.h Normal file
View file

@ -0,0 +1,46 @@
#ifndef SDAISET_H
#define SDAISET_H 1
#include <sc_mutex.h>
#include <sc_export.h>
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 );
void Remove( SDAI_ptr );
int Index( SDAI_ptr );
void Clear();
int Count();
private:
void Check( int index );
private:
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:
};
#endif

View file

@ -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)

View file

@ -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"
@ -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 );
}
@ -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<char *>( 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<char *>( 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<char *>( 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<char *>( keywd.c_str() ), "ENDSCOPE", 8 ) ) {
//ERROR: "ENDSCOPE" expected
SkipInstance( in, tmpbuf );
@ -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;
}
/***************************
@ -1494,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();
@ -1505,6 +1510,7 @@ void STEPfile::WriteHeader( ostream & out ) {
WriteHeaderInstance(
_headerInstances->GetMgrNode( i )->GetApplication_instance(), out );
}
_headerInstances->masterMtx.unlock();
out << "ENDSEC;\n";
}
@ -1516,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 );
@ -1523,6 +1531,8 @@ void STEPfile::WriteHeaderInstance( SDAI_Application_instance * obj, ostream & o
out << ",";
}
}
obj->attributes.mtxP->unlock();
obj->mtx.unlock();
out << ");\n";
}
@ -1584,21 +1594,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 ) {
@ -1609,7 +1623,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 );
@ -1672,26 +1687,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;
}
@ -1699,21 +1699,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 );
}
@ -1728,25 +1726,23 @@ Severity STEPfile::AppendFile( istream * in, bool useTechCor ) {
//check for "ENDSTEP;" || "END-ISO-10303-21;"
if( in2 -> good() ) {
ReadTokenSeparator( *in2 );
keywd = GetKeyword( *in2, ";", _error );
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;
}
@ -1790,6 +1786,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 ) {
@ -1819,6 +1817,7 @@ void STEPfile::WriteWorkingData( ostream & out, int writeComments ) {
break;
}
}
instances().masterMtx.unlock();
out << "ENDSEC;\n";
}

View file

@ -23,6 +23,7 @@
#include <time.h>
#include <read_func.h>
#include <sc_mutex.h>
//error reporting level
#define READ_COMPLETE 10
@ -36,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
@ -55,6 +61,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;

View file

@ -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;
@ -262,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();
}
/**

View file

@ -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 ) {
@ -73,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() {

View file

@ -33,7 +33,22 @@ include_directories(
${SC_SOURCE_DIR}/src/base/judy/src
)
SC_ADDLIB(steplazyfile "${clLazyFile_SRCS};${clLazyFile_HDRS}" "stepcore;stepdai;steputils;base")
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" )
#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 -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" )
set_target_properties(lazy_test PROPERTIES COMPILE_FLAGS "-DNO_REGISTRY" )
if(TARGET lazy_test-static)

View file

@ -3,6 +3,10 @@
#include <lazyInstMgr.h>
#include <instmgr.h>
#include <lazyTypes.h>
#include <sc_mutex.h>
#include <sc_thread.h>
/**
* \file instMgrHelper.h helper classes for the lazyInstMgr. Allows use of SDAI_Application_instance class
@ -30,6 +34,12 @@ class mgrNodeHelper: protected MgrNode {
// unsigned int c = _lim->countDataSections();
return _lim->loadInstance( _id );
}
///Thread safe counterpart of GetSTEPentity()
inline SDAI_Application_instance * GetSTEPentitySafely() {
return _lim->loadInstanceSafely( _id );
}
};
@ -42,14 +52,58 @@ class mgrNodeHelper: protected MgrNode {
class instMgrAdapter: public InstMgr {
protected:
mgrNodeHelper _mn;
mgrNodeHelper _mn; //Used in single threaded operations
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;
public:
instMgrAdapter( lazyInstMgr * lim ): InstMgr( 0 ), _mn( lim ) {}
instMgrAdapter( lazyInstMgr * lim ): InstMgr( 0 ), _mn( lim ) {
_lim = lim;
_map.clear();
}
//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;
}
}
inline mgrNodeHelper * FindFileId( int fileId ) {
_mn.setInstance( fileId );
return &_mn;
}
///Thread-safe counterpart of FindFileId( fileId ). It protects the state of mgrNodeHelper.
inline mgrNodeHelper * FindFileIdSafely( int fileId ) {
mgrNodeHelper * _myMN;
thread_id_t tid = sc_thread::getthread_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;
}
};

View file

@ -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() ) {

View file

@ -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;
@ -21,30 +22,60 @@ 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::registerDataSection( lazyDataSectionReader * sreader ) {
_dataSections.push_back( sreader );
return _dataSections.size() - 1;
sectionID lazyInstMgr::reserveDataSection() {
mtxLock( dataSectionsMtx );
sectionID sid = _dataSections.size();
_dataSections.push_back( NULL );
mtxUnlock( dataSectionsMtx );
return sid;
}
void lazyInstMgr::registerDataSection( lazyDataSectionReader * sreader, sectionID sid ) {
assert( _dataSections[sid] == NULL );
mtxLock( dataSectionsMtx );
_dataSections[sid] = sreader;
mtxUnlock( dataSectionsMtx );
}
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?
@ -52,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;
@ -93,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?!
@ -114,23 +159,25 @@ 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 {
} else if( !inst ) {
std::cerr << "Instance #" << id << " not found in any section." << std::endl;
}
mtxUnlock( instanceStreamPosMtx );
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 ) {
@ -143,7 +190,7 @@ instanceSet * lazyInstMgr::instanceDependencies( instanceID id ) {
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() );
}
@ -155,3 +202,74 @@ instanceSet * lazyInstMgr::instanceDependencies( instanceID id ) {
return checkedDependencies;
}
instanceSet * lazyInstMgr::instanceDependencies( instanceID id ) {
return instanceDependenciesHelper( id, getFwdRefs() );
}
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();
instanceRefs_t * myFwdRefsCopy = new instanceRefs_t( _fwdInstanceRefs );
fwdRefsMtx.unlock();
return myFwdRefsCopy;
}
instanceRefs_t * lazyInstMgr::getRevRefsSafely() {
revRefsMtx.lock();
instanceRefs_t * myRevRefsCopy = new instanceRefs_t( _revInstanceRefs );
revRefsMtx.unlock();
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();
}
SDAI_Application_instance * lazyInstMgr::loadInstanceSafely( instanceID id ) {
assert( _mainRegistry && "Main registry has not been initialized. Do so with initRegistry() or setRegistry()." );
SDAI_Application_instance * sdaiInst;
mtxLock( loadInstanceMtx );
sdaiInst = _instancesLoaded.find( id );
mtxUnlock( loadInstanceMtx );
if( !sdaiInst ) {
sdaiInst = loadInstance( id );
}
return sdaiInst;
}
instanceSet * lazyInstMgr::instanceDependenciesSafely( instanceID id ) {
return instanceDependenciesHelper( id, getFwdRefsSafely() );
}

View file

@ -9,6 +9,8 @@
#include "lazyFileReader.h"
#include "lazyTypes.h"
#include "sc_mutex.h"
#include "Registry.h"
#include "sc_memmgr.h"
@ -62,6 +64,9 @@ class lazyInstMgr {
instMgrAdapter * _ima;
/** mutexes for mutual exclusion */
sc_mutex fwdRefsMtx, revRefsMtx, instanceTypesMtx, loadInstanceMtx, instanceStreamPosMtx, dataSectionsMtx, filesMtx;
public:
lazyInstMgr();
~lazyInstMgr();
@ -80,6 +85,7 @@ class lazyInstMgr {
instanceRefs_t * getRevRefs() {
return & _revInstanceRefs;
}
/// returns two iterators delimiting the instances that match `type`
instanceTypes_t::cvector * getInstances( std::string type ) { /*const*/
return _instanceTypes->find( type.c_str() );
@ -92,6 +98,7 @@ class lazyInstMgr {
}
return v->size();
}
instancesLoaded_t * getHeaderInstances( fileID file ) {
return _files[file]->getHeaderInstances();
}
@ -139,7 +146,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() {
@ -148,8 +160,49 @@ 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 );
/// thread safe counterpart of openFile();
void openFileSafely( std::string fname );
/// 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 );
/// Thread safe counterpart of loadInstance( instanceID )
SDAI_Application_instance * loadInstanceSafely( instanceID id );
/// Thread safe counterpart of instanceDependencies( instanceID )
instanceSet * instanceDependenciesSafely( instanceID id );
void mtxLock( sc_mutex &mtx ) {
mtx.lock();
}
void mtxUnlock( sc_mutex &mtx ) {
mtx.unlock();
}
/// unloads all instances. (For testing purpose, not thread safe)
void unloadAllInstances() {
_loadedInstanceCount = 0;
_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

View file

@ -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 );
}

View file

@ -4,8 +4,11 @@
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <stdint.h>
# include <sc_thread.h>
#include "judyLArray.h"
#include "judySArray.h"
#include "judyL2Array.h"
@ -14,6 +17,7 @@
class SDAI_Application_instance;
class lazyDataSectionReader;
class lazyFileReader;
class mgrNodeHelper;
enum fileTypeEnum { Part21, Part28 };
// enum loadingEnum { immediate, lazy };
@ -79,6 +83,12 @@ typedef std::vector< lazyDataSectionReader * > dataSectionReaderVec_t;
// files
typedef std::vector< lazyFileReader * > lazyFileReaderVec_t;
//map thread id to mgrNodeHelper. Each thread will have only one mgrNodeHelper value.
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< thread_id_t, mgrNodeHelper * > idNodePair_t;
// type for performing actions on multiple instances
// NOTE not useful? typedef std::vector< lazyInstance > lazyInstanceVec_t;

View file

@ -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,7 +84,7 @@ 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 << " ";
}

View file

@ -0,0 +1,593 @@
#include "lazyTypes.h"
#include "lazyInstMgr.h"
#include "SdaiSchemaInit.h"
#include "instMgrHelper.h"
// Registry will be needed for checkLazyLoadingSafety & checkLazyLoadingSafetyWithAdapter checks.
#ifndef NO_REGISTRY
# include "schema.h"
#endif //NO_REGISTRY
#include <algorithm>
#ifdef HAVE_STD_THREAD
# include <thread>
#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 ) {
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 );
}
/// 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;
int i, k, instances = realRefs->size();
instanceID current;
instanceRefs_t * _refs;
for( k = 0; k < iterations; k++ ) {
_refs = forward ? mgr->getFwdRefsSafely() : mgr->getRevRefsSafely();
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).
bool checkRefsSafety( char * fileName, bool forward ) {
instanceRefs realRefs;
lazyInstMgr * mgr = new lazyInstMgr;
mgr->openFile( fileName );
if( forward ) {
std::cout << "Checking thread safety while iterating over forward references..." ;
prepareRealRefs( mgr->getFwdRefs(), realRefs );
} else {
std::cout << "Checking thread safety while iterating over backward references..." ;
prepareRealRefs( mgr->getRevRefs(), realRefs );
}
bool success[2] = { true, true };
std::thread first( iterateOverRefs, mgr, &realRefs, forward, &success[0] );
std::thread second( iterateOverRefs, mgr, &realRefs, forward, &success[1] );
first.join();
second.join();
bool pass = ( success[0] && success[1] );
if( pass ) {
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;
return pass;
}
/// Checks thread safety of getFwdRefs();
bool checkFwdRefsSafety( char * fileName ) {
return checkRefsSafety( fileName, true );
}
/// Checks thread safety of getFwdRefs();
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.
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->getInstancesSafely( commonTypes[i] );
if( !compareTypeLists( refs, (*sameTypeInstances)[i] ) ) {
break;
}
}
*success = *success && ( i == instances );
}
}
/// checks the thread safety of getInstances();
bool 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();
bool pass = ( success[0] && success[1] );
if( pass ) {
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 << 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.
/// 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++ ) {
if( useAdapter ) {
sdaiInstance = mgr->getAdapter()->FindFileIdSafely( _refs->at( i ) )->GetSTEPentitySafely();
} 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++ ) {
if( useAdapter ) {
sdaiInstance = mgr->getAdapter()->FindFileIdSafely( _refs->at( i ) )->GetSTEPentitySafely();
} 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!!!
*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;
}
#ifndef NO_REGISTRY
//checks thread safety of loadInstance. (Also of instMgrAdapter if useAdapter is TRUE)
bool checkLazyLoadingSafety( char * fileName, bool useAdapter=false ) {
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 ("<< ( useAdapter ? "with" : "without" ) << " Adapter)...";
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, useAdapter, &intraThreadSuccess[0] );
std::thread second( loadInstancesFromList, mgr, toBeLoadedOnT2, &loadedOnT2, useAdapter, &intraThreadSuccess[1] );
first.join();
second.join();
interThreadSuccess &= compareLoadedInstances( toBeLoadedOnT1, &loadedOnT1, toBeLoadedOnT2, &loadedOnT2 );
mgr->unloadAllInstances();
loadedOnT1.clear();
loadedOnT2.clear();
}
bool pass = ( intraThreadSuccess[0] && intraThreadSuccess[1] && interThreadSuccess );
if( pass ) {
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;
return pass;
}
//checks thread safety of lazyloading along with that of instMgrAdapter
bool checkLazyLoadingSafetyWithAdapter( char * fileName ) {
return checkLazyLoadingSafety( fileName, true );
}
#endif //NO_REGISTRY
/// 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->openFileSafely( fileName );
}
/// checks the thread safety by opening multiple files in parallel
bool 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;
}
}
bool pass = ( compareResult == OK );
if( pass ) {
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;
return pass;
}
/// 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 != 3 ) {
std::cerr << "Expected two argument, given " << argc - 1 << ". Exiting." << std::endl;
exit( EXIT_FAILURE );
}
bool pass = true;
pass &= checkFwdRefsSafety( argv[1] );
pass &= checkRevRefsSafety( argv[1] );
pass &= checkTypeInstancesSafety( argv[1] );
#ifndef NO_REGISTRY
pass &= checkLazyLoadingSafety( argv[1] );
pass &= checkLazyLoadingSafetyWithAdapter( argv[1] );
#endif //NO_REGISTRY
pass &= checkOpenFileSafety( argv[1], argv[2] );
if( pass ) {
exit( EXIT_SUCCESS );
}
exit( EXIT_FAILURE );
}

View file

@ -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;
@ -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;

View file

@ -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();

View file

@ -81,10 +81,9 @@ 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;
//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();
str.reserve( 100 );
skipWS();
@ -97,17 +96,22 @@ 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();
}
return str.c_str();
}
/// search forward in the file for the end of the instance. Start position should
@ -251,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;
@ -295,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;
@ -321,7 +326,9 @@ STEPcomplex * sectionReader::CreateSubSuperInstance( const Registry * reg, insta
std::vector<std::string *> 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();

View file

@ -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 );

View file

@ -69,6 +69,22 @@ 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" )
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}
DESTINATION ${INCLUDE_INSTALL_DIR}/stepcode/clstepcore)

View file

@ -21,269 +21,143 @@
#include "sc_memmgr.h"
Explicit_item_id__set::Explicit_item_id__set( int defaultSize ) {
Dictionary_instance__set::Dictionary_instance__set( int defaultSize ) {
_bufsize = defaultSize;
_buf = new Explicit_item_id_ptr[_bufsize];
_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;
mtx.lock();
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;
}
mtx.unlock();
}
void Dictionary_instance__set::Insert( Dictionary_instance_ptr v, int index ) {
Dictionary_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( Dictionary_instance_ptr ) );
} else {
Check( index );
spot = &_buf[index];
}
*spot = v;
++_count;
mtx.unlock();
}
void Dictionary_instance__set::Append( Dictionary_instance_ptr v ) {
Dictionary_instance_ptr * spot;
mtx.lock();
int index = _count;
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;
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 ) {
index = i;
break;
}
}
mtx.unlock();
return index;
}
Dictionary_instance_ptr & Dictionary_instance__set::operator[]( int index ) {
mtx.lock();
Check( index );
_count = ( ( _count > index + 1 ) ? _count : ( index + 1 ) );
Dictionary_instance_ptr & dip = _buf[index];
mtx.unlock();
return dip;
}
int Dictionary_instance__set::Count() {
return _count;
}
void Dictionary_instance__set::Clear() {
_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;
return ( Explicit_item_id_ptr & )Dictionary_instance__set::operator[]( index );
}
///////////////////////////////////////////////////////////////////////////////
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( int defaultSize ) : Dictionary_instance__set( defaultSize ) {
}
Implicit_item_id__set::~Implicit_item_id__set() {
delete[] _buf;
}
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_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 );
}
///////////////////////////////////////////////////////////////////////////////
@ -322,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;
@ -341,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
@ -478,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;
@ -487,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;
@ -500,6 +386,7 @@ void Schema::GenerateEntitiesExpress( ostream & out ) const {
out << endl << ed->GenerateExpress( tmp );
ed = edi.NextEntityDesc();
}
_entList.mtxP->unlock();
}
///////////////////////////////////////////////////////////////////////////////
@ -757,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
@ -781,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" );
@ -827,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();
@ -845,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();
@ -876,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();
@ -892,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() ) {
@ -919,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
@ -949,6 +847,7 @@ const char * EntityDescriptor::GenerateExpress( std::string & buf ) const {
buf.append( "\n" );
}
}
_where_rules->mtx.unlock();
}
buf.append( "END_ENTITY;\n" );
@ -958,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;
@ -970,6 +870,8 @@ const char * EntityDescriptor::QualifiedName( std::string & s ) const {
count++;
ed = edi.NextEntityDesc();
}
_supertypes.mtxP->unlock();
if( count > 1 ) {
s.append( "&" );
}
@ -987,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;
}
@ -1025,96 +929,24 @@ 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() {
mtx.lock();
for( int i = 0; i < _count ; i ++ ) {
delete _buf[i];
delete ( Where_rule_ptr )_buf[i];
}
_count = 0;
mtx.unlock();
}
///////////////////////////////////////////////////////////////////////////////
@ -1134,96 +966,24 @@ 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() {
mtx.lock();
for( int i = 0; i < _count; i ++ ) {
delete _buf[i];
delete ( Uniqueness_rule_ptr )_buf[i];
}
_count = 0;
mtx.unlock();
}
///////////////////////////////////////////////////////////////////////////////
@ -1249,6 +1009,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;
@ -1256,9 +1018,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;
@ -1266,99 +1030,29 @@ void Global_rule::where_rules_( const Where_rule__list_var & wrl ) {
delete _where_rules;
}
_where_rules = wrl;
mtx.unlock();
}
///////////////////////////////////////////////////////////////////////////////
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() {
mtx.lock();
for( int i = 0; i < _count; i ++ ) {
delete _buf[i];
delete ( Global_rule_ptr )_buf[i];
}
_count = 0;
mtx.unlock();
}
@ -1396,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
@ -1420,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" );
@ -1704,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;
}
/**
@ -1721,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;
}
/**
@ -1758,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;
}
///////////////////////////////////////////////////////////////////////////////

View file

@ -40,6 +40,7 @@ enum AggrBoundTypeEnum {
#include <baseType.h>
#include <dictdefs.h>
#include <Str.h>
#include <sc_mutex.h>
// defined and created in Registry.inline.cc
extern SC_CORE_EXPORT const TypeDescriptor * t_sdaiINTEGER;
@ -63,6 +64,33 @@ 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();
sc_recursive_mutex mtx;
private:
virtual void Check( int index );
protected:
Dictionary_instance_ptr * _buf;
int _bufsize;
int _count;
};
///////////////////////////////////////////////////////////////////////////////
class SC_CORE_EXPORT TypeDescLinkNode : public SingleLinkNode {
@ -286,25 +314,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;
@ -338,25 +353,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;
@ -423,25 +425,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;
@ -497,31 +486,23 @@ 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;
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
@ -566,25 +547,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;
@ -630,25 +600,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;
@ -676,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;

View file

@ -0,0 +1,229 @@
#include "instmgr.h"
#include "ExpDict.h"
#include "sdaiApplication_instance.h"
#include <baseType.h>
#ifdef HAVE_STD_THREAD
# include <thread>
#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->EntityKeywordCount( str ) << " and " << mgr2->EntityKeywordCount( str ) << 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.
bool 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 = 1000;
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;
}
}
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.
bool 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 = 1000;
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;
}
}
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 addition and deletion of different instances to the same InstMgr simultaneosly.
bool 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 = 1000;
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;
}
}
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;
}
int main( int , char ** ) {
bool pass = true;
assert( dummyEDescNames.size() % 4 == 0 && "dummyEDescNames should be a multiple of 4 ");
pass &= checkInstMgrAppendOnlyThreadSafety();
pass &= checkInstMgrDeleteOnlyThreadSafety();
pass &= checkInstMgrAppendDeleteThreadSafety();
if( pass ) {
exit( EXIT_SUCCESS );
}
exit( EXIT_FAILURE );
}

View file

@ -18,6 +18,7 @@
#include <sc_hash.h>
#include <Str.h>
#include <complexSupport.h>
#include <sc_mutex.h>
typedef struct Hash_Table * HashTable;
@ -37,6 +38,10 @@ 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
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
// file Registry.inline.cc

View file

@ -113,22 +113,28 @@ 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
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();
}
/**
@ -145,12 +151,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.
@ -181,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() {
@ -209,19 +228,25 @@ 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();
}
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();
}
/**
@ -234,12 +259,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 +298,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,19 +307,24 @@ void Registry::RemoveEntity( const char * n ) {
}
tmp.key = ( char * ) n;
SC_HASHsearch( primordialSwamp, &tmp, HASH_DELETE ) ? --entity_cnt : 0;
entityMtx.unlock();
}
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();
}
/**
@ -301,17 +334,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 +374,9 @@ int Registry::GetEntityCnt() {
}
void Registry::ResetEntities() {
entityMtx.lock();
SC_HASHlistinit( primordialSwamp, &cur_entity );
entityMtx.unlock();
}
@ -349,7 +388,9 @@ const EntityDescriptor * Registry::NextEntity() {
}
void Registry::ResetSchemas() {
schemaMtx.lock();
SC_HASHlistinit( active_schemas, &cur_schema );
schemaMtx.unlock();
}
const Schema * Registry::NextSchema() {

View file

@ -0,0 +1,338 @@
#include <string>
#include <vector>
#include <iostream>
#ifdef HAVE_STD_THREAD
# include <thread>
#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.
bool 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;
}
}
bool pass = ( i == iterations );
if( pass ) {
std::cout << "...PASS!" << std::endl;
} else {
std::cout << "...FAIL!" << std::endl;
}
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.
bool 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;
}
}
bool pass = ( i == iterations );
if( pass ) {
std::cout << "...PASS!" << std::endl;
} else {
std::cout << "...FAIL!" << std::endl;
}
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.
bool 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;
}
}
bool pass = ( i == iterations );
if( pass ) {
std::cout << "...PASS!" << std::endl;
} else {
std::cout << "...FAIL!" << std::endl;
}
std::cout << std::endl;
delete regExpected;
return pass;
}
bool checkRegistryEntityAddOnlyThreadSafety() {
return checkRegistryAddOnlyThreadSafety( ENTITY );
}
bool checkRegistrySchemaAddOnlyThreadSafety() {
return checkRegistryAddOnlyThreadSafety( SCHEMA );
}
bool checkRegistryTypeAddOnlyThreadSafety() {
return checkRegistryAddOnlyThreadSafety( TYPE );
}
bool checkRegistryEntityRemoveOnlyThreadSafety() {
return checkRegistryRemoveOnlyThreadSafety( ENTITY );
}
bool checkRegistrySchemaRemoveOnlyThreadSafety() {
return checkRegistryRemoveOnlyThreadSafety( SCHEMA );
}
bool checkRegistryTypeRemoveOnlyThreadSafety() {
return checkRegistryRemoveOnlyThreadSafety( TYPE );
}
bool checkRegistryEntityAddRemoveThreadSafety() {
return checkRegistryAddRemoveThreadSafety( ENTITY );
}
bool checkRegistrySchemaAddRemoveThreadSafety() {
return checkRegistryAddRemoveThreadSafety( SCHEMA );
}
bool checkRegistryTypeAddRemoveThreadSafety() {
return 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();
bool pass = true;
pass &= checkRegistryEntityAddOnlyThreadSafety();
pass &= checkRegistryEntityRemoveOnlyThreadSafety();
pass &= checkRegistryEntityAddRemoveThreadSafety();
pass &= checkRegistrySchemaAddOnlyThreadSafety();
pass &= checkRegistrySchemaRemoveOnlyThreadSafety();
pass &= checkRegistrySchemaAddRemoveThreadSafety();
pass &= checkRegistryTypeAddOnlyThreadSafety();
pass &= checkRegistryTypeRemoveOnlyThreadSafety();
pass &= checkRegistryTypeAddRemoveThreadSafety();
if( pass ) {
exit( EXIT_SUCCESS );
}
exit( EXIT_FAILURE );
}

View file

@ -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 ) {
@ -391,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;
@ -399,6 +393,8 @@ STEPaggregate & GenericAggregate::ShallowCopy( const STEPaggregate & a ) {
AddNode( copy );
next = next->NextNode();
}
a.mtxP->unlock();
if( head ) {
_null = 0;
} else {
@ -579,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 {
@ -817,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 {
@ -937,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;
@ -945,6 +948,8 @@ STEPaggregate & StringAggregate::ShallowCopy( const STEPaggregate & a ) {
AddNode( copy );
next = next->NextNode();
}
a.mtxP->unlock();
if( head ) {
_null = 0;
} else {
@ -1042,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;
@ -1050,6 +1056,8 @@ STEPaggregate & BinaryAggregate::ShallowCopy( const STEPaggregate & a ) {
AddNode( copy );
next = next->NextNode();
}
a.mtxP->unlock();
if( head ) {
_null = 0;
} else {
@ -1142,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;
@ -1151,6 +1160,8 @@ STEPaggregate & EnumAggregate::ShallowCopy( const STEPaggregate & a ) {
AddNode( to );
tmp = ( const EnumNode * ) tmp -> NextNode();
}
a.mtxP->unlock();
if( head ) {
_null = 0;
} else {
@ -1306,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;
@ -1315,6 +1327,8 @@ STEPaggregate & RealAggregate::ShallowCopy( const STEPaggregate & a ) {
AddNode( to );
tmp = ( const RealNode * ) tmp -> NextNode();
}
a.mtxP->unlock();
if( head ) {
_null = 0;
} else {
@ -1339,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;
@ -1348,6 +1363,8 @@ STEPaggregate & IntAggregate::ShallowCopy( const STEPaggregate & a ) {
AddNode( to );
tmp = ( const IntNode * ) tmp -> NextNode();
}
a.mtxP->unlock();
if( head ) {
_null = 0;
} else {

View file

@ -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() ) {

View file

@ -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();
}

View file

@ -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,18 +201,19 @@ void STEPcomplex::AssignDerives() {
} else {
attrNm = nm;
}
scomp2 = head;
while( scomp2 && !a ) {
if( scomp1 != scomp2 ) {
scomp2->MakeDerived( attrNm );
a = scomp2->GetSTEPattribute( attrNm );
}
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 );
scomp2 = scomp2->sc;
}
}
// increment attr
attrPtr = ( AttrDescLinkNode * )attrPtr->NextNode();
}
attrList->mtxP->unlock();
scomp1 = scomp1->sc;
}
}
@ -215,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;
@ -226,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;
@ -268,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
@ -448,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;
@ -535,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 );
@ -592,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 );
@ -614,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 ) {

View file

@ -14,12 +14,20 @@ typedef std::list<void *> STEPcomplex_attr_data_list;
typedef std::list<void *>::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,

View file

@ -12,8 +12,10 @@
#include <SingleLinkList.h>
#include "sc_memmgr.h"
#include <assert.h>
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();
}

View file

@ -13,6 +13,7 @@
*/
#include <sc_export.h>
#include <sc_mutex.h>
class SC_CORE_EXPORT SingleLinkList {
@ -25,6 +26,9 @@ class SC_CORE_EXPORT SingleLinkList {
SingleLinkNode * tail;
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 (where another object might lock/unlock them)
virtual SingleLinkNode * NewNode();
virtual void AppendNode( SingleLinkNode * );

View file

@ -21,19 +21,23 @@ SingleLinkNode::NextNode() const {
SingleLinkList::SingleLinkList()
: head( 0 ), tail( 0 ) {
mtxP = new sc_recursive_mutex();
}
SingleLinkList::~SingleLinkList() {
Empty();
delete mtxP;
}
void SingleLinkList::Empty() {
mtxP->lock();
SingleLinkNode * tmp = head;
while( tmp ) {
tmp = head -> NextNode();
delete head;
head = tmp;
}
mtxP->unlock();
}
SingleLinkNode * SingleLinkList::NewNode() {
@ -51,9 +55,11 @@ int SingleLinkList::EntryCount() const {
int entryCount = 0;
SingleLinkNode * entryPtr = head;
mtxP->lock();
while( entryPtr != 0 ) {
entryPtr = entryPtr->NextNode();
entryCount++;
}
mtxP->unlock();
return entryCount;
}

View file

@ -5,6 +5,7 @@
#include "ExpDict.h"
#include <queue>
#include <assert.h>
#include <sc_mutex.h>
/** 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,56 +120,75 @@ 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 {
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
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 ) {

View file

@ -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->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();
}
if( cl && *cl == name ) {
return cl;
}
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;
}

View file

@ -19,6 +19,7 @@
#include <fstream>
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;
@ -138,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;
@ -193,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;
@ -207,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 & );
@ -330,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();
}
@ -388,6 +408,8 @@ class SC_CORE_EXPORT ComplexList {
*/
AndList * head;
ComplexList * next;
sc_mutex mtx; ///< For hand over hand locking
int Dependent() {
return dependent;
}
@ -418,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

View file

@ -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.
}

View file

@ -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;
}

View file

@ -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:

View file

@ -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;
}
@ -93,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;
}
@ -101,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;
@ -115,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() ) {
@ -123,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;
}

View file

@ -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();
}

View file

@ -37,13 +37,14 @@ static int debug_level = 3;
void
InstMgr::PrintSortedFileIds() {
MgrNode * mn = 0;
int count = InstanceCount();
masterMtx.lock();
int i = 0;
for( i = 0; i < count; i++ ) {
mn = ( MgrNode * )( ( *sortedMaster )[i] );
cout << i << " " << mn->GetFileId() << endl;
std::map<int, MgrNode *>::iterator it;
for( it = sortedMaster->begin(); it!=sortedMaster->end(); ++it ) {
std::cout << i << " " << it->first << std::endl;
i = i+1;
}
masterMtx.unlock();
}
InstMgr::InstMgr( int ownsInstances )
@ -59,7 +60,6 @@ InstMgr::~InstMgr() {
master->ClearEntries();
}
sortedMaster->clear();
std::map<int, MgrNode *>::iterator iter;
delete master;
delete sortedMaster;
@ -68,15 +68,19 @@ InstMgr::~InstMgr() {
///////////////////////////////////////////////////////////////////////////////
void InstMgr::ClearInstances() {
masterMtx.lock();
master->ClearEntries();
sortedMaster->clear();
maxFileId = -1;
masterMtx.unlock();
}
void InstMgr::DeleteInstances() {
masterMtx.lock();
master->DeleteEntries();
sortedMaster->clear();
maxFileId = -1;
masterMtx.unlock();
}
///////////////////////////////////////////////////////////////////////////////
@ -96,6 +100,8 @@ InstMgr::VerifyInstances( ErrorDescriptor & err ) {
int errorCount = 0;
char errbuf[BUFSIZ];
masterMtx.lock();
int n = InstanceCount();
MgrNode * mn;
SDAI_Application_instance * se;
@ -159,16 +165,23 @@ InstMgr::VerifyInstances( ErrorDescriptor & err ) {
err.GreaterSeverity( SEVERITY_INCOMPLETE );
}
masterMtx.unlock();
return rval;
}
///////////////////////////////////////////////////////////////////////////////
MgrNode * InstMgr::FindFileId( int fileId ) {
MgrNode * mn = 0;
masterMtx.lock();
std::map<int, MgrNode *>::iterator it;
it=sortedMaster->find(fileId);
if (it == sortedMaster->end()) return ( MgrNode * )0;
return it->second;
it=sortedMaster->find( fileId );
if( it != sortedMaster->end() ) {
mn = it->second;
}
masterMtx.unlock();
return mn;
}
///////////////////////////////////////////////////////////////////////////////
@ -208,10 +221,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
@ -232,14 +247,18 @@ MgrNode * InstMgr::Append( SDAI_Application_instance * se, stateEnum listState )
" doesn't have state information" << endl;
master->Append( mn );
(*sortedMaster)[mn->GetFileId()] = mn;
//PrintSortedFileIds();
masterMtx.unlock();
return mn;
}
///////////////////////////////////////////////////////////////////////////////
// Is common to both the the avalaible API
void InstMgr::Delete( MgrNode * node ) {
// delete the node from its current state list
masterMtx.lock();
node->Remove();
// remove the node from the sorted master array
@ -250,12 +269,15 @@ void InstMgr::Delete( MgrNode * node ) {
master->Remove( index );
delete node;
masterMtx.unlock();
}
///////////////////////////////////////////////////////////////////////////////
void InstMgr::Delete( SDAI_Application_instance * se ) {
masterMtx.lock();
Delete( FindFileId( se->StepFileId() ) );
masterMtx.unlock();
}
///////////////////////////////////////////////////////////////////////////////
@ -307,6 +329,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 );
@ -316,6 +340,7 @@ InstMgr::EntityKeywordCount( const char * name ) {
++count;
}
}
masterMtx.unlock();
return count;
}
@ -323,7 +348,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 {
@ -333,12 +358,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 );
}
///////////////////////////////////////////////////////////////////////////////
@ -358,43 +378,49 @@ 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 );
se = node->GetApplication_instance();
if( !strcmp( se->EntityName(),
PrettyTmpName( entityKeyword ) ) ) {
masterMtx.unlock();
return se;
}
}
masterMtx.unlock();
return ENTITY_NULL;
}
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 );
}
///////////////////////////////////////////////////////////////////////////////
void *
InstMgr::GetSEE( int index ) {
MgrNode * mn = ( MgrNode * )( *master )[index];
MgrNode * mn = ( MgrNode * )master->GetGenNode( index );
if( mn ) {
return mn->SEE();
} else {
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;
}

View file

@ -38,6 +38,7 @@
#include <dispnodelist.h>
#include <mgrnodearray.h>
#include <sc_mutex.h>
class SC_CORE_EXPORT InstMgr {
protected:
@ -51,6 +52,8 @@ class SC_CORE_EXPORT InstMgr {
// StateList *master; // this will be an sorted array of ptrs to MgrNodes
public:
sc_recursive_mutex masterMtx; // is public as it is used in STEPfile
InstMgr( int ownsInstances = 0 );
virtual ~InstMgr();
@ -73,8 +76,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];
}
@ -110,6 +115,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();

View file

@ -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;
}
@ -85,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
@ -115,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;
}
@ -149,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,

View file

@ -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 );
}
}

View file

@ -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,20 +98,32 @@ 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 ) {
mtx.lock();
int index = Insert( gn, _count );
mtx.unlock();
return index;
}
/*****************************************************************************/
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;
@ -113,6 +131,7 @@ void MgrNodeArray::Remove( int index ) {
( ( MgrNode * )_buf[i] )->ArrayIndex( i );
}
}
mtx.unlock();
}
/*****************************************************************************/
@ -121,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;
}
@ -143,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();
}
/*****************************************************************************/
@ -182,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();
}
/*****************************************************************************/
@ -200,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;
}
@ -224,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();
@ -235,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;
}

View file

@ -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();

View file

@ -40,34 +40,41 @@ 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;
}
MgrNode * MgrNodeList::FindFileId( int fileId ) {
MgrNode * mn = ( MgrNode * )head->next;
return FindFileId( fileId, ( MgrNode * )head );
}
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;
}

View file

@ -36,14 +36,15 @@ 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
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:

View file

@ -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;
@ -196,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

View file

@ -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;
}
/**
@ -78,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
@ -116,6 +121,7 @@ MatchType AndOrList::matchNonORs( EntNode * ents ) {
child = child->nextNot( OR );
}
setViableVal( ents );
ents->sharedMtxP->unlock();
return viable;
}
@ -126,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.
}
@ -140,5 +148,6 @@ MatchType AndList::matchNonORs( EntNode * ents ) {
// we'll catch it in setViableVal() called below.
}
setViableVal( ents );
ents->sharedMtxP->unlock();
return viable;
}

View file

@ -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;
}

View file

@ -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 );
@ -671,23 +678,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 +703,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<char *>( str.c_str() );
return;
}
if( !in.good() ) {
break; //BUG: should do something on eof()
@ -712,7 +716,6 @@ const char * GetKeyword( istream & in, const char * delims, ErrorDescriptor & er
in.get( c );
}
in.putback( c );
return const_cast<char *>( str.c_str() );
}
/**

View file

@ -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 );

View file

@ -154,6 +154,8 @@ typedef char * SDAI_Time_stamp;
typedef char * SDAI_Entity_name;
typedef char * SDAI_Schema_name;
#include <sdaiSet.h> //A superclass for many of the *__set classes
#include <sdaiString.h>
#include <sdaiBinary.h>

View file

@ -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;
}
}
@ -72,6 +72,8 @@ 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";
@ -82,36 +84,43 @@ 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;
}
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 ) {
@ -126,30 +135,40 @@ 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 {
SDAI_Application_instance * link = nextMiEntity;
SDAI_Application_instance * linkTrailing = 0;
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
SDAI_Application_instance * SDAI_Application_instance::GetMiEntity( char * entName ) {
SDAI_Application_instance * SDAI_Application_instance::GetMiEntity( const char * entName ) {
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() );
@ -161,9 +180,12 @@ SDAI_Application_instance * SDAI_Application_instance::GetMiEntity( char * entNa
}
// search alternate parent path since didn't find it in this one.
if( nextMiEntity ) {
return nextMiEntity->GetMiEntity( entName );
nextMiEntity->mtx.lock(); //lock is acquired increasing order
mie = nextMiEntity->GetMiEntity( entName );
nextMiEntity->mtx.unlock();//locks are released in the reverse order
}
return 0;
mtx.unlock();
return mie;
}
@ -178,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() ) ) {
@ -188,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;
}
@ -208,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();
@ -227,14 +256,18 @@ 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 {
if( !eDesc ) {
return NULL;
const char * en = NULL;
mtx.lock();
if( eDesc ) {
en = eDesc->Name( schnm );
}
return eDesc->Name( schnm );
mtx.unlock();
return en;
}
/**
@ -242,10 +275,13 @@ 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;
mtx.lock();
if( eDesc ) {
edA = ( eDesc->IsA( ed ) );
}
return ( eDesc->IsA( ed ) );
mtx.unlock();
return edA;
}
/**
@ -254,26 +290,35 @@ 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();
}
attributes.mtxP->lock();
int n = attributes.list_length();
for( int i = 0 ; i < n; i++ ) {
if( !( attributes[i].aDesc->AttrType() == AttrType_Redefining ) )
error->GreaterSeverity( attributes[i].ValidLevel(
attributes[i].asStr().c_str(), &err, im, 0 ) );
}
return error->severity();
Severity sev = error->severity();
attributes.mtxP->unlock();
mtx.unlock();
return sev;
}
/**
* clears all attr's errors
*/
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();
}
/**
@ -296,6 +341,8 @@ void SDAI_Application_instance::beginSTEPwrite( ostream & out ) {
out << "begin STEPwrite ... \n" ;
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
@ -303,6 +350,8 @@ void SDAI_Application_instance::beginSTEPwrite( ostream & out ) {
( *( attributes[i].ptr.c ) ) -> STEPwrite();
}
}
attributes.mtxP->unlock();
mtx.unlock();
}
/**************************************************************//**
@ -321,6 +370,8 @@ 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++ ) {
@ -331,6 +382,8 @@ void SDAI_Application_instance::STEPwrite( ostream & out, const char * currSch,
( attributes[i] ).STEPwrite( out, currSch );
}
}
attributes.mtxP->unlock();
mtx.unlock();
out << ");\n";
}
@ -344,6 +397,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;
}
@ -358,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++ ) {
@ -376,6 +431,8 @@ void SDAI_Application_instance::WriteValuePairs( ostream & out,
}
}
out << endl;
attributes.mtxP->unlock();
mtx.unlock();
}
@ -392,6 +449,8 @@ 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();
attributes.mtxP->lock();
int n = attributes.list_length();
for( int i = 0 ; i < n; i++ ) {
@ -404,6 +463,8 @@ const char * SDAI_Application_instance::STEPwrite( std::string & buf, const char
}
}
buf.append( ");" );
attributes.mtxP->unlock();
mtx.unlock();
return const_cast<char *>( buf.c_str() );
}
@ -411,12 +472,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();
}
/**************************************************************//**
@ -432,6 +495,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(),
@ -439,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",
@ -448,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
@ -459,7 +525,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();
}
/**************************************************************//**
@ -486,6 +552,7 @@ Severity SDAI_Application_instance::STEPread( int id, int idIncr,
Severity severe;
int i = 0;
mtx.lock();
ClearError( 1 );
in >> ws;
@ -498,11 +565,15 @@ 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 == ')' ) {
return _error.severity();
severe = _error.severity();
attributes.mtxP->unlock();
mtx.unlock();
return severe;
}
}
@ -576,11 +647,11 @@ 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 ) {
attributes.mtxP->unlock();
mtx.unlock();
return severe;
}
} else if( c == ')' ) {
while( i < n - 1 ) {
@ -590,13 +661,17 @@ 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();
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
@ -626,7 +701,9 @@ 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();
mtx.unlock();
return severe;
}
/// read an entity reference and return a pointer to the SDAI_Application_instance
@ -890,13 +967,17 @@ Severity EntityValidLevel( const char * attrValue, // string contain entity ref
** \Returns reference to an attribute pointer
******************************************************************/
STEPattribute * SDAI_Application_instance::NextAttribute() {
STEPattribute * sa = 0;
mtx.lock();
attributes.mtxP->lock();
int i = AttributeCount();
++_cur;
if( i < _cur ) {
return 0;
if( i >= _cur ) {
sa = &attributes [_cur - 1];
}
return &attributes [_cur - 1];
attributes.mtxP->unlock();
mtx.unlock();
return sa;
}
int SDAI_Application_instance::AttributeCount() {

View file

@ -13,6 +13,7 @@
*/
#include <sc_export.h>
#include <sc_mutex.h>
///////////////////////////////////////////////////////////////////////////////
// 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;
@ -129,7 +132,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:

View file

@ -0,0 +1,206 @@
#include <assert.h>
#include <string>
#include <vector>
#include <iostream>
#ifdef HAVE_STD_THREAD
# include <thread>
#else
# error Need std::thread for this test!
#endif
#include "ExpDict.h"
#include "baseType.h"
#include "sdaiApplication_instance.h"
typedef std::vector<SDAI_Application_instance *> 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 );
}

View file

@ -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 *

View file

@ -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;
}

View file

@ -17,6 +17,8 @@ set(SC_CLUTILS_HDRS
gennodelist.h
sc_hash.h
Str.h
sc_mutex.h
sc_thread.h
)
include_directories(
@ -25,7 +27,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)

View file

@ -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() //////////////////////////////////////

View file

@ -43,6 +43,7 @@
#endif
#include <string>
#include <sc_mutex.h>
/*****************************************************************************/
@ -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

View file

@ -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 );
}
}

View file

@ -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();
};
//////////////////////////////////////////////////////////////////////////////

View file

@ -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];
@ -44,22 +35,43 @@ GenNodeArray::~GenNodeArray() {
delete [] _buf;
}
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];
@ -69,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 ) {
@ -87,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;
}

View file

@ -25,6 +25,7 @@
#include <string.h>
#include <memory.h>
#include <stdlib.h> // to get bcopy for CenterLine
#include <sc_mutex.h>
#include <gennode.h>
@ -44,7 +45,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 );
@ -63,12 +69,14 @@ 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;
};
//////////////////////////////////////////////////////////////////////////////
// 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];

View file

@ -17,25 +17,50 @@
//#include <gennode.inline.h>
#include <gennodearray.h>
#include <sc_memmgr.h>
#include <assert.h>
// inserts after existNode
void GenNodeList::InsertAfter( GenericNode * newNode,
bool GenNodeList::InsertAfter( GenericNode * newNode,
GenericNode * existNode ) {
newNode->next = existNode->next;
newNode->next->prev = newNode;
bool success = false;
assert( newNode->containingList == 0 && "Node Already in another list, remove it first" );
newNode->prev = existNode;
existNode->next = newNode;
mtx.lock();
// 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;
}
mtx.unlock();
return success;
}
// inserts before existNode
void GenNodeList::InsertBefore( GenericNode * newNode,
bool GenNodeList::InsertBefore( GenericNode * newNode,
GenericNode * existNode ) {
existNode->prev->next = newNode;
newNode->prev = existNode->prev;
bool success = false;
assert( newNode->containingList == 0 && "Node Already in another list, remove it first" );
newNode->next = existNode;
existNode->prev = newNode;
mtx.lock();
// 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;
}
mtx.unlock();
return success;
}
// inserts before the head node
@ -45,32 +70,39 @@ 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;
node->next = 0;
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();
while( gnPrev != head ) {
gnPrev->prev = 0;
gnPrev->next = 0;
gnPrev->containingList = 0;
gnPrev = gn;
gn = gn->Next();
}
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;
@ -82,4 +114,5 @@ void GenNodeList::DeleteEntries() {
}
head->next = head;
head->prev = head;
mtx.unlock();
}

View file

@ -17,6 +17,7 @@
#include <sc_export.h>
#include <iostream>
#include <sc_mutex.h>
//////////////////////////////////////////////////////////////////////////////
// class GenNodeList
@ -42,14 +43,17 @@ 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 );
protected:
GenericNode * head;
sc_recursive_mutex mtx;
};
//////////////////////////////////////////////////////////////////////////////
@ -62,6 +66,7 @@ inline GenNodeList::GenNodeList( GenericNode * headNode ) {
head = headNode;
head->next = head;
head->prev = head;
head->containingList = this;
}
#endif

51
src/clutils/sc_mutex.h Normal file
View file

@ -0,0 +1,51 @@
#ifndef SC_MUTEX_H
#define SC_MUTEX_H
#ifdef HAVE_STD_THREAD
# include <mutex>
# include <thread>
#endif //HAVE_STD_THREAD
/*
This class is a wrapper to std::mutex.
It does nothing if HAVE_STD_THREAD 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
}
};
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

34
src/clutils/sc_thread.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef SC_THREAD_H
#define SC_THREAD_H
#ifdef HAVE_STD_THREAD
# include <thread>
#endif //HAVE_STD_THREAD
#ifdef HAVE_STD_THREAD
typedef std::thread::id thread_id_t;
#else //dummy equivalent
typedef int thread_id_t;
#endif //HAVE_STD_THREAD
/*
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

View file

@ -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")