Hold lock for named lock table not while acquiring named lock

Otherwise all other attempts to acquire named locks are blocked. It should
be ok because references are not invalidated when inserting/accessing
elements of an `std::unique_map`. When cleaning locks up elements are
erased, though. Hence an additional cleanup lock is required to prevent
acquiring a named lock which has already been cleaned up.
This commit is contained in:
Martchus 2021-07-25 00:39:49 +02:00
parent 4850ada836
commit f3ec908bcc
2 changed files with 17 additions and 9 deletions

View File

@ -660,7 +660,7 @@ void ServiceSetup::run()
void ServiceSetup::Locks::clear() void ServiceSetup::Locks::clear()
{ {
auto log = LogContext(); auto log = LogContext();
const auto lock = std::lock_guard(m_mutex); const auto lock = std::unique_lock(m_cleanupMutex);
for (auto i = m_locksByName.begin(), end = m_locksByName.end(); i != end;) { for (auto i = m_locksByName.begin(), end = m_locksByName.end(); i != end;) {
if (auto lock2 = i->second.tryLockToWrite(log, std::string(i->first)); lock2.lock()) { // check whether nobody holds the lock anymore if (auto lock2 = i->second.tryLockToWrite(log, std::string(i->first)); lock2.lock()) { // check whether nobody holds the lock anymore
lock2.lock().unlock(); // ~shared_mutex(): The behavior is undefined if the mutex is owned by any thread [...]. lock2.lock().unlock(); // ~shared_mutex(): The behavior is undefined if the mutex is owned by any thread [...].

View File

@ -127,15 +127,17 @@ struct LIBREPOMGR_EXPORT ServiceSetup : public LibPkg::Lockable {
struct LIBREPOMGR_EXPORT Locks { struct LIBREPOMGR_EXPORT Locks {
using LockTable = std::unordered_map<std::string, GlobalLockable>; using LockTable = std::unordered_map<std::string, GlobalLockable>;
[[nodiscard]] GlobalLockable &namedLock(const std::string &lockName);
[[nodiscard]] SharedLoggingLock acquireToRead(LogContext &log, std::string &&lockName); [[nodiscard]] SharedLoggingLock acquireToRead(LogContext &log, std::string &&lockName);
[[nodiscard]] UniqueLoggingLock acquireToWrite(LogContext &log, std::string &&lockName); [[nodiscard]] UniqueLoggingLock acquireToWrite(LogContext &log, std::string &&lockName);
[[nodiscard]] std::pair<LockTable *, std::unique_lock<std::mutex>> acquireLockTable(); [[nodiscard]] std::pair<LockTable *, std::unique_lock<std::shared_mutex>> acquireLockTable();
void clear(); void clear();
static std::string forDatabase(std::string_view dbName, std::string_view dbArch); static std::string forDatabase(std::string_view dbName, std::string_view dbArch);
static std::string forDatabase(const LibPkg::Database &db); static std::string forDatabase(const LibPkg::Database &db);
private: private:
std::mutex m_mutex; std::mutex m_accessMutex;
std::shared_mutex m_cleanupMutex;
LockTable m_locksByName; LockTable m_locksByName;
} locks; } locks;
@ -155,21 +157,27 @@ inline std::shared_ptr<BuildAction> ServiceSetup::BuildSetup::getBuildAction(Bui
return id < actions.size() ? actions[id] : nullptr; return id < actions.size() ? actions[id] : nullptr;
} }
inline GlobalLockable &ServiceSetup::Locks::namedLock(const std::string &lockName)
{
const auto locktableLock = std::unique_lock(m_accessMutex);
return m_locksByName[lockName];
}
inline SharedLoggingLock ServiceSetup::Locks::acquireToRead(LogContext &log, std::string &&lockName) inline SharedLoggingLock ServiceSetup::Locks::acquireToRead(LogContext &log, std::string &&lockName)
{ {
const auto lock = std::lock_guard(m_mutex); const auto locktableLock = std::shared_lock(m_cleanupMutex);
return m_locksByName[lockName].lockToRead(log, std::move(lockName)); return namedLock(lockName).lockToRead(log, std::move(lockName));
} }
inline UniqueLoggingLock ServiceSetup::Locks::acquireToWrite(LogContext &log, std::string &&lockName) inline UniqueLoggingLock ServiceSetup::Locks::acquireToWrite(LogContext &log, std::string &&lockName)
{ {
const auto lock = std::lock_guard(m_mutex); const auto locktableLock = std::shared_lock(m_cleanupMutex);
return m_locksByName[lockName].lockToWrite(log, std::move(lockName)); return namedLock(lockName).lockToWrite(log, std::move(lockName));
} }
inline std::pair<ServiceSetup::Locks::LockTable *, std::unique_lock<std::mutex>> ServiceSetup::Locks::acquireLockTable() inline std::pair<ServiceSetup::Locks::LockTable *, std::unique_lock<std::shared_mutex>> ServiceSetup::Locks::acquireLockTable()
{ {
return std::make_pair(&m_locksByName, std::unique_lock(m_mutex)); return std::make_pair(&m_locksByName, std::unique_lock(m_cleanupMutex));
} }
struct LIBREPOMGR_EXPORT ServiceStatus : public ReflectiveRapidJSON::JsonSerializable<ServiceStatus> { struct LIBREPOMGR_EXPORT ServiceStatus : public ReflectiveRapidJSON::JsonSerializable<ServiceStatus> {