cedric pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=4105c002b3161d67600a22b2f570c4969a6b36b2

commit 4105c002b3161d67600a22b2f570c4969a6b36b2
Author: Felipe Magno de Almeida <fel...@expertisesolutions.com.br>
Date:   Fri Mar 7 14:33:07 2014 +0900

    ecore-cxx: add support for exceptions.
    
    Summary:
    Added support for exceptions on ecore_main_loop_thread_safe_call_async and
    ecore_main_loop_thread_safe_call_sync. Also optimized the transport of the
    return value through a parameter on ecore_main_loop_thread_safe_call_sync.
    
    ecore-cxx: Changed uses of alignas for aligned_storage in C++11
    
    Reviewers: cedric, raster
    
    CC: savio, cedric
    
    Differential Revision: https://phab.enlightenment.org/D593
    
    Signed-off-by: Cedric BAIL <cedric.b...@samsung.com>
---
 src/bindings/ecore_cxx/Ecore.hh                 | 177 +++++++++++++++---------
 src/bindings/eina_cxx/eina_error.hh             |  14 ++
 src/tests/ecore_cxx/ecore_cxx_test_safe_call.cc |  91 ++++++++++--
 3 files changed, 210 insertions(+), 72 deletions(-)

diff --git a/src/bindings/ecore_cxx/Ecore.hh b/src/bindings/ecore_cxx/Ecore.hh
index 9d2dd0b..b121ba9 100644
--- a/src/bindings/ecore_cxx/Ecore.hh
+++ b/src/bindings/ecore_cxx/Ecore.hh
@@ -3,6 +3,8 @@
 
 #include <Ecore.h>
 
+#include <Eina.hh>
+
 #include <utility>
 #include <type_traits>
 #include <memory>
@@ -10,83 +12,100 @@
 
 namespace efl { namespace ecore {
 
-template <typename T, typename Enable = void>
-struct _ecore_result_type_marshaller;
-
 template <typename T>
-struct _ecore_result_type_marshaller
-  <T, typename std::enable_if<std::is_pointer<T>::value>::type>
+struct _identity
 {
-  static void* to_void(T o)
-  {
-    return static_cast<void*>(o);
-  }
-  static T from_void(void* o)
-  {
-    return static_cast<T>(o);
-  }
+  typedef T type;
 };
 
-template <typename T>
-struct _ecore_result_type_marshaller
- <T, typename std::enable_if<!std::is_pointer<T>::value && 
std::is_pod<T>::value
-                              && sizeof(T) <= sizeof(void*)>::type>
+template <typename F>
+void _ecore_main_loop_thread_safe_call_async_callback(void* data)
 {
-  static void* to_void(T&& o)
-  {
-    unsigned char buf[sizeof(void*)];
-    T* p = static_cast<T*>(static_cast<void*>(&buf[0]));
-    new (p) T(std::move(o));
-    void* store;
-    std::memcpy(&store, buf, sizeof(void*));
-    return store;
-  }
-  static T from_void(void* store)
-  {
-    T* p = static_cast<T*>(static_cast<void*>(&store));
-    struct destroy_T
+  std::unique_ptr<F> f (static_cast<F*>(data));
+  try
     {
-      destroy_T(T& p)
-        : p(p) {}
-      ~destroy_T()
-      {
-        p.~T();
-      }
-      T& p;
-    } destroy(*p);
-    return T(std::move(*p));
-  }
-};
+      (*f)();
+    }
+  catch(std::bad_alloc const& e)
+    {
+      eina_error_set( ::EINA_ERROR_OUT_OF_MEMORY);
+    }
+  catch(std::system_error const& e)
+    {
+      efl::eina::set_error_code(e.code());
+    }
+  catch(...)
+    {
+      eina_error_set( efl::eina::unknown_error() );
+    }
+}
 
 template <typename T>
-struct _ecore_result_type_marshaller
-<T, typename std::enable_if<(sizeof(T) > sizeof(void*)) || 
!std::is_pod<T>::value>::type>
+struct _return_buffer
+{
+  typename std::aligned_storage<sizeof(T),std::alignment_of<T>::value>::type 
buffer;
+};
+
+template <>
+struct _return_buffer<void>
 {
-  static void* to_void(T&& o)
-  {
-    return new T(o);
-  }
-  static T from_void(void* store)
-  {
-    std::unique_ptr<T> p(static_cast<T*>(store));
-    return T(std::move(*p.get()));
-  }
 };
 
 template <typename F>
-void _ecore_main_loop_thread_safe_call_async_callback(void* data)
+struct _data
 {
-  F* f = static_cast<F*>(data);
-  (*f)();
-  delete f;
+  F& f;
+  std::exception_ptr exception;
+  typedef typename std::result_of<F()>::type result_type;
+  _return_buffer<result_type> return_buffer;
+};
+
+template <typename F>
+void* _ecore_main_loop_thread_safe_call_sync_callback_aux(_data<F>* d, 
_identity<void>)
+{
+  d->f();
+  if(eina_error_get())
+    d->exception = 
make_exception_ptr(std::system_error(efl::eina::get_error_code()));
+  return 0;
+}
+
+template <typename F, typename R>
+void* _ecore_main_loop_thread_safe_call_sync_callback_aux(_data<F>* d, 
_identity<R>)
+{
+  typedef R result_type;
+  new (&d->return_buffer.buffer) result_type ( std::move(d->f()) );
+  if(eina_error_get())
+    {
+      d->exception = 
make_exception_ptr(std::system_error(efl::eina::get_error_code()));
+      eina_error_set(0);
+      result_type* p = 
static_cast<result_type*>(static_cast<void*>(&d->return_buffer.buffer));
+      p->~result_type();
+    }
+  return 0;
 }
 
 template <typename F>
 void* _ecore_main_loop_thread_safe_call_sync_callback(void* data)
 {
-  F* f = static_cast<F*>(data);
-  typedef typename std::result_of<F()>::type result_type;
-  return _ecore_result_type_marshaller<result_type>::to_void((*f)());
+  _data<F>* d = static_cast<_data<F>*>(data);
+  try
+    {
+      return _ecore_main_loop_thread_safe_call_sync_callback_aux
+        (d, _identity<typename std::result_of<F()>::type>());
+    }
+  catch(std::bad_alloc const& e)
+    {
+      d->exception = std::current_exception();
+    }
+  catch(std::system_error const& e)
+    {
+      d->exception = std::current_exception();
+    }
+  catch(...)
+    {
+      d->exception = std::current_exception();
+    }
+  return 0;
 }
 
 template <typename F>
@@ -97,13 +116,47 @@ void main_loop_thread_safe_call_async(F&& f)
 }
 
 template <typename F>
+void _get_return_value(_data<F>& data, _identity<void>)
+{
+  if(data.exception)
+    {
+      std::rethrow_exception(data.exception);
+    }
+}
+
+template <typename F, typename R>
+R _get_return_value(_data<F>& data, _identity<R>)
+{
+  if(!data.exception)
+    {
+      R* b = static_cast<R*>(static_cast<void*>(&data.return_buffer.buffer));
+      struct destroy
+      {
+        destroy(R* p) : p(p)
+        {}
+        ~destroy()
+        {
+          p->~R();
+        }
+        R* p;
+      } destroy_temp(b);
+      return std::move(*b);
+    }
+  else
+    {
+      std::rethrow_exception(data.exception);
+    }
+}
+
+template <typename F>
 typename std::result_of<F()>::type
 main_loop_thread_safe_call_sync(F&& f)
 {
-  void* d = ::ecore_main_loop_thread_safe_call_sync
-    (&ecore::_ecore_main_loop_thread_safe_call_sync_callback<F>, &f);
   typedef typename std::result_of<F()>::type result_type;
-  return _ecore_result_type_marshaller<result_type>::from_void(d);
+  _data<F> data {f};
+  ::ecore_main_loop_thread_safe_call_sync
+      (&ecore::_ecore_main_loop_thread_safe_call_sync_callback<F>, &data);
+  return _get_return_value(data, _identity<result_type>());
 }
 
 struct ecore_init
diff --git a/src/bindings/eina_cxx/eina_error.hh 
b/src/bindings/eina_cxx/eina_error.hh
index 1199e69..9962768 100644
--- a/src/bindings/eina_cxx/eina_error.hh
+++ b/src/bindings/eina_cxx/eina_error.hh
@@ -13,6 +13,12 @@ using std::error_code;
 using std::error_condition;
 typedef std::error_category system_error_category;
 
+inline Eina_Error unknown_error()
+{
+  static Eina_Error error = eina_error_msg_static_register("Error from C++ 
from another value category error");
+  return error;
+}
+
 inline system_error_category const& get_generic_category()
 {
   return ::std::generic_category();
@@ -66,6 +72,14 @@ inline eina::error_code get_error_code()
     return eina::error_code();
 }
 
+inline void set_error_code(eina::error_code const& e)
+{
+  if(e.category() == eina_error_category())
+    eina_error_set(e.value());
+  else
+    eina_error_set(unknown_error());
+}
+
 inline eina::error_condition get_error_condition()
 {
   Eina_Error error = eina_error_get();
diff --git a/src/tests/ecore_cxx/ecore_cxx_test_safe_call.cc 
b/src/tests/ecore_cxx/ecore_cxx_test_safe_call.cc
index bc2b78d..9be7d73 100644
--- a/src/tests/ecore_cxx/ecore_cxx_test_safe_call.cc
+++ b/src/tests/ecore_cxx/ecore_cxx_test_safe_call.cc
@@ -8,19 +8,28 @@
 
 #include <check.h>
 
-void call_async(efl::eina::mutex& mutex, efl::eina::condition_variable& cond, 
bool& done)
+void call_async(efl::eina::mutex& mutex, efl::eina::condition_variable& cond, 
int& done)
 {
   efl::ecore::main_loop_thread_safe_call_async
     (
      [&mutex,&cond,&done]
      {
        std::cout << "yeah" << std::endl;
-       ecore_main_loop_quit();
        efl::eina::unique_lock<efl::eina::mutex> l(mutex);
-       std::cout << "mutex locked" << std::endl;
-       done = true;
+       ++done;
+     }
+    );
+
+  efl::ecore::main_loop_thread_safe_call_async
+    (
+     [&mutex,&cond,&done]
+     {
+       std::cout << "yeah2" << std::endl;
+       efl::eina::unique_lock<efl::eina::mutex> l(mutex);
+       ++done;
        cond.notify_one();
-       std::cout << "exiting" << std::endl;
+       ecore_main_loop_quit();
+       throw std::bad_alloc();
      }
     );
 }
@@ -31,7 +40,7 @@ START_TEST(ecore_cxx_safe_call_async)
 
   efl::eina::mutex mutex;
   efl::eina::condition_variable cond;
-  bool done = false;
+  int done = 0;
   efl::eina::thread thread(&call_async, std::ref(mutex), std::ref(cond), 
std::ref(done));
 
   ecore_main_loop_begin();
@@ -43,13 +52,15 @@ START_TEST(ecore_cxx_safe_call_async)
   std::cout << "joined" << std::endl;
 
   efl::eina::unique_lock<efl::eina::mutex> l(mutex);
-  while(!done)
+  while(done != 2)
     {
-      std::cout << "waiting" << std::endl;
+      std::cout << "wait" << std::endl;
       cond.wait(l);
       std::cout << "waited" << std::endl;
     }
 
+  ck_assert( ::eina_error_get() == ::EINA_ERROR_OUT_OF_MEMORY);
+  ::eina_error_set(0);
   std::cout << "end of ecore_cxx_safe_call_async" << std::endl;
 }
 END_TEST
@@ -111,7 +122,14 @@ struct big_nonpod : big_pod
 
 void call_sync_int()
 {
-  std::cout << "call_sync_init" << std::endl;
+  efl::ecore::main_loop_thread_safe_call_sync
+    (
+     [] () -> void
+     {
+       ck_assert( ::eina_error_get() == 0);
+     }
+    );
+
   int r1 =
   efl::ecore::main_loop_thread_safe_call_sync
     (
@@ -122,6 +140,37 @@ void call_sync_int()
     );
   ck_assert(r1 == 1);
 
+  try
+    {
+      efl::ecore::main_loop_thread_safe_call_sync
+        (
+         [] () -> int
+         {
+           throw std::bad_alloc();
+         }
+         );
+      ck_assert(false);
+    }
+  catch(std::bad_alloc const& e)
+    {
+    }
+
+  try
+    {
+      efl::ecore::main_loop_thread_safe_call_sync
+        (
+         [] () -> int
+         {
+           ::eina_error_set( ::EINA_ERROR_OUT_OF_MEMORY);
+           return 0;
+         }
+         );
+      ck_assert(false);
+    }
+  catch(std::system_error const& e)
+    {
+    }
+
   std::cout << "big_pod" << std::endl;
 
   big_pod r2 =
@@ -160,7 +209,6 @@ void call_sync_int()
        [] () -> big_nonpod
        {
          std::cout << "before quit" << std::endl;
-         ecore_main_loop_quit();
          std::cout << "are we calling here" << std::endl;
          return big_nonpod();
        }
@@ -169,6 +217,29 @@ void call_sync_int()
   std::cout << "constructor_called: " << constructor_called << std::endl;
   std::cout << "destructor_called: " << destructor_called << std::endl;
   ck_assert(constructor_called == destructor_called);
+
+  {
+    try
+      {
+        efl::ecore::main_loop_thread_safe_call_sync
+          (
+           [] () -> big_nonpod
+           {
+             std::cout << "before quit" << std::endl;
+             ecore_main_loop_quit();
+             std::cout << "are we calling here" << std::endl;
+             throw std::bad_alloc();
+           }
+           );
+        ck_assert(false);
+      }
+    catch(std::bad_alloc const& e)
+      {
+      }
+  }
+  std::cout << "constructor_called: " << constructor_called << std::endl;
+  std::cout << "destructor_called: " << destructor_called << std::endl;
+  ck_assert(constructor_called == destructor_called);
 }
 
 START_TEST(ecore_cxx_safe_call_sync)

-- 


Reply via email to