ide: Fixed some parser deadlock issues (and added detection)

git-svn-id: svn://ultimatepp.org/upp/trunk@14681 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2020-07-15 07:11:08 +00:00
parent 464661d97d
commit 0de514b9f2
8 changed files with 58 additions and 32 deletions

View file

@ -226,7 +226,7 @@ void PreprocessParse(CppBase& base, Stream& in, int file, const String& path,
Event<int, const String&> error);
String PreprocessCpp(const String& src, const String& path);
ParserContext AssistParse(CppBase& base, const String& src, const String& path_, Event<int, const String&> error);
ParserContext AssistParse(const String& src, const String& path_, Event<int, const String&> error);
void SimpleParse(CppBase& cpp, const String& txt, const String& cls);

View file

@ -55,7 +55,7 @@ String PreprocessCpp(const String& src, const String& path)
return cpp.output;
}
ParserContext AssistParse(CppBase& base, const String& src, const String& path_, Event<int, const String&> error)
ParserContext AssistParse(const String& src, const String& path_, Event<int, const String&> error)
{
String path = NormalizeSourcePath(path_);
Cpp cpp;
@ -64,7 +64,8 @@ ParserContext AssistParse(CppBase& base, const String& src, const String& path_,
Parser parser;
parser.dobody = true; // will do bodies and not write anything to base
StringStream pin(cpp.output);
parser.Do(pin, base, Null, Null, GetFileTitle(path), error,
CppBase dummy;
parser.Do(pin, dummy, Null, Null, GetFileTitle(path), error,
Vector<String>(), cpp.namespace_stack, cpp.namespace_using); // needs CodeBase to identify type names
return pick(parser);
}

View file

@ -58,7 +58,6 @@ public:
virtual ~Pusher();
};
class Button : public Pusher {
public:
virtual void Paint(Draw& draw);

View file

@ -22,20 +22,35 @@
static StaticMutex sGLock;
static thread_local int sGLockLevel = 0;
CodeBaseLock::CodeBaseLock()
bool DeadLockCheck()
{
if(sGLockLevel) {
PostCallback([] { Exclamation("Internal error (deadlock on sGLock)"); });
return true;
}
return false;
}
void LockCodeBase()
{
if(sGLockLevel++ == 0)
sGLock.Enter();
}
CodeBaseLock::~CodeBaseLock()
void UnlockCodeBase()
{
ASSERT(sGLockLevel > 0);
if(--sGLockLevel == 0)
if(sGLockLevel > 0 && --sGLockLevel == 0)
sGLock.Leave();
}
void UnlockCodeBaseAll()
{
if(sGLockLevel > 0)
sGLock.Leave();
sGLockLevel = 0; // just in case
}
INITIALIZER(CodeBase)
{
void InitializeTopicModule();
@ -121,7 +136,7 @@ void BrowserScanError(int line, const String& text, int file)
void SerializeCodeBase(Stream& s)
{
ASSERT(sGLockLevel == 0);
if(DeadLockCheck()) return;
Mutex::Lock __(CppBaseMutex);
MLOG(s.IsLoading());
source_file.Serialize(s);
@ -134,7 +149,7 @@ void SerializeCodeBase(Stream& s)
void SaveCodeBase()
{
ASSERT(sGLockLevel == 0);
if(DeadLockCheck()) return;
Mutex::Lock __(CppBaseMutex);
LTIMING("SaveCodeBase");
LLOG("Save code base " << CodeBase().GetCount());
@ -148,7 +163,7 @@ void SaveCodeBase()
bool TryLoadCodeBase(const char *pattern)
{
ASSERT(sGLockLevel == 0);
if(DeadLockCheck()) return false;
Mutex::Lock __(CppBaseMutex);
LLOG("+++ Trying to load " << pattern);
FindFile ff(pattern);
@ -176,7 +191,7 @@ bool TryLoadCodeBase(const char *pattern)
void LoadCodeBase()
{
ASSERT(sGLockLevel == 0);
if(DeadLockCheck()) return;
Mutex::Lock __(CppBaseMutex);
MLOG("LoadCodeBase start: " << MemoryUsedKb());
TryLoadCodeBase(CodeBaseCacheFile()) ||
@ -191,7 +206,7 @@ void FinishCodeBase()
{
LTIMING("FinishBase");
ASSERT(sGLockLevel == 0);
if(DeadLockCheck()) return;
Mutex::Lock __(CppBaseMutex);
Qualify(CodeBase());
}
@ -199,7 +214,7 @@ void FinishCodeBase()
void LoadDefs()
{
LTIMING("LoadDefs");
ASSERT(sGLockLevel == 0);
if(DeadLockCheck()) return;
Mutex::Lock __(CppBaseMutex);
Vector<String> defs;
defs.Add(ConfigFile("global.defs"));
@ -230,7 +245,7 @@ void LoadDefs()
void BaseInfoSync(Progress& pi)
{ // clears temporary caches (file times etc..)
ASSERT(sGLockLevel == 0);
if(DeadLockCheck()) return;
Mutex::Lock __(CppBaseMutex);
PPSync(TheIde()->IdeGetIncludePath());
@ -313,7 +328,7 @@ bool CheckFile0(SourceFileInfo& f, const String& path)
bool CheckFile(SourceFileInfo& f, const String& path)
{
LTIMING("CheckFile");
ASSERT(sGLockLevel == 0);
if(DeadLockCheck()) return false;
Mutex::Lock __(CppBaseMutex);
return CheckFile0(f, path);
}
@ -321,7 +336,7 @@ bool CheckFile(SourceFileInfo& f, const String& path)
void UpdateCodeBase2(Progress& pi)
{
CLOG("============= UpdateCodeBase2 " << GetSysTime());
ASSERT(sGLockLevel == 0);
if(DeadLockCheck()) return;
Mutex::Lock __(CppBaseMutex);
Index<int> parse_file;
{
@ -416,9 +431,6 @@ void CodeBaseScanFile0(Stream& in, const String& fn)
{
LLOG("===== CodeBaseScanFile " << fn);
ASSERT(sGLockLevel == 0);
Mutex::Lock __(CppBaseMutex);
InvalidateFileTimeCache(NormalizeSourcePath(fn));
PPSync(TheIde()->IdeGetIncludePath());
@ -436,6 +448,8 @@ void CodeBaseScanFile0(Stream& in, const String& fn)
void CodeBaseScanFile(Stream& in, const String& fn)
{
if(DeadLockCheck()) return;
Mutex::Lock __(CppBaseMutex);
CodeBaseScanFile0(in, fn);
FinishCodeBase();
}
@ -443,11 +457,11 @@ void CodeBaseScanFile(Stream& in, const String& fn)
void CodeBaseScanFile(const String& fn, bool auto_check)
{
LLOG("CodeBaseScanFile " << fn);
ASSERT(sGLockLevel == 0);
if(DeadLockCheck()) return;
Mutex::Lock __(CppBaseMutex);
String md5sum = GetPPMD5(fn);
FileIn in(fn);
CodeBaseScanFile(in, fn);
CodeBaseScanFile0(in, fn);
int file = GetSourceFileIndex(fn);
SourceFileInfo& f = source_file[file];
CLOG("CodeBaseScanFile " << fn << ", " << md5sum << " " << f.md5sum);
@ -463,7 +477,7 @@ void CodeBaseScanFile(const String& fn, bool auto_check)
void ClearCodeBase()
{
// TODO: Create combined defs
ASSERT(sGLockLevel == 0);
if(DeadLockCheck()) return;
Mutex::Lock __(CppBaseMutex);
CleanPP();
CodeBase().Clear();
@ -475,7 +489,7 @@ void SyncCodeBase()
LTIMING("SyncCodeBase");
LTIMESTOP("SyncCodeBase");
CLOG("============= Sync code base");
ASSERT(sGLockLevel == 0);
if(DeadLockCheck()) return;
Mutex::Lock __(CppBaseMutex);
if(IsNull(IdeGetCurrentMainPackage())) {
ClearCodeBase();
@ -489,7 +503,7 @@ void SyncCodeBase()
void NewCodeBase()
{
ASSERT(sGLockLevel == 0);
if(DeadLockCheck()) return;
Mutex::Lock __(CppBaseMutex);
ReduceCodeBaseCache();
if(IsNull(IdeGetCurrentMainPackage())) {
@ -510,7 +524,7 @@ void NewCodeBase()
void RescanCodeBase()
{
ASSERT(sGLockLevel == 0);
if(DeadLockCheck()) return;
Mutex::Lock __(CppBaseMutex);
ClearCodeBase();
s_console = true;

View file

@ -20,9 +20,13 @@ class Browser;
void ReduceCacheFolder(const char *path, int max_total);
void LockCodeBase();
void UnlockCodeBase();
void UnlockCodeBaseAll();
struct CodeBaseLock { // Use when accessing CodeBase
CodeBaseLock();
~CodeBaseLock();
CodeBaseLock() { LockCodeBase(); }
~CodeBaseLock() { UnlockCodeBase(); }
};
CppBase& CodeBase();

View file

@ -459,10 +459,11 @@ void Ide::JumpToDefinition(const Array<CppItem>& n, int q, const String& scope)
}
i++;
}
const CppItem& pos = n[qimpl >= 0 ? qimpl : qcpp >= 0 ? qcpp : q];
CppItem pos = n[qimpl >= 0 ? qimpl : qcpp >= 0 ? qcpp : q];
String path = GetSourceFilePath(pos.file);
editastext.RemoveKey(path);
editashex.RemoveKey(path);
UnlockCodeBaseAll();
if(!GotoDesignerFile(path, scope, pos.name, pos.line))
GotoCpp(pos);
}

View file

@ -14,16 +14,19 @@
String ResolveTParam(const String& type, const Vector<String>& tparam)
{
CodeBaseLock __;
return ResolveTParam(CodeBase(), type, tparam);
}
void ResolveTParam(Vector<String>& type, const Vector<String>& tparam)
{
CodeBaseLock __;
return ResolveTParam(CodeBase(), type, tparam);
}
String Qualify(const String& scope, const String& type, const String& usings)
{
CodeBaseLock __;
return Qualify(CodeBase(), scope, type, usings);
}
@ -41,7 +44,7 @@ void AssistEditor::Context(ParserContext& parser, int pos)
theide->ScanFile(true);
parser = AssistParse(CodeBase(), Get(0, pos), theide->editfile, AssistScanError);
parser = AssistParse(Get(0, pos), theide->editfile, AssistScanError);
inbody = parser.IsInBody();
#ifdef _DEBUG
PutVerbose("body: " + AsString(inbody));
@ -54,6 +57,7 @@ void AssistEditor::Context(ParserContext& parser, int pos)
Index<String> AssistEditor::EvaluateExpressionType(const ParserContext& parser, const Vector<String>& xp)
{
CodeBaseLock __;
return GetExpressionType(CodeBase(), parser, xp);
}
@ -71,6 +75,7 @@ void AssistEditor::GatherItems(const String& type, bool only_public, Index<Strin
{
LTIMING("GatherItems");
LLOG("---- GatherItems " << type);
CodeBaseLock __;
if(in_types.Find(type) >= 0) {
LLOG("-> recursion, exiting");
return;

View file

@ -61,7 +61,9 @@ bool Ide::SwapSIf(const char *cref)
break;
}
}
GotoCpp(*n[i % n.GetCount()]);
CppItem m = *n[i % n.GetCount()];
UnlockCodeBaseAll();
GotoCpp(m);
return true;
}