Fixed crash with multi threaded parsers warming up at the same time.

The lock for the shared DFA state needs to protect a few more operations than just the addDFAState stuff and had to move up one call level. This in turn requires now 2 places where the lock must be aquired.
This commit is contained in:
Mike Lischke 2017-03-04 14:20:09 +01:00
parent d8826368d4
commit e002b177c6
4 changed files with 17 additions and 16 deletions

View File

@ -32,8 +32,7 @@ PredictionContextCache& ATNSimulator::getSharedContextCache() {
}
Ref<PredictionContext> ATNSimulator::getCachedContext(Ref<PredictionContext> const& context) {
// This function requires a lock as it might modify the cache, however the only path so far where it is called from
// (addDFAState -> optimizeConfigs) already has _stateLock aquired. Adding another lock here would then deadlock.
// This function must only be called with an active state lock, as we are going to change a shared structure.
std::map<Ref<PredictionContext>, Ref<PredictionContext>> visited;
return PredictionContext::getCachedContext(context, _sharedContextCache, visited);
}

View File

@ -12,6 +12,7 @@
#include "atn/SingletonPredictionContext.h"
#include "atn/PredicateTransition.h"
#include "atn/ActionTransition.h"
#include "atn/TokensStartState.h"
#include "misc/Interval.h"
#include "dfa/DFA.h"
#include "Lexer.h"
@ -102,7 +103,7 @@ void LexerATNSimulator::clearDFA() {
}
size_t LexerATNSimulator::matchATN(CharStream *input) {
ATNState *startState = (ATNState *)atn.modeToStartState[_mode];
ATNState *startState = atn.modeToStartState[_mode];
std::unique_ptr<ATNConfigSet> s0_closure = computeStartState(input, startState);

View File

@ -107,6 +107,8 @@ size_t ParserATNSimulator::adaptivePredict(TokenStream *input, size_t decision,
bool fullCtx = false;
std::unique_ptr<ATNConfigSet> s0_closure = computeStartState(dynamic_cast<ATNState *>(dfa.atnStartState),
&ParserRuleContext::EMPTY, fullCtx);
_stateLock.writeLock();
if (dfa.isPrecedenceDfa()) {
/* If this is a precedence DFA, we use applyPrecedenceFilter
* to convert the computed start state to a precedence start
@ -129,6 +131,7 @@ size_t ParserATNSimulator::adaptivePredict(TokenStream *input, size_t decision,
delete newState; // If there was already a state with this config set we don't need the new one.
}
}
_stateLock.writeUnlock();
}
// We can start with an existing DFA.
@ -1239,7 +1242,9 @@ dfa::DFAState *ParserATNSimulator::addDFAEdge(dfa::DFA &dfa, dfa::DFAState *from
return nullptr;
}
_stateLock.writeLock();
to = addDFAState(dfa, to); // used existing if possible not incoming
_stateLock.writeUnlock();
if (from == nullptr || t > (int)atn.maxTokenType) {
return to;
}
@ -1268,11 +1273,8 @@ dfa::DFAState *ParserATNSimulator::addDFAState(dfa::DFA &dfa, dfa::DFAState *D)
return D;
}
_stateLock.writeLock();
auto existing = dfa.states.find(D);
if (existing != dfa.states.end()) {
_stateLock.writeUnlock();
return *existing;
}
@ -1283,7 +1285,6 @@ dfa::DFAState *ParserATNSimulator::addDFAState(dfa::DFA &dfa, dfa::DFAState *D)
}
dfa.states.insert(D);
_stateLock.writeUnlock();
#if DEBUG_DFA == 1
std::cout << "adding new DFA state: " << D << std::endl;

View File

@ -251,11 +251,12 @@ namespace atn {
std::vector<dfa::DFA> &decisionToDFA;
private:
/// <summary>
/// SLL, LL, or LL + exact ambig detection? </summary>
private:
PredictionMode mode;
protected:
/// <summary>
/// Each prediction operation uses a cache for merge of prediction contexts.
/// Don't keep around as it wastes huge amounts of memory. The merge cache
@ -265,7 +266,6 @@ namespace atn {
/// the merge if we ever see a and b again. Note that (b,a)->c should
/// also be examined during cache lookup.
/// </summary>
protected:
PredictionContextMergeCache mergeCache;
// LAME globals to avoid parameters!!!!! I need these down deep in predTransition
@ -286,6 +286,7 @@ namespace atn {
virtual void clearDFA() override;
virtual size_t adaptivePredict(TokenStream *input, size_t decision, ParserRuleContext *outerContext);
protected:
/// <summary>
/// Performs ATN simulation to compute a predicted alternative based
/// upon the remaining input, but also updates the DFA cache to avoid
@ -317,7 +318,6 @@ namespace atn {
/// conflict
/// conflict + preds
/// </summary>
protected:
virtual size_t execATN(dfa::DFA &dfa, dfa::DFAState *s0, TokenStream *input, size_t startIndex,
ParserRuleContext *outerContext);