c++/lib c++/tests DEVELOPMENT

Christian Mollekopf mollekopf at kolabsys.com
Fri Feb 24 01:34:25 CET 2012


 DEVELOPMENT                  |   16 ++++++++++
 c++/lib/CMakeLists.txt       |    2 -
 c++/lib/utils.cpp            |   66 +++++++++++++++++++++++++++++--------------
 c++/tests/conversiontest.cpp |   33 +++++++++++++++++++++
 c++/tests/conversiontest.h   |    2 +
 5 files changed, 97 insertions(+), 22 deletions(-)

New commits:
commit 177938de4a173c5a087d55de23320d28ec6102b9
Author: Christian Mollekopf <mollekopf at kolabsys.com>
Date:   Fri Feb 24 01:31:50 2012 +0100

    ThreadLocal storage of globals for thread safety. Doesn't work when called from python...

diff --git a/DEVELOPMENT b/DEVELOPMENT
index 3a60e90..db795c3 100644
--- a/DEVELOPMENT
+++ b/DEVELOPMENT
@@ -1,3 +1,19 @@
+Building:
+
+To build everything including the pykolab stuff:
+# autoreconf -v
+# ./configure
+# make
+
+If you get "error: possibly undefined macro: AC_PROG_INTLTOOL" on autoreconf you might need to install intltool.
+
+For the python tests:
+# make quicktest
+
+Make sure you have "nosetests"  for python2 is installed (python2-nose on arch). Otherwise you will get an error that "PyInit__kolabformat" could not be found.
+
+For the library only, switch to the c++ directory and read the instructinos in there
+
 Branch layout:
 
   master
diff --git a/c++/lib/CMakeLists.txt b/c++/lib/CMakeLists.txt
index 9cc48f1..dfd4921 100644
--- a/c++/lib/CMakeLists.txt
+++ b/c++/lib/CMakeLists.txt
@@ -10,7 +10,7 @@ set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC " ) #always generate shared libra
 
 #Library with serialization/deserialization code and kolab-containers
 add_library(kolabxml SHARED kolabformat.cpp kolabcontainers.cpp kolabevent.cpp kolabtodo.cpp kolabjournal.cpp kolabcontact.cpp utils.cpp base64.cpp ../compiled/XMLParserWrapper.cpp ../compiled/grammar-input-stream.cxx ${SCHEMA_SOURCEFILES})
-target_link_libraries(kolabxml ${XERCES_C})
+target_link_libraries(kolabxml ${XERCES_C} boost_thread)
 
 #For the core library we can be stricter when compiling. This doesn't work with the auto generated code though.
 set_target_properties(kolabxml PROPERTIES COMPILE_FLAGS "-Wl,--no-undefined -Werror ")
diff --git a/c++/lib/utils.cpp b/c++/lib/utils.cpp
index b3862d3..c9ed61c 100644
--- a/c++/lib/utils.cpp
+++ b/c++/lib/utils.cpp
@@ -20,46 +20,72 @@
 #include <boost/uuid/uuid.hpp>
 #include <boost/uuid/uuid_io.hpp>
 #include <boost/lexical_cast.hpp>
+#include <boost/thread.hpp>
 #include <time.h>
 #include "base64.h"
 
 namespace Kolab {
     
 namespace Utils {
+
+/**
+ * We have to store our global variables thread-local to ensure thread-safety.
+ */
+struct Global {
+    std::string createdUID;
+    std::string productId;
+    std::string xKolabVersion;
     
-std::string global_createdUID;
-std::string global_productId;
-std::string global_xKolabVersion;
+    ErrorSeverity errorBit;
+    std::string errorMessage;
+};
+
+boost::thread_specific_ptr<Global> ptr;
+class ThreadLocal
+{
+public:
+   static Global &inst()
+   {
+      Global *t = ptr.get();
+      std::cout << "inst " << boost::this_thread::get_id() << std::endl;
+      if (!t) {
+          std::cout << "initialize Global" << std::endl;
+         t = new Global();
+         ptr.reset(t);
+      }
+      return *t;
+   }
+};
 
 void setKolabVersion(const std::string &s)
 {
-    global_xKolabVersion = s;
+    ThreadLocal::inst().xKolabVersion = s;
 }
 
 std::string kolabVersion()
 {
-    return global_xKolabVersion;
+    return ThreadLocal::inst().xKolabVersion;
 }
 
 void setProductId(const std::string &s)
 {
-    global_productId = s;
+    ThreadLocal::inst().productId = s;
 }
 
 std::string productId()
 {
-    return global_productId;
+    return ThreadLocal::inst().productId;
 }
 
 
 void setCreatedUid(const std::string &s)
 {
-    global_createdUID = s;
+    ThreadLocal::inst().createdUID = s;
 }
 
 std::string createdUid()
 {
-    return global_createdUID;
+    return ThreadLocal::inst().createdUID;
 }
 
 
@@ -81,8 +107,6 @@ DateTime getCurrentTime()
     return DateTime(ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, true);
 }
 
-ErrorSeverity global_errorBit;
-std::string global_errorMessage;
 
 void logMessage(const std::string &m, ErrorSeverity s)
 {
@@ -95,17 +119,17 @@ void logMessage(const std::string &m, ErrorSeverity s)
             break;
         case Error:
             std::cerr << "Error: " << m << std::endl;
-            if (global_errorBit < Error) {
-                global_errorBit = Error;
-                global_errorMessage = m;
+            if (ThreadLocal::inst().errorBit < Error) {
+                ThreadLocal::inst().errorBit = Error;
+                ThreadLocal::inst().errorMessage = m;
             }
             break;
         case Critical:
         default:
             std::cerr << "Critical: " << m << std::endl;
-            if (global_errorBit < Critical) {
-                global_errorBit = Critical;
-                global_errorMessage = m;
+            if (ThreadLocal::inst().errorBit < Critical) {
+                ThreadLocal::inst().errorBit = Critical;
+                ThreadLocal::inst().errorMessage = m;
             }
     }
 }
@@ -117,18 +141,18 @@ void logMessage(const std::string &message, const std::string &file, int line, E
 
 void clearErrors()
 {
-    global_errorBit = NoError;
-    global_errorMessage.clear();
+    ThreadLocal::inst().errorBit = NoError;
+    ThreadLocal::inst().errorMessage.clear();
 }
 
 ErrorSeverity getError()
 {
-    return global_errorBit;
+    return ThreadLocal::inst().errorBit;
 }
 
 std::string getErrorMessage()
 {
-    return global_errorMessage;
+    return ThreadLocal::inst().errorMessage;
 }
 
 
diff --git a/c++/tests/conversiontest.cpp b/c++/tests/conversiontest.cpp
index 369e380..95c4bf1 100644
--- a/c++/tests/conversiontest.cpp
+++ b/c++/tests/conversiontest.cpp
@@ -6,6 +6,7 @@
 #include <lib/utils.h>
 
 #include "serializers.h"
+#include <boost/thread.hpp>
 
 Q_DECLARE_METATYPE(Kolab::Duration);
 Q_DECLARE_METATYPE(Kolab::DayPos);
@@ -141,6 +142,38 @@ void ConversionTest::uriInlineEncodingTest()
     QCOMPARE(d, std::string("data"));
 }
 
+void wait(int seconds) 
+{ 
+  boost::this_thread::sleep(boost::posix_time::seconds(seconds)); 
+} 
+
+void threadF() 
+{ 
+  for (int i = 0; i < 5; ++i) 
+  { 
+      std::stringstream s;
+      s << boost::this_thread::get_id();
+    std::string uid = s.str();//std::string(boost::this_thread::get_id());
+    std::cout << uid << std::endl; 
+    Kolab::Utils::setCreatedUid(uid);
+    wait(1);
+    if (Kolab::Utils::createdUid() != uid) {
+        std::cout << "Error " << uid << std::endl; 
+    } else {
+        std::cout << "ok" << std::endl; 
+    }
+  } 
+} 
+
+void ConversionTest::threadLocalTest()
+{
+    boost::thread t(threadF);
+  boost::thread t2(threadF); 
+  t.join(); 
+  t2.join(); 
+}
+
+
 
 
 QTEST_MAIN( ConversionTest )
diff --git a/c++/tests/conversiontest.h b/c++/tests/conversiontest.h
index 3b4739e..41eda33 100644
--- a/c++/tests/conversiontest.h
+++ b/c++/tests/conversiontest.h
@@ -28,6 +28,8 @@ class ConversionTest : public QObject
     void xCardSerializerTest();
     
     void uriInlineEncodingTest();
+    
+    void threadLocalTest();
 };
 
 #endif // CONVERSIONTEST_H





More information about the commits mailing list