There is a race in using singleton-static class object b/w mds thread
and application thread - caller of exit() api.

This patch still uses singleton but making the instance shared_ptr
to ensure the resource will not be destroyed if it is being used.
---
 src/log/agent/lga_agent.cc |  7 ++-----
 src/log/agent/lga_agent.h  | 21 ++++++++++++++-------
 src/log/agent/lga_api.cc   | 20 ++++++++++----------
 src/log/agent/lga_mds.cc   | 32 ++++++++++++++++----------------
 src/log/agent/lga_state.cc |  2 +-
 src/log/agent/lga_util.cc  | 10 +++++-----
 6 files changed, 48 insertions(+), 44 deletions(-)

diff --git a/src/log/agent/lga_agent.cc b/src/log/agent/lga_agent.cc
index bf9caa935..1000bb3fd 100644
--- a/src/log/agent/lga_agent.cc
+++ b/src/log/agent/lga_agent.cc
@@ -108,7 +108,7 @@ ScopeData::~ScopeData() {
     recovery2_unlock(is_locked_);
   }
 
-  LogAgent::instance().EnterCriticalSection();
+  LogAgent::instance()->EnterCriticalSection();
   LogClient* client = client_data_->client;
   bool* is_updated = client_data_->is_updated;
   RefCounter::Degree client_degree = client_data_->value;
@@ -128,15 +128,12 @@ ScopeData::~ScopeData() {
       stream->RestoreRefCounter(caller, stream_degree, *stream_is_updated);
     }
   }
-  LogAgent::instance().LeaveCriticalSection();
+  LogAgent::instance()->LeaveCriticalSection();
 }
 
 
//------------------------------------------------------------------------------
 // LogAgent
 
//------------------------------------------------------------------------------
-// Singleton represents LOG agent.
-LogAgent LogAgent::me_;
-
 LogAgent::LogAgent() {
   client_list_.clear();
   // There is high risk of calling one @LogClient method
diff --git a/src/log/agent/lga_agent.h b/src/log/agent/lga_agent.h
index 0049da054..0c32ea33b 100644
--- a/src/log/agent/lga_agent.h
+++ b/src/log/agent/lga_agent.h
@@ -19,12 +19,14 @@
 #define SRC_LOG_AGENT_LGA_AGENT_H_
 
 #include <atomic>
+#include <memory>
 #include <string>
 #include <vector>
-#include "mds/mds_papi.h"
 #include <saAis.h>
-#include "base/macros.h"
 #include <saLog.h>
+
+#include "base/macros.h"
+#include "mds/mds_papi.h"
 #include "log/common/lgsv_msg.h"
 #include "log/common/lgsv_defs.h"
 #include "log/agent/lga_common.h"
@@ -80,7 +82,15 @@ class LogClient;
 //<
 class LogAgent {
  public:
-  static LogAgent& instance() { return me_; }
+  static std::shared_ptr<LogAgent>& instance() {
+    // Ensure this static singleton instance is only destroyed when
+    // no one is using it. Note that: static data can be destroyed
+    // in log application thread which calls exit() libc. So, introducing
+    // shared_ptr<> to avoid races among threads.
+    static std::shared_ptr<LogAgent> me =
+        std::shared_ptr<LogAgent>{new LogAgent()};
+    return me;
+  }
 
   //<
   // C++ APIs wrapper for corresponding C LOG Agent APIs
@@ -158,11 +168,11 @@ class LogAgent {
   // Introduce these public interface for MDS thread use.
   void EnterCriticalSection();
   void LeaveCriticalSection();
+  ~LogAgent() {}
 
  private:
   // Not allow to create @LogAgent object, except the singleton object @me_.
   LogAgent();
-  ~LogAgent() {}
 
   // True if there is no Active SC, otherwise false
   bool no_active_log_server() const;
@@ -274,9 +284,6 @@ class LogAgent {
   // LGS LGA sync params
   NCS_SEL_OBJ lgs_sync_sel_;
 
-  // Singleton represents LOG Agent in LOG application process
-  static LogAgent me_;
-
   DELETE_COPY_AND_MOVE_OPERATORS(LogAgent);
 };
 
diff --git a/src/log/agent/lga_api.cc b/src/log/agent/lga_api.cc
index 37a1cc650..97dbf1d31 100644
--- a/src/log/agent/lga_api.cc
+++ b/src/log/agent/lga_api.cc
@@ -39,7 +39,7 @@
 SaAisErrorT saLogInitialize(SaLogHandleT* logHandle,
                             const SaLogCallbacksT* callbacks,
                             SaVersionT* version) {
-  return LogAgent::instance().saLogInitialize(logHandle, callbacks, version);
+  return LogAgent::instance()->saLogInitialize(logHandle, callbacks, version);
 }
 
 /***************************************************************************
@@ -69,7 +69,7 @@ SaAisErrorT saLogInitialize(SaLogHandleT* logHandle,
  ***************************************************************************/
 SaAisErrorT saLogSelectionObjectGet(SaLogHandleT logHandle,
                                     SaSelectionObjectT* selectionObject) {
-  return LogAgent::instance().saLogSelectionObjectGet(logHandle,
+  return LogAgent::instance()->saLogSelectionObjectGet(logHandle,
                                                       selectionObject);
 }
 
@@ -96,7 +96,7 @@ SaAisErrorT saLogSelectionObjectGet(SaLogHandleT logHandle,
  ***************************************************************************/
 SaAisErrorT saLogDispatch(SaLogHandleT logHandle,
                           SaDispatchFlagsT dispatchFlags) {
-  return LogAgent::instance().saLogDispatch(logHandle, dispatchFlags);
+  return LogAgent::instance()->saLogDispatch(logHandle, dispatchFlags);
 }
 
 /***************************************************************************
@@ -122,7 +122,7 @@ SaAisErrorT saLogDispatch(SaLogHandleT logHandle,
  *
  ***************************************************************************/
 SaAisErrorT saLogFinalize(SaLogHandleT logHandle) {
-  return LogAgent::instance().saLogFinalize(logHandle);
+  return LogAgent::instance()->saLogFinalize(logHandle);
 }
 
 /**
@@ -142,7 +142,7 @@ SaAisErrorT saLogStreamOpen_2(
     const SaLogFileCreateAttributesT_2* logFileCreateAttributes,
     SaLogStreamOpenFlagsT logStreamOpenFlags, SaTimeT timeOut,
     SaLogStreamHandleT* logStreamHandle) {
-  return LogAgent::instance().saLogStreamOpen_2(
+  return LogAgent::instance()->saLogStreamOpen_2(
       logHandle, logStreamName, logFileCreateAttributes, logStreamOpenFlags,
       timeOut, logStreamHandle);
 }
@@ -161,7 +161,7 @@ SaAisErrorT saLogStreamOpenAsync_2(
     SaLogHandleT logHandle, const SaNameT* logStreamName,
     const SaLogFileCreateAttributesT_2* logFileCreateAttributes,
     SaLogStreamOpenFlagsT logstreamOpenFlags, SaInvocationT invocation) {
-  return LogAgent::instance().saLogStreamOpenAsync_2(
+  return LogAgent::instance()->saLogStreamOpenAsync_2(
       logHandle, logStreamName, logFileCreateAttributes, logstreamOpenFlags,
       invocation);
 }
@@ -176,7 +176,7 @@ SaAisErrorT saLogStreamOpenAsync_2(
  */
 SaAisErrorT saLogWriteLog(SaLogStreamHandleT logStreamHandle, SaTimeT timeOut,
                           const SaLogRecordT* logRecord) {
-  return LogAgent::instance().saLogWriteLog(logStreamHandle, timeOut,
+  return LogAgent::instance()->saLogWriteLog(logStreamHandle, timeOut,
                                             logRecord);
 }
 
@@ -193,7 +193,7 @@ SaAisErrorT saLogWriteLogAsync(SaLogStreamHandleT 
logStreamHandle,
                                SaInvocationT invocation,
                                SaLogAckFlagsT ackFlags,
                                const SaLogRecordT* logRecord) {
-  return LogAgent::instance().saLogWriteLogAsync(logStreamHandle, invocation,
+  return LogAgent::instance()->saLogWriteLogAsync(logStreamHandle, invocation,
                                                  ackFlags, logRecord);
 }
 /**
@@ -204,7 +204,7 @@ SaAisErrorT saLogWriteLogAsync(SaLogStreamHandleT 
logStreamHandle,
  * @return SaAisErrorT
  */
 SaAisErrorT saLogStreamClose(SaLogStreamHandleT logStreamHandle) {
-  return LogAgent::instance().saLogStreamClose(logStreamHandle);
+  return LogAgent::instance()->saLogStreamClose(logStreamHandle);
 }
 
 /**
@@ -217,5 +217,5 @@ SaAisErrorT saLogStreamClose(SaLogStreamHandleT 
logStreamHandle) {
  */
 SaAisErrorT saLogLimitGet(SaLogHandleT logHandle, SaLogLimitIdT limitId,
                           SaLimitValueT* limitValue) {
-  return LogAgent::instance().saLogLimitGet(logHandle, limitId, limitValue);
+  return LogAgent::instance()->saLogLimitGet(logHandle, limitId, limitValue);
 }
diff --git a/src/log/agent/lga_mds.cc b/src/log/agent/lga_mds.cc
index ca949577f..07db48d2c 100644
--- a/src/log/agent/lga_mds.cc
+++ b/src/log/agent/lga_mds.cc
@@ -516,9 +516,9 @@ static uint32_t lga_lgs_msg_proc(lgsv_msg_t *lgsv_msg,
   // Lookup the hdl rec by client_id
   LogClient *client = nullptr;
   uint32_t id = lgsv_msg->info.cbk_info.lgs_client_id;
-  LogAgent::instance().EnterCriticalSection();
-  if (nullptr == (client = LogAgent::instance().SearchClientById(id))) {
-    LogAgent::instance().LeaveCriticalSection();
+  LogAgent::instance()->EnterCriticalSection();
+  if (nullptr == (client = LogAgent::instance()->SearchClientById(id))) {
+    LogAgent::instance()->LeaveCriticalSection();
     TRACE("regid not found");
     lga_msg_destroy(lgsv_msg);
     return NCSCC_RC_FAILURE;
@@ -527,12 +527,12 @@ static uint32_t lga_lgs_msg_proc(lgsv_msg_t *lgsv_msg,
   // @client is being deleted in other thread. DO NOT touch this.
   bool updated = false;
   if (client->FetchAndIncreaseRefCounter(__func__, &updated) == -1) {
-    LogAgent::instance().LeaveCriticalSection();
+    LogAgent::instance()->LeaveCriticalSection();
     lga_msg_destroy(lgsv_msg);
     TRACE_LEAVE();
     return rc;
   }
-  LogAgent::instance().LeaveCriticalSection();
+  LogAgent::instance()->LeaveCriticalSection();
 
   switch (lgsv_msg->type) {
     case LGSV_LGS_CBK_MSG:
@@ -554,7 +554,7 @@ static uint32_t lga_lgs_msg_proc(lgsv_msg_t *lgsv_msg,
 
           TRACE_2("LGSV_CLM_NODE_STATUS_CALLBACK clm_node_status: %d", status);
           std::atomic<SaClmClusterChangesT> &clm_node_state =
-              LogAgent::instance().atomic_get_clm_node_state();
+              LogAgent::instance()->atomic_get_clm_node_state();
           clm_node_state =
               lgsv_msg->info.cbk_info.clm_node_status_cbk.clm_node_status;
           // A client becomes stale if Node loses CLM Membership.
@@ -644,7 +644,7 @@ static uint32_t lga_mds_svc_evt(struct ncsmds_callback_info 
*mds_cb_info) {
       TRACE("%s\t NCSMDS_NO_ACTIVE", __func__);
       // This is a temporary server down e.g. during switch/fail over
       if (mds_cb_info->info.svc_evt.i_svc_id == NCSMDS_SVC_ID_LGS) {
-        LogAgent::instance().NoActiveLogServer();
+        LogAgent::instance()->NoActiveLogServer();
       }
       break;
 
@@ -658,7 +658,7 @@ static uint32_t lga_mds_svc_evt(struct ncsmds_callback_info 
*mds_cb_info) {
         // Notify to LOG Agent that no LOG server exist.
         // In turn, it will inform to all its log clients
         // and all log streams belong to each log client.
-        LogAgent::instance().NoLogServer();
+        LogAgent::instance()->NoLogServer();
         // Stop the recovery thread if it is running
         lga_no_server_state_set();
       }
@@ -671,11 +671,11 @@ static uint32_t lga_mds_svc_evt(struct 
ncsmds_callback_info *mds_cb_info) {
           TRACE("%s\t NCSMDS_UP", __func__);
           // Inform to LOG agent that LOG server is up from headless
           // and provide it the LOG server destination address too.
-          LogAgent::instance().HasActiveLogServer(
+          LogAgent::instance()->HasActiveLogServer(
               mds_cb_info->info.svc_evt.i_dest);
-          if (LogAgent::instance().waiting_log_server_up() == true) {
+          if (LogAgent::instance()->waiting_log_server_up() == true) {
             // Signal waiting thread
-            m_NCS_SEL_OBJ_IND(LogAgent::instance().get_lgs_sync_sel());
+            m_NCS_SEL_OBJ_IND(LogAgent::instance()->get_lgs_sync_sel());
           }
           // Start recovery
           lga_serv_recov1state_set();
@@ -1236,7 +1236,7 @@ uint32_t lga_mds_init() {
   NCSMDS_INFO mds_info;
   uint32_t rc = NCSCC_RC_SUCCESS;
   MDS_SVC_ID svc = NCSMDS_SVC_ID_LGS;
-  std::atomic<MDS_HDL> &mds_hdl = LogAgent::instance().atomic_get_mds_hdl();
+  std::atomic<MDS_HDL> &mds_hdl = LogAgent::instance()->atomic_get_mds_hdl();
 
   TRACE_ENTER();
   // Create the ADEST for LGA and get the pwe hdl
@@ -1307,9 +1307,9 @@ uint32_t lga_mds_msg_sync_send(lgsv_msg_t *i_msg, 
lgsv_msg_t **o_msg,
                                SaTimeT timeout, uint32_t prio) {
   NCSMDS_INFO mds_info;
   uint32_t rc = NCSCC_RC_SUCCESS;
-  std::atomic<MDS_HDL> &mds_hdl = LogAgent::instance().atomic_get_mds_hdl();
+  std::atomic<MDS_HDL> &mds_hdl = LogAgent::instance()->atomic_get_mds_hdl();
   std::atomic<MDS_DEST> &lgs_mds_dest =
-      LogAgent::instance().atomic_get_lgs_mds_dest();
+      LogAgent::instance()->atomic_get_lgs_mds_dest();
 
   TRACE_ENTER();
 
@@ -1358,9 +1358,9 @@ uint32_t lga_mds_msg_sync_send(lgsv_msg_t *i_msg, 
lgsv_msg_t **o_msg,
 ******************************************************************************/
 uint32_t lga_mds_msg_async_send(lgsv_msg_t *i_msg, uint32_t prio) {
   NCSMDS_INFO mds_info;
-  std::atomic<MDS_HDL> &mds_hdl = LogAgent::instance().atomic_get_mds_hdl();
+  std::atomic<MDS_HDL> &mds_hdl = LogAgent::instance()->atomic_get_mds_hdl();
   std::atomic<MDS_DEST> &lgs_mds_dest =
-      LogAgent::instance().atomic_get_lgs_mds_dest();
+      LogAgent::instance()->atomic_get_lgs_mds_dest();
 
   TRACE_ENTER();
   osafassert(i_msg != nullptr);
diff --git a/src/log/agent/lga_state.cc b/src/log/agent/lga_state.cc
index 05c7a85ee..970fe27d2 100644
--- a/src/log/agent/lga_state.cc
+++ b/src/log/agent/lga_state.cc
@@ -97,7 +97,7 @@ static void *recovery2_thread(void *dummy) {
 
   // Recover all log clients. During this time, any call of LOG APIs
   // return TRY_AGAIN until the recovery is done.
-  LogAgent::instance().RecoverAllLogClients();
+  LogAgent::instance()->RecoverAllLogClients();
 
   // All clients are recovered (or removed). Or recovery is aborted
   // Change to not recovering state RecoveryState::kNormal
diff --git a/src/log/agent/lga_util.cc b/src/log/agent/lga_util.cc
index f4d0f970a..0bb91aaee 100644
--- a/src/log/agent/lga_util.cc
+++ b/src/log/agent/lga_util.cc
@@ -40,17 +40,17 @@ static unsigned int lga_create() {
   unsigned int rc = NCSCC_RC_SUCCESS;
 
   // Create and init sel obj for mds sync
-  NCS_SEL_OBJ* lgs_sync_sel = LogAgent::instance().get_lgs_sync_sel();
+  NCS_SEL_OBJ* lgs_sync_sel = LogAgent::instance()->get_lgs_sync_sel();
   m_NCS_SEL_OBJ_CREATE(lgs_sync_sel);
   std::atomic<bool>& lgs_sync_wait =
-      LogAgent::instance().atomic_get_lgs_sync_wait();
+      LogAgent::instance()->atomic_get_lgs_sync_wait();
   lgs_sync_wait = true;
 
   // register with MDS
   if ((NCSCC_RC_SUCCESS != (rc = lga_mds_init()))) {
     rc = NCSCC_RC_FAILURE;
     // Delete the lga init instances
-    LogAgent::instance().RemoveAllLogClients();
+    LogAgent::instance()->RemoveAllLogClients();
     return rc;
   }
 
@@ -64,7 +64,7 @@ static unsigned int lga_create() {
 
   lgs_sync_wait = false;
   std::atomic<SaClmClusterChangesT>& clm_state =
-      LogAgent::instance().atomic_get_clm_node_state();
+      LogAgent::instance()->atomic_get_clm_node_state();
   clm_state = SA_CLM_NODE_JOINED;
 
   // No longer needed
@@ -82,7 +82,7 @@ static unsigned int lga_create() {
 unsigned int lga_startup() {
   unsigned int rc = NCSCC_RC_SUCCESS;
   ScopeLock lock(init_lock);
-  std::atomic<MDS_HDL>& mds_hdl = LogAgent::instance().atomic_get_mds_hdl();
+  std::atomic<MDS_HDL>& mds_hdl = LogAgent::instance()->atomic_get_mds_hdl();
 
   TRACE_ENTER();
 
-- 
2.19.2



_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to