
I traced the issue reported by Caroline and Pavel in #134757 back to the call to ProcessRunLock::TrySetRunning. When that fails, we get a somewhat misleading error message: > process resume at entry point failed: Resume request failed - process still running. This is incorrect: the problem was not that the process was in a running state, but rather that the RunLock was being held by another thread (i.e. the Statusline). TrySetRunning would return false in both cases and the call site only accounted for the former. Besides the odd semantics, the current implementation is inherently race-y and I believe incorrect. If someone is holding the RunLock, the resume call should block, rather than give up, and with the lock held, switch the running state and report the old running state. This patch removes ProcessRunLock::TrySetRunning and updates all callers to use ProcessRunLock::SetRunning instead. To support that, ProcessRunLock::SetRunning (and ProcessRunLock::SetStopped, for consistency) now report whether the process was stopped or running respectively. Previously, both methods returned true unconditionally. The old code has been around pretty much pretty much forever, there's nothing in the git history to indicate that this was done purposely to solve a particular issue. I've tested this on both Linux and macOS and confirmed that this solves the statusline issue. A big thank you to Jim for reviewing my proposed solution offline and trying to poke holes in it.
57 lines
1.3 KiB
C++
57 lines
1.3 KiB
C++
//===-- ProcessRunLock.cpp ------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef _WIN32
|
|
#include "lldb/Host/ProcessRunLock.h"
|
|
|
|
namespace lldb_private {
|
|
|
|
ProcessRunLock::ProcessRunLock() {
|
|
int err = ::pthread_rwlock_init(&m_rwlock, nullptr);
|
|
(void)err;
|
|
}
|
|
|
|
ProcessRunLock::~ProcessRunLock() {
|
|
int err = ::pthread_rwlock_destroy(&m_rwlock);
|
|
(void)err;
|
|
}
|
|
|
|
bool ProcessRunLock::ReadTryLock() {
|
|
::pthread_rwlock_rdlock(&m_rwlock);
|
|
if (!m_running) {
|
|
// coverity[missing_unlock]
|
|
return true;
|
|
}
|
|
::pthread_rwlock_unlock(&m_rwlock);
|
|
return false;
|
|
}
|
|
|
|
bool ProcessRunLock::ReadUnlock() {
|
|
return ::pthread_rwlock_unlock(&m_rwlock) == 0;
|
|
}
|
|
|
|
bool ProcessRunLock::SetRunning() {
|
|
::pthread_rwlock_wrlock(&m_rwlock);
|
|
bool was_stopped = !m_running;
|
|
m_running = true;
|
|
::pthread_rwlock_unlock(&m_rwlock);
|
|
return was_stopped;
|
|
}
|
|
|
|
bool ProcessRunLock::SetStopped() {
|
|
::pthread_rwlock_wrlock(&m_rwlock);
|
|
bool was_running = m_running;
|
|
m_running = false;
|
|
::pthread_rwlock_unlock(&m_rwlock);
|
|
return was_running;
|
|
}
|
|
|
|
} // namespace lldb_private
|
|
|
|
#endif
|