change locking mechanism for lookup tables;

pull/87/head
Bryan Biedenkapp 10 months ago
parent 10f6514c55
commit ac0cc2cf90

@ -23,6 +23,26 @@ using namespace lookups;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
std::mutex PeerListLookup::m_mutex; std::mutex PeerListLookup::m_mutex;
bool PeerListLookup::m_locked = false;
// ---------------------------------------------------------------------------
// Macros
// ---------------------------------------------------------------------------
// Lock the table.
#define __LOCK_TABLE() \
std::lock_guard<std::mutex> lock(m_mutex); \
m_locked = true;
// Unlock the table.
#define __UNLOCK_TABLE() m_locked = false;
// Spinlock wait for table to be released.
#define __SPINLOCK() \
if (m_locked) { \
while (m_locked) \
Thread::sleep(2U); \
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Public Class Members // Public Class Members
@ -40,8 +60,11 @@ PeerListLookup::PeerListLookup(const std::string& filename, Mode mode, uint32_t
void PeerListLookup::clear() void PeerListLookup::clear()
{ {
std::lock_guard<std::mutex> lock(m_mutex); __LOCK_TABLE();
m_table.clear(); m_table.clear();
__UNLOCK_TABLE();
} }
/* Adds a new entry to the list. */ /* Adds a new entry to the list. */
@ -50,7 +73,8 @@ void PeerListLookup::addEntry(uint32_t id, const std::string& alias, const std::
{ {
PeerId entry = PeerId(id, alias, password, peerLink, canRequestKeys, false); PeerId entry = PeerId(id, alias, password, peerLink, canRequestKeys, false);
std::lock_guard<std::mutex> lock(m_mutex); __LOCK_TABLE();
try { try {
PeerId _entry = m_table.at(id); PeerId _entry = m_table.at(id);
// if either the alias or the enabled flag doesn't match, update the entry // if either the alias or the enabled flag doesn't match, update the entry
@ -61,13 +85,16 @@ void PeerListLookup::addEntry(uint32_t id, const std::string& alias, const std::
} catch (...) { } catch (...) {
m_table[id] = entry; m_table[id] = entry;
} }
__UNLOCK_TABLE();
} }
/* Removes an existing entry from the list. */ /* Removes an existing entry from the list. */
void PeerListLookup::eraseEntry(uint32_t id) void PeerListLookup::eraseEntry(uint32_t id)
{ {
std::lock_guard<std::mutex> lock(m_mutex); __LOCK_TABLE();
try { try {
PeerId entry = m_table.at(id); // this value will get discarded PeerId entry = m_table.at(id); // this value will get discarded
(void)entry; // but some variants of C++ mark the unordered_map<>::at as nodiscard (void)entry; // but some variants of C++ mark the unordered_map<>::at as nodiscard
@ -75,6 +102,8 @@ void PeerListLookup::eraseEntry(uint32_t id)
} catch (...) { } catch (...) {
/* stub */ /* stub */
} }
__UNLOCK_TABLE();
} }
/* Finds a table entry in this lookup table. */ /* Finds a table entry in this lookup table. */
@ -83,7 +112,8 @@ PeerId PeerListLookup::find(uint32_t id)
{ {
PeerId entry; PeerId entry;
std::lock_guard<std::mutex> lock(m_mutex); __SPINLOCK();
try { try {
entry = m_table.at(id); entry = m_table.at(id);
} catch (...) { } catch (...) {
@ -111,7 +141,8 @@ bool PeerListLookup::getACL() const
bool PeerListLookup::isPeerInList(uint32_t id) const bool PeerListLookup::isPeerInList(uint32_t id) const
{ {
std::lock_guard<std::mutex> lock(m_mutex); __SPINLOCK();
if (m_table.find(id) != m_table.end()) { if (m_table.find(id) != m_table.end()) {
return true; return true;
} }
@ -141,8 +172,11 @@ bool PeerListLookup::isPeerAllowed(uint32_t id) const
void PeerListLookup::setMode(Mode mode) void PeerListLookup::setMode(Mode mode)
{ {
std::lock_guard<std::mutex> lock(m_mutex); __LOCK_TABLE();
m_mode = mode; m_mode = mode;
__UNLOCK_TABLE();
} }
/* Gets the current mode. */ /* Gets the current mode. */
@ -158,11 +192,13 @@ std::vector<PeerId> PeerListLookup::tableAsList() const
{ {
std::vector<PeerId> ret = std::vector<PeerId>(); std::vector<PeerId> ret = std::vector<PeerId>();
std::lock_guard<std::mutex> lock(m_mutex); __LOCK_TABLE();
for (auto entry : m_table) { for (auto entry : m_table) {
ret.push_back(entry.second); ret.push_back(entry.second);
} }
__UNLOCK_TABLE();
return ret; return ret;
} }
@ -184,8 +220,9 @@ bool PeerListLookup::load()
return false; return false;
} }
m_table.clear(); clear();
std::lock_guard<std::mutex> lock(m_mutex);
__LOCK_TABLE();
// read lines from file // read lines from file
std::string line; std::string line;
@ -249,6 +286,7 @@ bool PeerListLookup::load()
} }
file.close(); file.close();
__UNLOCK_TABLE();
size_t size = m_table.size(); size_t size = m_table.size();
if (size == 0U) if (size == 0U)

@ -263,7 +263,8 @@ namespace lookups
private: private:
Mode m_mode; Mode m_mode;
static std::mutex m_mutex; static std::mutex m_mutex; //! Mutex used for hard locking.
static bool m_locked; //! Flag used for soft locking (prevents find lookups), should be used when atomic operations (add/erase/etc) are being used.
}; };
} // namespace lookups } // namespace lookups

@ -5,7 +5,7 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2016 Jonathan Naylor, G4KLX * Copyright (C) 2016 Jonathan Naylor, G4KLX
* Copyright (C) 2017-2022 Bryan Biedenkapp, N2PLL * Copyright (C) 2017-2022,2025 Bryan Biedenkapp, N2PLL
* Copyright (c) 2024 Patrick McDonnell, W3AXL * Copyright (c) 2024 Patrick McDonnell, W3AXL
* *
*/ */
@ -25,6 +25,26 @@ using namespace lookups;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
std::mutex RadioIdLookup::m_mutex; std::mutex RadioIdLookup::m_mutex;
bool RadioIdLookup::m_locked = false;
// ---------------------------------------------------------------------------
// Macros
// ---------------------------------------------------------------------------
// Lock the table.
#define __LOCK_TABLE() \
std::lock_guard<std::mutex> lock(m_mutex); \
m_locked = true;
// Unlock the table.
#define __UNLOCK_TABLE() m_locked = false;
// Spinlock wait for table to be released.
#define __SPINLOCK() \
if (m_locked) { \
while (m_locked) \
Thread::sleep(2U); \
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Public Class Members // Public Class Members
@ -42,8 +62,11 @@ RadioIdLookup::RadioIdLookup(const std::string& filename, uint32_t reloadTime, b
void RadioIdLookup::clear() void RadioIdLookup::clear()
{ {
std::lock_guard<std::mutex> lock(m_mutex); __LOCK_TABLE();
m_table.clear(); m_table.clear();
__UNLOCK_TABLE();
} }
/* Toggles the specified radio ID enabled or disabled. */ /* Toggles the specified radio ID enabled or disabled. */
@ -64,7 +87,8 @@ void RadioIdLookup::addEntry(uint32_t id, bool enabled, const std::string& alias
RadioId entry = RadioId(enabled, false, alias, ipAddress); RadioId entry = RadioId(enabled, false, alias, ipAddress);
std::lock_guard<std::mutex> lock(m_mutex); __LOCK_TABLE();
try { try {
RadioId _entry = m_table.at(id); RadioId _entry = m_table.at(id);
// if either the alias or the enabled flag doesn't match, update the entry // if either the alias or the enabled flag doesn't match, update the entry
@ -79,20 +103,26 @@ void RadioIdLookup::addEntry(uint32_t id, bool enabled, const std::string& alias
//LogDebug(LOG_HOST, "Adding new RID %d (%s) to ACL", id, alias.c_str()); //LogDebug(LOG_HOST, "Adding new RID %d (%s) to ACL", id, alias.c_str());
m_table[id] = entry; m_table[id] = entry;
} }
__UNLOCK_TABLE();
} }
/* Erases an existing entry from the lookup table by the specified unique ID. */ /* Erases an existing entry from the lookup table by the specified unique ID. */
void RadioIdLookup::eraseEntry(uint32_t id) void RadioIdLookup::eraseEntry(uint32_t id)
{ {
std::lock_guard<std::mutex> lock(m_mutex); __LOCK_TABLE();
try { try {
RadioId entry = m_table.at(id); // this value will get discarded RadioId entry = m_table.at(id); // this value will get discarded
(void)entry; // but some variants of C++ mark the unordered_map<>::at as nodiscard (void)entry; // but some variants of C++ mark the unordered_map<>::at as nodiscard
m_table.erase(id); m_table.erase(id);
} catch (...) { }
catch (...) {
/* stub */ /* stub */
} }
__UNLOCK_TABLE();
} }
/* Finds a table entry in this lookup table. */ /* Finds a table entry in this lookup table. */
@ -105,7 +135,8 @@ RadioId RadioIdLookup::find(uint32_t id)
return RadioId(true, false); return RadioId(true, false);
} }
std::lock_guard<std::mutex> lock(m_mutex); __SPINLOCK();
try { try {
entry = m_table.at(id); entry = m_table.at(id);
} catch (...) { } catch (...) {
@ -150,7 +181,7 @@ bool RadioIdLookup::load()
// clear table // clear table
clear(); clear();
std::lock_guard<std::mutex> lock(m_mutex); __LOCK_TABLE();
// read lines from file // read lines from file
std::string line; std::string line;
@ -199,6 +230,7 @@ bool RadioIdLookup::load()
} }
file.close(); file.close();
__UNLOCK_TABLE();
size_t size = m_table.size(); size_t size = m_table.size();
if (size == 0U) if (size == 0U)

@ -5,7 +5,7 @@
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2016 Jonathan Naylor, G4KLX * Copyright (C) 2016 Jonathan Naylor, G4KLX
* Copyright (C) 2017-2022,2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2017-2022,2024,2025 Bryan Biedenkapp, N2PLL
* Copyright (c) 2024 Patrick McDonnell, W3AXL * Copyright (c) 2024 Patrick McDonnell, W3AXL
* *
*/ */
@ -208,7 +208,8 @@ namespace lookups
bool save() override; bool save() override;
private: private:
static std::mutex m_mutex; static std::mutex m_mutex; //! Mutex used for hard locking.
static bool m_locked; //! Flag used for soft locking (prevents find lookups), should be used when atomic operations (add/erase/etc) are being used.
}; };
} // namespace lookups } // namespace lookups

@ -4,7 +4,7 @@
* GPLv2 Open Source. Use is subject to license terms. * GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2023,2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2023,2024,2025 Bryan Biedenkapp, N2PLL
* Copyright (C) 2024 Patrick McDonnell, W3AXL * Copyright (C) 2024 Patrick McDonnell, W3AXL
* *
*/ */
@ -23,6 +23,26 @@ using namespace lookups;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
std::mutex TalkgroupRulesLookup::m_mutex; std::mutex TalkgroupRulesLookup::m_mutex;
bool TalkgroupRulesLookup::m_locked = false;
// ---------------------------------------------------------------------------
// Macros
// ---------------------------------------------------------------------------
// Lock the table.
#define __LOCK_TABLE() \
std::lock_guard<std::mutex> lock(m_mutex); \
m_locked = true;
// Unlock the table.
#define __UNLOCK_TABLE() m_locked = false;
// Spinlock wait for table to be released.
#define __SPINLOCK() \
if (m_locked) { \
while (m_locked) \
Thread::sleep(2U); \
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Public Class Members // Public Class Members
@ -101,8 +121,11 @@ bool TalkgroupRulesLookup::read()
void TalkgroupRulesLookup::clear() void TalkgroupRulesLookup::clear()
{ {
std::lock_guard<std::mutex> lock(m_mutex); __LOCK_TABLE();
m_groupVoice.clear(); m_groupVoice.clear();
__UNLOCK_TABLE();
} }
/* Adds a new entry to the lookup table by the specified unique ID. */ /* Adds a new entry to the lookup table by the specified unique ID. */
@ -117,7 +140,8 @@ void TalkgroupRulesLookup::addEntry(uint32_t id, uint8_t slot, bool enabled, boo
config.affiliated(affiliated); config.affiliated(affiliated);
config.nonPreferred(nonPreferred); config.nonPreferred(nonPreferred);
std::lock_guard<std::mutex> lock(m_mutex); __LOCK_TABLE();
auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(), auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(),
[&](TalkgroupRuleGroupVoice x) [&](TalkgroupRuleGroupVoice x)
{ {
@ -150,6 +174,8 @@ void TalkgroupRulesLookup::addEntry(uint32_t id, uint8_t slot, bool enabled, boo
m_groupVoice.push_back(entry); m_groupVoice.push_back(entry);
} }
__UNLOCK_TABLE();
} }
/* Adds a new entry to the lookup table by the specified unique ID. */ /* Adds a new entry to the lookup table by the specified unique ID. */
@ -163,7 +189,8 @@ void TalkgroupRulesLookup::addEntry(TalkgroupRuleGroupVoice groupVoice)
uint32_t id = entry.source().tgId(); uint32_t id = entry.source().tgId();
uint8_t slot = entry.source().tgSlot(); uint8_t slot = entry.source().tgSlot();
std::lock_guard<std::mutex> lock(m_mutex); __LOCK_TABLE();
auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(), auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(),
[&](TalkgroupRuleGroupVoice x) [&](TalkgroupRuleGroupVoice x)
{ {
@ -179,17 +206,22 @@ void TalkgroupRulesLookup::addEntry(TalkgroupRuleGroupVoice groupVoice)
else { else {
m_groupVoice.push_back(entry); m_groupVoice.push_back(entry);
} }
__UNLOCK_TABLE();
} }
/* Erases an existing entry from the lookup table by the specified unique ID. */ /* Erases an existing entry from the lookup table by the specified unique ID. */
void TalkgroupRulesLookup::eraseEntry(uint32_t id, uint8_t slot) void TalkgroupRulesLookup::eraseEntry(uint32_t id, uint8_t slot)
{ {
std::lock_guard<std::mutex> lock(m_mutex); __LOCK_TABLE();
auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(), [&](TalkgroupRuleGroupVoice x) { return x.source().tgId() == id && x.source().tgSlot() == slot; }); auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(), [&](TalkgroupRuleGroupVoice x) { return x.source().tgId() == id && x.source().tgSlot() == slot; });
if (it != m_groupVoice.end()) { if (it != m_groupVoice.end()) {
m_groupVoice.erase(it); m_groupVoice.erase(it);
} }
__UNLOCK_TABLE();
} }
/* Finds a table entry in this lookup table. */ /* Finds a table entry in this lookup table. */
@ -198,7 +230,8 @@ TalkgroupRuleGroupVoice TalkgroupRulesLookup::find(uint32_t id, uint8_t slot)
{ {
TalkgroupRuleGroupVoice entry; TalkgroupRuleGroupVoice entry;
std::lock_guard<std::mutex> lock(m_mutex); __SPINLOCK();
auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(), auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(),
[&](TalkgroupRuleGroupVoice x) [&](TalkgroupRuleGroupVoice x)
{ {
@ -223,7 +256,8 @@ TalkgroupRuleGroupVoice TalkgroupRulesLookup::findByRewrite(uint32_t peerId, uin
{ {
TalkgroupRuleGroupVoice entry; TalkgroupRuleGroupVoice entry;
std::lock_guard<std::mutex> lock(m_mutex); __SPINLOCK();
auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(), auto it = std::find_if(m_groupVoice.begin(), m_groupVoice.end(),
[&](TalkgroupRuleGroupVoice x) [&](TalkgroupRuleGroupVoice x)
{ {
@ -295,11 +329,13 @@ bool TalkgroupRulesLookup::load()
// clear table // clear table
clear(); clear();
std::lock_guard<std::mutex> lock(m_mutex); __LOCK_TABLE();
yaml::Node& groupVoiceList = m_rules["groupVoice"]; yaml::Node& groupVoiceList = m_rules["groupVoice"];
if (groupVoiceList.size() == 0U) { if (groupVoiceList.size() == 0U) {
::LogError(LOG_HOST, "No group voice rules list defined!"); ::LogError(LOG_HOST, "No group voice rules list defined!");
m_locked = false;
return false; return false;
} }
@ -332,9 +368,12 @@ bool TalkgroupRulesLookup::load()
::LogInfoEx(LOG_HOST, "Talkgroup NAME: %s SRC_TGID: %u SRC_TS: %u ACTIVE: %u PARROT: %u AFFILIATED: %u INCLUSIONS: %u EXCLUSIONS: %u REWRITES: %u ALWAYS: %u PREFERRED: %u PERMITTED RIDS: %u", groupName.c_str(), tgId, tgSlot, active, parrot, affil, incCount, excCount, rewrCount, alwyCount, prefCount, permRIDCount); ::LogInfoEx(LOG_HOST, "Talkgroup NAME: %s SRC_TGID: %u SRC_TS: %u ACTIVE: %u PARROT: %u AFFILIATED: %u INCLUSIONS: %u EXCLUSIONS: %u REWRITES: %u ALWAYS: %u PREFERRED: %u PERMITTED RIDS: %u", groupName.c_str(), tgId, tgSlot, active, parrot, affil, incCount, excCount, rewrCount, alwyCount, prefCount, permRIDCount);
} }
__UNLOCK_TABLE();
size_t size = m_groupVoice.size(); size_t size = m_groupVoice.size();
if (size == 0U) if (size == 0U) {
return false; return false;
}
LogInfoEx(LOG_HOST, "Loaded %lu entries into talkgroup rules table", size); LogInfoEx(LOG_HOST, "Loaded %lu entries into talkgroup rules table", size);

@ -4,7 +4,7 @@
* GPLv2 Open Source. Use is subject to license terms. * GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* Copyright (C) 2023,2024 Bryan Biedenkapp, N2PLL * Copyright (C) 2023,2024,2025 Bryan Biedenkapp, N2PLL
* Copyright (C) 2024 Patrick McDonnell, W3AXL * Copyright (C) 2024 Patrick McDonnell, W3AXL
* *
*/ */
@ -643,7 +643,8 @@ namespace lookups
bool m_acl; bool m_acl;
bool m_stop; bool m_stop;
static std::mutex m_mutex; static std::mutex m_mutex; //! Mutex used for hard locking.
static bool m_locked; //! Flag used for soft locking (prevents find lookups), should be used when atomic operations (add/erase/etc) are being used.
/** /**
* @brief Loads the table from the passed lookup table file. * @brief Loads the table from the passed lookup table file.

@ -63,7 +63,7 @@ namespace network
// Constants // Constants
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
#define MAX_INFLUXQL_THREAD_CNT 75 // this is a really extreme number of pending queries... #define MAX_INFLUXQL_THREAD_CNT 125 // Extreme maximum number of pending Flux queries
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Class Declaration // Class Declaration

Loading…
Cancel
Save

Powered by TurnKey Linux.