Fix thread synchronization in Cynara class 55/109955/3
authorRafal Krypa <r.krypa@samsung.com>
Wed, 11 Jan 2017 13:13:36 +0000 (14:13 +0100)
committerGerrit Code Review <gerrit@review.vlan103.tizen.org>
Mon, 23 Jan 2017 13:50:57 +0000 (05:50 -0800)
Pass changes to cynaraFd and fd events to be polled via atomic variables
and over atomic_thread_fence to properly propagate changes to these
values between checking threads and communication thread.

Change-Id: I9b41a0f8e40365bc30cdd47ed04be8727521476e
Signed-off-by: Rafal Krypa <r.krypa@samsung.com>
src/common/cynara.cpp
src/common/include/cynara.h

index add981529dfa2a70986fddebb3b264efbe765b2a..fd18f212c5bc47c77409f4b59002cb5e59e9c3a0 100644 (file)
@@ -705,24 +705,13 @@ int CynaraAdmin::GetPrivilegeManagerMaxLevel(const std::string &label, const std
     return result;
 }
 
-Cynara::Cynara()
+Cynara::Cynara() : eventFd(eventfd(0, 0)), cynaraFd(eventFd), cynaraFdEvents(0), terminate(false)
 {
-    int ret;
-
-    ret = eventfd(0, 0);
-    if (ret == -1) {
+    if (eventFd == -1) {
         LogError("Error while creating eventfd: " << GetErrnoString(errno));
         ThrowMsg(CynaraException::UnknownError, "Error while creating eventfd");
     }
 
-    // Poll the eventfd for reading
-    pollFds[0].fd = ret;
-    pollFds[0].events = POLLIN;
-
-    // Temporary, will be replaced by cynara fd when available
-    pollFds[1].fd = pollFds[0].fd;
-    pollFds[1].events = 0;
-
     cynara_async_configuration *p_conf = nullptr;
     checkCynaraError(cynara_async_configuration_create(&p_conf),
                      "Cannot create cynara async configuration");
@@ -740,7 +729,7 @@ Cynara::Cynara()
 Cynara::~Cynara()
 {
     LogDebug("Sending terminate event to Cynara thread");
-    terminate.store(true);
+    terminate = true;
     threadNotifyPut();
     thread.join();
 
@@ -751,7 +740,7 @@ Cynara::~Cynara()
 
 void Cynara::threadNotifyPut()
 {
-    int ret = eventfd_write(pollFds[0].fd, 1);
+    int ret = eventfd_write(eventFd, 1);
     if (ret == -1)
         LogError("Unexpected error while writing to eventfd: " << GetErrnoString(errno));
 }
@@ -759,7 +748,7 @@ void Cynara::threadNotifyPut()
 void Cynara::threadNotifyGet()
 {
     eventfd_t value;
-    int ret = eventfd_read(pollFds[0].fd, &value);
+    int ret = eventfd_read(eventFd, &value);
     if (ret == -1)
         LogError("Unexpected error while reading from eventfd: " << GetErrnoString(errno));
 }
@@ -770,21 +759,22 @@ void Cynara::statusCallback(int oldFd, int newFd, cynara_async_status status)
         "Status = " << status << ", oldFd = " << oldFd << ", newFd = " << newFd);
 
     if (newFd == -1) {
-        pollFds[1].events = 0;
+        cynaraFdEvents = 0;
     } else {
-        pollFds[1].fd = newFd;
 
+        cynaraFd = newFd;
         switch (status) {
         case CYNARA_STATUS_FOR_READ:
-            pollFds[1].events = POLLIN;
+            cynaraFdEvents = POLLIN;
             break;
 
         case CYNARA_STATUS_FOR_RW:
-            pollFds[1].events = POLLIN | POLLOUT;
+            cynaraFdEvents = POLLIN | POLLOUT;
             break;
         }
     }
 
+    std::atomic_thread_fence(std::memory_order_release);
     threadNotifyPut();
 }
 
@@ -834,7 +824,10 @@ void Cynara::run()
 {
     LogInfo("Cynara thread started");
     while (true) {
+        std::atomic_thread_fence(std::memory_order_acquire);
+        struct pollfd pollFds[2] = {{eventFd, POLLIN, 0}, {cynaraFd, cynaraFdEvents, 0}};
         int ret = poll(pollFds, 2, -1);
+
         if (ret == -1) {
             if (errno != EINTR)
                 LogError("Unexpected error returned by poll: " << GetErrnoString(errno));
@@ -844,23 +837,23 @@ void Cynara::run()
         // Check eventfd for termination signal
         if (pollFds[0].revents) {
             threadNotifyGet();
-            if (terminate.load()) {
+            if (terminate) {
                 LogInfo("Cynara thread terminated");
                 return;
             }
         }
 
         // Check if Cynara fd is ready for processing
-        try {
-            if (pollFds[1].revents) {
+        if (pollFds[1].revents) {
+            try {
                 // Critical section
                 std::lock_guard<std::mutex> guard(mutex);
 
                 checkCynaraError(cynara_async_process(cynara),
                     "Unexpected error returned by cynara_async_process");
+            } catch (const CynaraException::Base &e) {
+                LogError("Error while processing Cynara events: " << e.DumpToString());
             }
-        } catch (const CynaraException::Base &e) {
-            LogError("Error while processing Cynara events: " << e.DumpToString());
         }
     }
 }
index 7d78b59d18ec69d7ea7095eb3092bb061593d096..5be7344e865d9de77a0c9c6681d29f86a3ac5c0f 100644 (file)
@@ -365,7 +365,11 @@ private:
     struct pollfd pollFds[2];
     std::mutex mutex;
     std::thread thread;
-    std::atomic<bool> terminate{false};
+
+    const int eventFd;
+    std::atomic<int> cynaraFd;
+    std::atomic<short> cynaraFdEvents;
+    std::atomic<bool> terminate;
 };
 
 } // namespace SecurityManager