Compare commits
111 commits
master
...
mp/type-na
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba74c53ca0 | ||
|
|
5dc00ba03f | ||
|
|
1265e0c110 | ||
|
|
e73ad4df1c | ||
|
|
f0fdfd706f | ||
|
|
bac1435936 | ||
|
|
54457e567a | ||
|
|
2aa936b601 | ||
|
|
85a248a50a | ||
|
|
03981d27e0 | ||
|
|
f26cb0457d | ||
|
|
42d71188fc | ||
|
|
40c3a1c33b | ||
|
|
fa75e8cedd | ||
|
|
b17bcbdaf0 | ||
|
|
731673f827 | ||
|
|
e941244617 | ||
|
|
91efe7c0e5 | ||
|
|
02b41416fb | ||
|
|
9cbe6d1dd9 | ||
|
|
a3ce139347 | ||
|
|
e3fbc14282 | ||
|
|
9f24e3ef64 | ||
|
|
7f653188c4 | ||
|
|
3c616f1455 | ||
|
|
376dc4a482 | ||
|
|
0fe8bc3a91 | ||
|
|
dc5a00f0ea | ||
|
|
27f781477c | ||
|
|
1095f7346d | ||
|
|
3c848a5d2b | ||
|
|
79c9901662 | ||
|
|
07448b77d6 | ||
|
|
0a45ce2aa5 | ||
|
|
3fdbe460f1 | ||
|
|
2cabefa944 | ||
|
|
7233d604a1 | ||
|
|
06b7ee5823 | ||
|
|
36d4876333 | ||
|
|
cdede9ee27 | ||
|
|
66999c76aa | ||
|
|
62761ceba8 | ||
|
|
1aa1ed110f | ||
|
|
10f041c779 | ||
|
|
25081dfa0e | ||
|
|
ca7594bd75 | ||
|
|
b7cc806a57 | ||
|
|
cb1f402b15 | ||
|
|
25ec194b33 | ||
|
|
832154ae44 | ||
|
|
6e5475e37d | ||
|
|
529d3a0ca0 | ||
|
|
d169a58ec5 | ||
|
|
e951c2c71a | ||
|
|
077633aa77 | ||
|
|
58ca507d13 | ||
|
|
738d1820df | ||
|
|
391180bc2d | ||
|
|
fe33e5d5cb | ||
|
|
cf9a203988 | ||
|
|
6b97cbe906 | ||
|
|
643da31f92 | ||
|
|
e02ce60f9d | ||
|
|
3db2ab29c0 | ||
|
|
dc8e00b794 | ||
|
|
2a4d42e596 | ||
|
|
29ec4e33e1 | ||
|
|
d0e9aa9dfb | ||
|
|
d6c133f805 | ||
|
|
ad6752a80f | ||
|
|
f89e3c4999 | ||
|
|
17c720206a | ||
|
|
05360da87c | ||
|
|
d6ad56ee6c | ||
|
|
79f9473d01 | ||
|
|
f6b92019b1 | ||
|
|
65f767aa7b | ||
|
|
164c0651e1 | ||
|
|
485fad46ca | ||
|
|
d990137d1b | ||
|
|
5cba5e6a8a | ||
|
|
e67a5f51d1 | ||
|
|
7981d8835b | ||
|
|
0972caa573 | ||
|
|
313e99c7f3 | ||
|
|
b20c9860a3 | ||
|
|
5558c7f0b1 | ||
|
|
1700288489 | ||
|
|
0e2ab604e9 | ||
|
|
22a6b9014f | ||
|
|
b865666b55 | ||
|
|
343c9c54e2 | ||
|
|
21aa179953 | ||
|
|
80d021e4cb | ||
|
|
5f38d1bd93 | ||
|
|
c6800fc9b4 | ||
|
|
4bd2682b51 | ||
|
|
e357da8a75 | ||
|
|
97e6b9b3c6 | ||
|
|
14107427b9 | ||
|
|
c2aecfb649 | ||
|
|
f511696c5d | ||
|
|
705483d0ab | ||
|
|
ab3c2d4717 | ||
|
|
88545df537 | ||
|
|
cc3c4ec705 | ||
|
|
8a528de01c | ||
|
|
c0e26cda16 | ||
|
|
a47447a7f9 | ||
|
|
8b8cde064f | ||
|
|
025ffba8fd |
86 changed files with 3308 additions and 1401 deletions
|
|
@ -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})
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
153
src/cldai/sdaiSet.cc
Normal 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
46
src/cldai/sdaiSet.h
Normal 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
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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() ) {
|
||||
|
|
|
|||
|
|
@ -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() );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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 << " ";
|
||||
}
|
||||
|
|
|
|||
593
src/cllazyfile/lazy_thread_safety_test.cc
Normal file
593
src/cllazyfile/lazy_thread_safety_test.cc
Normal 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 );
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
229
src/clstepcore/InstMgr_thread_safety_test.cc
Normal file
229
src/clstepcore/InstMgr_thread_safety_test.cc
Normal 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 );
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
338
src/clstepcore/Registry_thread_safety_test.cc
Normal file
338
src/clstepcore/Registry_thread_safety_test.cc
Normal 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 );
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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() ) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 * );
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
206
src/clstepcore/sdaiApplication_instance_thread_safety_test.cc
Normal file
206
src/clstepcore/sdaiApplication_instance_thread_safety_test.cc
Normal 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 );
|
||||
}
|
||||
|
||||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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() //////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
51
src/clutils/sc_mutex.h
Normal 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
34
src/clutils/sc_thread.h
Normal 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
|
||||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in a new issue