Simplified Locking in MultList
This was done by moving the mutex from EntList to MultList.
This commit is contained in:
parent
ba74c53ca0
commit
e9d878edae
5 changed files with 26 additions and 43 deletions
|
|
@ -142,12 +142,6 @@ class SC_CORE_EXPORT EntNode {
|
|||
};
|
||||
|
||||
class SC_CORE_EXPORT EntList {
|
||||
// NOTE: The locking methodology used here assumes that a node (i.e a
|
||||
// EntList object) can neither be removed, nor can be inserted
|
||||
// between two existing nodes. If such APIs are introduced in
|
||||
// future the EntList class (or its subclasses) will no longer be
|
||||
// thread safe and can crash / deadlock under multithreaded environment.
|
||||
|
||||
friend class MultList;
|
||||
friend class JoinList;
|
||||
friend class OrList;
|
||||
|
|
@ -203,10 +197,6 @@ class SC_CORE_EXPORT EntList {
|
|||
return ( join != SIMPLE );
|
||||
}
|
||||
EntList * next, *prev;
|
||||
sc_mutex mtx;
|
||||
/** \var mtx
|
||||
* Currently only being used by the subclass MultList
|
||||
*/
|
||||
|
||||
protected:
|
||||
MatchType viable;
|
||||
|
|
@ -269,7 +259,7 @@ class SC_CORE_EXPORT MultList : public EntList {
|
|||
|
||||
public:
|
||||
MultList( JoinType j ) : EntList( j ), supertype( 0 ), numchildren( 0 ),
|
||||
childList( 0 ) {}
|
||||
childList( 0 ), mtxP( new sc_mutex() ) {;}
|
||||
~MultList();
|
||||
void setLevel( int );
|
||||
bool contains( char * );
|
||||
|
|
@ -301,6 +291,13 @@ class SC_CORE_EXPORT MultList : public EntList {
|
|||
* The children may be SIMPLE EntLists (contain entity names) or may
|
||||
* themselves be And-, Or-, or AndOrLists.
|
||||
*/
|
||||
|
||||
mutable sc_mutex * mtxP;
|
||||
/** \var mtxP
|
||||
* Protects childList, numchildren and the counters in subclass
|
||||
* OrList. NOTE: The locking methodology assumes that a childList
|
||||
* will have a unique parent.
|
||||
*/
|
||||
};
|
||||
|
||||
/** \class JoinList
|
||||
|
|
@ -346,17 +343,17 @@ class SC_CORE_EXPORT OrList : public MultList {
|
|||
void unmarkAll( EntNode * );
|
||||
bool acceptChoice( EntNode * );
|
||||
bool acceptNextChoice( EntNode * ents ) {
|
||||
mtx.lock();
|
||||
mtxP->lock();
|
||||
choice++;
|
||||
mtx.unlock();
|
||||
mtxP->unlock();
|
||||
return ( acceptChoice( ents ) );
|
||||
}
|
||||
void reset() {
|
||||
mtx.lock();
|
||||
mtxP->lock();
|
||||
choice = -1;
|
||||
choice1 = -2;
|
||||
choiceCount = 0;
|
||||
mtx.unlock();
|
||||
mtxP->unlock();
|
||||
MultList::reset();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -121,9 +121,9 @@ MatchType OrList::matchORs( EntNode * ents ) {
|
|||
if( choice == -1 ) {
|
||||
choice1 = choice = count;
|
||||
}
|
||||
mtx.lock();// protects choiceCount
|
||||
mtxP->lock();// protects choiceCount
|
||||
choiceCount++;
|
||||
mtx.unlock();
|
||||
mtxP->unlock();
|
||||
|
||||
if( viable < retval ) {
|
||||
viable = retval;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ MultList::~MultList() {
|
|||
delete child;
|
||||
child = cnext;
|
||||
}
|
||||
delete mtxP;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -104,29 +105,16 @@ EntList * MultList::getChild( int num ) {
|
|||
*/
|
||||
void MultList::appendList( EntList * ent ) {
|
||||
EntList * eprev;
|
||||
|
||||
mtx.lock(); // Protects numchildren, childList
|
||||
mtxP->lock(); // Protects numchildren, childList
|
||||
if( numchildren == 0 ) {
|
||||
childList = ent;
|
||||
} else {
|
||||
eprev = getLast();
|
||||
eprev->mtx.lock();
|
||||
// In a multithreaded environment It is possible that before locking
|
||||
// more elements got added into the existing list and eprev is no
|
||||
// longer the last element. This while loop takes care of that.
|
||||
while( eprev->next ) {
|
||||
eprev->mtx.unlock();
|
||||
eprev = eprev->next;
|
||||
eprev->mtx.lock();
|
||||
}
|
||||
// eprev lock is acquired
|
||||
eprev->next = ent;
|
||||
eprev->mtx.unlock();
|
||||
|
||||
ent->prev = eprev; // ent locking not required
|
||||
}
|
||||
numchildren += ent->siblings();
|
||||
mtx.unlock();
|
||||
mtxP->unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -150,9 +138,7 @@ EntList * MultList::copyList( EntList * ent ) {
|
|||
newlist = new AndOrList;
|
||||
break;
|
||||
};
|
||||
ent->mtx.lock(); // appendList doesn't lock the EntNode
|
||||
appendList( newlist );
|
||||
ent->mtx.unlock();
|
||||
|
||||
if( ent->multiple() ) {
|
||||
// For the multlists, we must recurse for all their children:
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ void OrList::unmarkAll( EntNode * ents ) {
|
|||
bool OrList::acceptChoice( EntNode * ents ) {
|
||||
EntList * child;
|
||||
|
||||
mtx.lock(); // to proctect choice
|
||||
mtxP->lock(); // to proctect choice
|
||||
if( choice == LISTEND ) {
|
||||
choice = choice1;
|
||||
}
|
||||
|
|
@ -73,7 +73,7 @@ bool OrList::acceptChoice( EntNode * ents ) {
|
|||
while( child ) {
|
||||
if( child->viable >= MATCHSOME && child->acceptChoice( ents ) ) {
|
||||
// acceptChoice() returns true if we marked something.
|
||||
mtx.unlock();
|
||||
mtxP->unlock();
|
||||
return true;
|
||||
}
|
||||
child = child->next;
|
||||
|
|
@ -82,6 +82,6 @@ bool OrList::acceptChoice( EntNode * ents ) {
|
|||
// If we got here, we must have gotten to the end of the childList without
|
||||
// finding a choice which marks something.
|
||||
choice = LISTEND;
|
||||
mtx.unlock();
|
||||
mtxP->unlock();
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,10 +103,10 @@ MatchType OrList::tryNext( EntNode * ents ) {
|
|||
EntList * child;
|
||||
MatchType retval;
|
||||
|
||||
mtx.lock(); // For choice
|
||||
mtxP->lock(); // For choice
|
||||
if( choice == LISTEND ) {
|
||||
// if we've already exhausted all the choices in this OR,
|
||||
mtx.unlock();
|
||||
mtxP->unlock();
|
||||
return NOMORE;
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +120,7 @@ MatchType OrList::tryNext( EntNode * ents ) {
|
|||
// our descendants before moving on.
|
||||
retval = ( ( MultList * )child )->tryNext( ents );
|
||||
if( retval == MATCHALL ) {
|
||||
mtx.unlock();
|
||||
mtxP->unlock();
|
||||
ents->sharedMtxP->unlock();
|
||||
return MATCHALL;
|
||||
}
|
||||
|
|
@ -129,7 +129,7 @@ MatchType OrList::tryNext( EntNode * ents ) {
|
|||
// EntLists on the higher levels (if there are) can retry all the
|
||||
// later choices with the new choice we just found. Otherwise,
|
||||
// we'll continue below looking into our next choice.
|
||||
mtx.unlock();
|
||||
mtxP->unlock();
|
||||
ents->sharedMtxP->unlock();
|
||||
return NEWCHOICE;
|
||||
}
|
||||
|
|
@ -143,11 +143,11 @@ MatchType OrList::tryNext( EntNode * ents ) {
|
|||
// (Also, it's nec. to unmark now, as we did above before returning and
|
||||
// before the calling tryNext() tries earlier OR's - see notes, 11/12.)
|
||||
choice = LISTEND;
|
||||
mtx.unlock();
|
||||
mtxP->unlock();
|
||||
ents->sharedMtxP->unlock();
|
||||
return NOMORE;
|
||||
}
|
||||
mtx.unlock();
|
||||
mtxP->unlock();
|
||||
|
||||
// Otherwise, try our next:
|
||||
if( acceptNextChoice( ents ) ) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue