From 8c3243d728c669a285ad8d7ea341d4470939724b Mon Sep 17 00:00:00 2001 From: Cristian Maglie Date: Wed, 10 Feb 2021 12:02:37 +0100 Subject: [PATCH] Correct locking for condition variable --- handler/handler.go | 55 +++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/handler/handler.go b/handler/handler.go index fa38dca..6656e9a 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -97,10 +97,21 @@ func (handler *InoHandler) dataRUnlock(msg string) { handler.dataMux.RUnlock() } -func (handler *InoHandler) waitClangdStart(msg string) { - log.Println(msg + yellow.Sprintf(" unlocked (waiting clangd)")) +func (handler *InoHandler) waitClangdStart(prefix string) error { + if handler.ClangdConn != nil { + return nil + } + + log.Printf(prefix + "(throttled: waiting for clangd)") + log.Println(prefix + yellow.Sprintf(" unlocked (waiting clangd)")) handler.clangdStarted.Wait() - log.Println(msg + yellow.Sprintf(" locked (waiting clangd)")) + log.Println(prefix + yellow.Sprintf(" locked (waiting clangd)")) + + if handler.ClangdConn == nil { + log.Printf(prefix + "clangd startup failed: aborting call") + return errors.New("could not start clangd, aborted") + } + return nil } // NewInoHandler creates and configures an InoHandler. @@ -165,37 +176,35 @@ func (handler *InoHandler) HandleMessageFromIDE(ctx context.Context, conn *jsonr params = req.Params } + // Set up RWLocks and wait for clangd startup switch req.Method { - case // Write lock - "initialize", + case // Write lock - NO clangd required + "initialize": + handler.dataLock(prefix) + defer handler.dataUnlock(prefix) + case // Write lock - clangd required "textDocument/didOpen", "textDocument/didChange", "textDocument/didClose": handler.dataLock(prefix) defer handler.dataUnlock(prefix) - case // Read lock - "textDocument/publishDiagnostics", - "workspace/applyEdit": + handler.waitClangdStart(prefix) + case // Read lock - NO clangd required + "initialized": handler.dataRLock(prefix) defer handler.dataRUnlock(prefix) - default: // Default to read lock + default: // Read lock - clangd required handler.dataRLock(prefix) - defer handler.dataRUnlock(prefix) - } - - switch req.Method { - case // Do not need clangd - "initialize", - "initialized": - default: // Default to clangd required - // Wait for clangd start-up + // if clangd is not started... if handler.ClangdConn == nil { - log.Printf(prefix + "(throttled: waiting for clangd)") + // Release the read lock and acquire a write lock + // (this is required to wait on condition variable). + handler.dataRUnlock(prefix) + handler.dataLock(prefix) + defer handler.dataUnlock(prefix) handler.waitClangdStart(prefix) - if handler.ClangdConn == nil { - log.Printf(prefix + "clangd startup failed: aborting call") - return nil, errors.New("could not start clangd, aborted") - } + } else { + defer handler.dataRUnlock(prefix) } }