This is an automated email from the ASF dual-hosted git repository.

bneradt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 094c755d7d Add TSMutex lock guard (#13188)
094c755d7d is described below

commit 094c755d7d2c503187e569a5df0d047453573125
Author: Brian Neradt <[email protected]>
AuthorDate: Tue Jun 23 12:57:11 2026 -0500

    Add TSMutex lock guard (#13188)
    
    Plugin code that protects small critical sections with TSMutex has to pair
    every early return with a matching unlock. That pattern is easy to get wrong
    and makes the intended lock lifetime harder to see.
    
    This adds a small TSMutexLockGuard helper to the plugin API and uses it in
    plugin code where the mutex naturally stays locked until a return path.
---
 include/ts/ts.h                                    | 20 +++++++++++++
 plugins/background_fetch/background_fetch.cc       |  3 +-
 plugins/certifier/certifier.cc                     | 35 ++++++++++------------
 plugins/experimental/cache_fill/background_fetch.h |  3 +-
 plugins/experimental/rate_limit/ip_reputation.cc   | 16 +++-------
 .../experimental/stale_response/stale_response.cc  |  7 +++--
 plugins/experimental/system_stats/system_stats.cc  |  4 +--
 plugins/experimental/wasm/ats_context.cc           |  7 ++---
 plugins/experimental/wasm/wasm_main.cc             |  7 ++---
 plugins/lua/ts_lua.cc                              |  5 +---
 plugins/lua/ts_lua_fetch.cc                        |  3 +-
 plugins/lua/ts_lua_util.cc                         |  9 +-----
 plugins/prefetch/fetch.cc                          |  4 +--
 plugins/prefetch/fetch.h                           |  3 +-
 14 files changed, 56 insertions(+), 70 deletions(-)

diff --git a/include/ts/ts.h b/include/ts/ts.h
index ad266054cb..5631bee0f6 100644
--- a/include/ts/ts.h
+++ b/include/ts/ts.h
@@ -1168,6 +1168,26 @@ TSReturnCode TSMutexLockTry(TSMutex mutexp);
 
 void TSMutexUnlock(TSMutex mutexp);
 
+/** Scoped lock guard for a @c TSMutex.
+
+    Locks @a mutexp on construction and unlocks it when the guard leaves scope.
+ */
+class [[nodiscard]] TSMutexLockGuard
+{
+public:
+  explicit TSMutexLockGuard(TSMutex mutexp) : m_mutex(mutexp) { 
TSMutexLock(m_mutex); }
+
+  TSMutexLockGuard(const TSMutexLockGuard &)            = delete;
+  TSMutexLockGuard &operator=(const TSMutexLockGuard &) = delete;
+  TSMutexLockGuard(TSMutexLockGuard &&)                 = delete;
+  TSMutexLockGuard &operator=(TSMutexLockGuard &&)      = delete;
+
+  ~TSMutexLockGuard() { TSMutexUnlock(m_mutex); }
+
+private:
+  TSMutex m_mutex = nullptr;
+};
+
 /* --------------------------------------------------------------------------
    cachekey */
 /**
diff --git a/plugins/background_fetch/background_fetch.cc 
b/plugins/background_fetch/background_fetch.cc
index 90ce73345e..09979e1a58 100644
--- a/plugins/background_fetch/background_fetch.cc
+++ b/plugins/background_fetch/background_fetch.cc
@@ -117,14 +117,13 @@ public:
   {
     bool ret;
 
-    TSMutexLock(_lock);
+    TSMutexLockGuard lock(_lock);
     if (_urls.end() == _urls.find(url)) {
       ret = false;
     } else {
       _urls.erase(url);
       ret = true;
     }
-    TSMutexUnlock(_lock);
 
     return ret;
   }
diff --git a/plugins/certifier/certifier.cc b/plugins/certifier/certifier.cc
index 6dd3ec8225..2274e1f141 100644
--- a/plugins/certifier/certifier.cc
+++ b/plugins/certifier/certifier.cc
@@ -132,12 +132,12 @@ public:
   SSL_CTX *
   lookup_and_create(const char *servername, void *edata, bool &wontdo)
   {
-    SslData       *ssl_data        = nullptr;
-    scoped_SslData scoped_ssl_data = nullptr;
-    SSL_CTX       *ref_ctx         = nullptr;
-    std::string    commonName(servername);
-    TSMutexLock(list_mutex);
-    auto dataItr = cnDataMap.find(commonName);
+    SslData         *ssl_data        = nullptr;
+    scoped_SslData   scoped_ssl_data = nullptr;
+    SSL_CTX         *ref_ctx         = nullptr;
+    std::string      commonName(servername);
+    TSMutexLockGuard lock(list_mutex);
+    auto             dataItr = cnDataMap.find(commonName);
     /// If such a context exists in dict
     if (dataItr != cnDataMap.end()) {
       /// Reuse context if already built, self queued if not
@@ -165,7 +165,6 @@ public:
         ssl_data->scheduled = true;
       }
     }
-    TSMutexUnlock(list_mutex);
     return ref_ctx;
   }
 
@@ -265,27 +264,24 @@ public:
   SslData *
   get_newest()
   {
-    TSMutexLock(list_mutex);
-    SslData *ret = head;
-    TSMutexUnlock(list_mutex);
+    TSMutexLockGuard lock(list_mutex);
+    SslData         *ret = head;
     return ret;
   }
 
   SslData *
   get_oldest()
   {
-    TSMutexLock(list_mutex);
-    SslData *ret = tail;
-    TSMutexUnlock(list_mutex);
+    TSMutexLockGuard lock(list_mutex);
+    SslData         *ret = tail;
     return ret;
   }
 
   int
   get_size()
   {
-    TSMutexLock(list_mutex);
-    int ret = size;
-    TSMutexUnlock(list_mutex);
+    TSMutexLockGuard lock(list_mutex);
+    int              ret = size;
     return ret;
   }
 
@@ -293,14 +289,13 @@ public:
   int
   set_schedule(const std::string &commonName, bool flag)
   {
-    int ret = -1;
-    TSMutexLock(list_mutex);
-    auto iter = cnDataMap.find(commonName);
+    int              ret = -1;
+    TSMutexLockGuard lock(list_mutex);
+    auto             iter = cnDataMap.find(commonName);
     if (iter != cnDataMap.end()) {
       iter->second->scheduled = flag;
       ret                     = 0;
     }
-    TSMutexUnlock(list_mutex);
     return ret;
   }
 };
diff --git a/plugins/experimental/cache_fill/background_fetch.h 
b/plugins/experimental/cache_fill/background_fetch.h
index 011d5e1d37..a2744f7ab2 100644
--- a/plugins/experimental/cache_fill/background_fetch.h
+++ b/plugins/experimental/cache_fill/background_fetch.h
@@ -99,14 +99,13 @@ public:
   {
     bool ret;
 
-    TSMutexLock(_lock);
+    TSMutexLockGuard lock(_lock);
     if (_urls.end() == _urls.find(url)) {
       ret = false;
     } else {
       _urls.erase(url);
       ret = true;
     }
-    TSMutexUnlock(_lock);
 
     return ret;
   }
diff --git a/plugins/experimental/rate_limit/ip_reputation.cc 
b/plugins/experimental/rate_limit/ip_reputation.cc
index 520b12d274..1853861c49 100644
--- a/plugins/experimental/rate_limit/ip_reputation.cc
+++ b/plugins/experimental/rate_limit/ip_reputation.cc
@@ -144,7 +144,7 @@ SieveLru::parseYaml(const YAML::Node &node)
 std::tuple<uint32_t, uint32_t>
 SieveLru::increment(KeyClass key)
 {
-  TSMutexLock(_lock);
+  TSMutexLockGuard lock(_lock);
   TSAssert(_initialized);
 
   auto map_it = _map.find(key);
@@ -166,7 +166,6 @@ SieveLru::increment(KeyClass key)
       lru->push_front({key, 1, entryBucket(), SystemClock::now()});
     }
     _map[key] = lru->begin();
-    TSMutexUnlock(_lock);
 
     return {entryBucket(), 1};
   } else {
@@ -213,7 +212,6 @@ SieveLru::increment(KeyClass key)
         lru->moveTop(lru.get(), map_item);
       }
     }
-    TSMutexUnlock(_lock);
 
     return {bucket, count};
   }
@@ -223,21 +221,17 @@ SieveLru::increment(KeyClass key)
 std::tuple<uint32_t, uint32_t>
 SieveLru::lookup(KeyClass key) const
 {
-  TSMutexLock(_lock);
+  TSMutexLockGuard lock(_lock);
   TSAssert(_initialized);
 
   auto map_it = _map.find(key);
 
   if (_map.end() == map_it) {
-    TSMutexUnlock(_lock);
-
     return {0, entryBucket()}; // Nothing found, return 0 hits and the entry 
bucket #
   } else {
     auto &[map_key, map_item]              = *map_it;
     auto &[list_key, count, bucket, added] = *map_item;
 
-    TSMutexUnlock(_lock);
-
     return {bucket, count};
   }
 }
@@ -247,7 +241,7 @@ SieveLru::lookup(KeyClass key) const
 int32_t
 SieveLru::move_bucket(KeyClass key, uint32_t to_bucket)
 {
-  TSMutexLock(_lock);
+  TSMutexLockGuard lock(_lock);
   TSAssert(_initialized);
 
   auto map_it = _map.find(key);
@@ -289,7 +283,6 @@ SieveLru::move_bucket(KeyClass key, uint32_t to_bucket)
       added  = SystemClock::now();
     }
   }
-  TSMutexUnlock(_lock);
 
   return to_bucket; // Just as a convenience, return the destination bucket 
for this entry
 }
@@ -336,7 +329,7 @@ SieveBucket::memorySize() const
 size_t
 SieveLru::memoryUsed() const
 {
-  TSMutexLock(_lock);
+  TSMutexLockGuard lock(_lock);
   TSAssert(_initialized);
 
   size_t total = sizeof(SieveLru);
@@ -347,7 +340,6 @@ SieveLru::memoryUsed() const
 
   total += _map.size() * (sizeof(void *) + sizeof(SieveBucket::iterator));
   total += _map.bucket_count() * (sizeof(size_t) + sizeof(void *));
-  TSMutexUnlock(_lock);
 
   return total;
 }
diff --git a/plugins/experimental/stale_response/stale_response.cc 
b/plugins/experimental/stale_response/stale_response.cc
index 02a2bbff8c..0f1b4f2f46 100644
--- a/plugins/experimental/stale_response/stale_response.cc
+++ b/plugins/experimental/stale_response/stale_response.cc
@@ -202,11 +202,12 @@ free_state_info(StateInfo *state)
 int64_t
 aync_memory_total_add(ConfigInfo *plugin_config, int64_t change)
 {
-  int64_t total;
-  TSMutexLock(plugin_config->body_data_mutex);
+  int64_t          total;
+  TSMutexLockGuard lock(plugin_config->body_data_mutex);
+
   plugin_config->body_data_memory_usage += change;
   total                                  = 
plugin_config->body_data_memory_usage;
-  TSMutexUnlock(plugin_config->body_data_mutex);
+
   return total;
 }
 
/*-----------------------------------------------------------------------------------------------*/
diff --git a/plugins/experimental/system_stats/system_stats.cc 
b/plugins/experimental/system_stats/system_stats.cc
index 1e98cfd3fd..1bb42e85e2 100644
--- a/plugins/experimental/system_stats/system_stats.cc
+++ b/plugins/experimental/system_stats/system_stats.cc
@@ -103,7 +103,7 @@ statAdd(const char *name, TSRecordDataType record_type, 
TSMutex create_mutex)
 {
   int stat_id = -1;
 
-  TSMutexLock(create_mutex);
+  TSMutexLockGuard lock(create_mutex);
 
   if (TS_ERROR == TSStatFindName(name, &stat_id)) {
     stat_id = TSStatCreate(name, record_type, TS_STAT_NON_PERSISTENT, 
TS_STAT_SYNC_SUM);
@@ -114,8 +114,6 @@ statAdd(const char *name, TSRecordDataType record_type, 
TSMutex create_mutex)
     }
   }
 
-  TSMutexUnlock(create_mutex);
-
   return stat_id;
 }
 
diff --git a/plugins/experimental/wasm/ats_context.cc 
b/plugins/experimental/wasm/ats_context.cc
index ec96d5c9c2..c7c2b636f3 100644
--- a/plugins/experimental/wasm/ats_context.cc
+++ b/plugins/experimental/wasm/ats_context.cc
@@ -496,9 +496,9 @@ Context::getConfiguration()
 WasmResult
 Context::setTimerPeriod(std::chrono::milliseconds period, uint32_t 
*timer_token_ptr)
 {
-  Wasm    *wasm         = this->wasm();
-  Context *root_context = this->root_context();
-  TSMutexLock(wasm->mutex());
+  Wasm            *wasm         = this->wasm();
+  Context         *root_context = this->root_context();
+  TSMutexLockGuard lock(wasm->mutex());
   if (!wasm->existsTimerPeriod(root_context->id())) {
     Dbg(dbg_ctl, "[%s] no previous timer period set", __FUNCTION__);
     TSCont contp = root_context->scheduler_cont();
@@ -511,7 +511,6 @@ Context::setTimerPeriod(std::chrono::milliseconds period, 
uint32_t *timer_token_
 
   wasm->setTimerPeriod(root_context->id(), period);
   *timer_token_ptr = 0;
-  TSMutexUnlock(wasm->mutex());
   return WasmResult::Ok;
 }
 
diff --git a/plugins/experimental/wasm/wasm_main.cc 
b/plugins/experimental/wasm/wasm_main.cc
index 6e7c32a31a..e2c16170fa 100644
--- a/plugins/experimental/wasm/wasm_main.cc
+++ b/plugins/experimental/wasm/wasm_main.cc
@@ -304,14 +304,13 @@ schedule_handler(TSCont contp, TSEvent /*event*/, void * 
/*data*/)
 
   auto *c = static_cast<ats_wasm::Context *>(TSContDataGet(contp));
 
-  auto *old_wasm = static_cast<ats_wasm::Wasm *>(c->wasm());
-  TSMutexLock(old_wasm->mutex());
+  auto            *old_wasm = static_cast<ats_wasm::Wasm *>(c->wasm());
+  TSMutexLockGuard lock(old_wasm->mutex());
 
   c->onTick(0); // use 0 as  token
 
   if (wasm_config->configs.empty()) {
     TSError("[wasm][%s] Configuration objects are empty", __FUNCTION__);
-    TSMutexUnlock(old_wasm->mutex());
     return 0;
   }
 
@@ -365,8 +364,6 @@ schedule_handler(TSCont contp, TSEvent /*event*/, void * 
/*data*/)
     Dbg(ats_wasm::dbg_ctl, "[%s] config wasm has changed. thus not 
scheduling", __FUNCTION__);
   }
 
-  TSMutexUnlock(old_wasm->mutex());
-
   return 0;
 }
 
diff --git a/plugins/lua/ts_lua.cc b/plugins/lua/ts_lua.cc
index 02b0781711..eeaa4f03a5 100644
--- a/plugins/lua/ts_lua.cc
+++ b/plugins/lua/ts_lua.cc
@@ -525,7 +525,7 @@ ts_lua_remap_plugin_init(void *ih, TSHttpTxn rh, 
TSRemapRequestInfo *rri)
     pthread_setspecific(lua_state_key, main_ctx);
   }
 
-  TSMutexLock(main_ctx->mutexp);
+  TSMutexLockGuard lock(main_ctx->mutexp);
 
   http_ctx = ts_lua_create_http_ctx(main_ctx, instance_conf);
 
@@ -551,7 +551,6 @@ ts_lua_remap_plugin_init(void *ih, TSHttpTxn rh, 
TSRemapRequestInfo *rri)
   if (lua_type(L, -1) != LUA_TFUNCTION) {
     lua_pop(L, 1);
     ts_lua_destroy_http_ctx(http_ctx);
-    TSMutexUnlock(main_ctx->mutexp);
     return TSREMAP_NO_REMAP;
   }
 
@@ -574,8 +573,6 @@ ts_lua_remap_plugin_init(void *ih, TSHttpTxn rh, 
TSRemapRequestInfo *rri)
     ts_lua_destroy_http_ctx(http_ctx);
   }
 
-  TSMutexUnlock(main_ctx->mutexp);
-
   return TSRemapStatus(ret);
 }
 
diff --git a/plugins/lua/ts_lua_fetch.cc b/plugins/lua/ts_lua_fetch.cc
index b14b918eab..45a80557c5 100644
--- a/plugins/lua/ts_lua_fetch.cc
+++ b/plugins/lua/ts_lua_fetch.cc
@@ -542,7 +542,7 @@ ts_lua_fetch_multi_handler(TSCont contp, TSEvent event 
ATS_UNUSED, void *edata)
   }
 
   // all finish
-  TSMutexLock(lmutex);
+  TSMutexLockGuard lock(lmutex);
 
   if (fmi->total == 1 && !fmi->multi) {
     ts_lua_fill_one_result(L, fi);
@@ -559,7 +559,6 @@ ts_lua_fetch_multi_handler(TSCont contp, TSEvent event 
ATS_UNUSED, void *edata)
     TSContCall(ci->contp, TSEvent(TS_LUA_EVENT_COROUTINE_CONT), 
reinterpret_cast<void *>(1));
   }
 
-  TSMutexUnlock(lmutex);
   return 0;
 }
 
diff --git a/plugins/lua/ts_lua_util.cc b/plugins/lua/ts_lua_util.cc
index bf1577f68f..10baf236b7 100644
--- a/plugins/lua/ts_lua_util.cc
+++ b/plugins/lua/ts_lua_util.cc
@@ -289,7 +289,7 @@ ts_lua_add_module(ts_lua_instance_conf *conf, 
ts_lua_main_ctx *arr, int n, int a
     conf->_first = (i == 0) ? 1 : 0;
     conf->_last  = (i == n - 1) ? 1 : 0;
 
-    TSMutexLock(arr[i].mutexp);
+    TSMutexLockGuard lock(arr[i].mutexp);
 
     L = arr[i].lua;
 
@@ -308,7 +308,6 @@ ts_lua_add_module(ts_lua_instance_conf *conf, 
ts_lua_main_ctx *arr, int n, int a
       if (luaL_loadstring(L, conf->content)) {
         snprintf(errbuf, errbuf_size, "[%s] luaL_loadstring failed: %s", 
__FUNCTION__, lua_tostring(L, -1));
         lua_pop(L, 1);
-        TSMutexUnlock(arr[i].mutexp);
         return -1;
       }
 
@@ -316,7 +315,6 @@ ts_lua_add_module(ts_lua_instance_conf *conf, 
ts_lua_main_ctx *arr, int n, int a
       if (luaL_loadfile(L, conf->script)) {
         snprintf(errbuf, errbuf_size, "[%s] luaL_loadfile %s failed: %s", 
__FUNCTION__, conf->script, lua_tostring(L, -1));
         lua_pop(L, 1);
-        TSMutexUnlock(arr[i].mutexp);
         return -1;
       }
     }
@@ -324,7 +322,6 @@ ts_lua_add_module(ts_lua_instance_conf *conf, 
ts_lua_main_ctx *arr, int n, int a
     if (lua_pcall(L, 0, 0, 0)) {
       snprintf(errbuf, errbuf_size, "[%s] lua_pcall %s failed: %s", 
__FUNCTION__, conf->script, lua_tostring(L, -1));
       lua_pop(L, 1);
-      TSMutexUnlock(arr[i].mutexp);
       return -1;
     }
 
@@ -346,7 +343,6 @@ ts_lua_add_module(ts_lua_instance_conf *conf, 
ts_lua_main_ctx *arr, int n, int a
       if (lua_pcall(L, 1, 1, 0)) {
         snprintf(errbuf, errbuf_size, "[%s] lua_pcall %s failed: %s", 
__FUNCTION__, conf->script, lua_tostring(L, -1));
         lua_pop(L, 1);
-        TSMutexUnlock(arr[i].mutexp);
         return -1;
       }
 
@@ -354,7 +350,6 @@ ts_lua_add_module(ts_lua_instance_conf *conf, 
ts_lua_main_ctx *arr, int n, int a
       lua_pop(L, 1);
 
       if (ret) {
-        TSMutexUnlock(arr[i].mutexp);
         return -1; /* script parse error */
       }
 
@@ -375,8 +370,6 @@ ts_lua_add_module(ts_lua_instance_conf *conf, 
ts_lua_main_ctx *arr, int n, int a
     } else {
       Dbg(dbg_ctl, "ljgc = %d, NOT running LuaJIT Garbage Collector...", 
conf->ljgc);
     }
-
-    TSMutexUnlock(arr[i].mutexp);
   }
 
   return 0;
diff --git a/plugins/prefetch/fetch.cc b/plugins/prefetch/fetch.cc
index f35b137aa3..b0d5c7615c 100644
--- a/plugins/prefetch/fetch.cc
+++ b/plugins/prefetch/fetch.cc
@@ -231,7 +231,7 @@ BgFetchState::init(const PrefetchConfig &config)
   TSMutexUnlock(_lock);
 
   /* Initialize fetching policy */
-  TSMutexLock(_policyLock);
+  TSMutexLockGuard policy_lock(_policyLock);
 
   if (!config.getFetchPolicy().empty() && 0 != 
config.getFetchPolicy().compare("simple")) {
     status &= initializePolicy(_policy, config.getFetchPolicy().c_str());
@@ -242,8 +242,6 @@ BgFetchState::init(const PrefetchConfig &config)
     PrefetchDebug("Policy not specified or 'simple' policy chosen (skipping)");
   }
 
-  TSMutexUnlock(_policyLock);
-
   return status;
 }
 
diff --git a/plugins/prefetch/fetch.h b/plugins/prefetch/fetch.h
index 2a1b7082a1..66ae24d561 100644
--- a/plugins/prefetch/fetch.h
+++ b/plugins/prefetch/fetch.h
@@ -140,7 +140,7 @@ public:
     BgFetchState                              *state;
     std::map<String, BgFetchState *>::iterator it;
 
-    TSMutexLock(_prefetchStates->_lock);
+    TSMutexLockGuard lock(_prefetchStates->_lock);
     it = _prefetchStates->_states.find(space);
     if (it != _prefetchStates->_states.end()) {
       state = it->second;
@@ -148,7 +148,6 @@ public:
       state                           = new BgFetchState();
       _prefetchStates->_states[space] = state;
     }
-    TSMutexUnlock(_prefetchStates->_lock);
     return state;
   }
 

Reply via email to