From c68bd228d87f63ede3bfc4113d7ef670b7de5881 Mon Sep 17 00:00:00 2001
From: Yichao Yu <yyc1992@gmail.com>
Date: Mon, 16 Jun 2014 04:50:36 -0400
Subject: [PATCH] do not assume cffi.new_handle always returns the same address
 for the same object (need to check)

---
 pyopencl/_cffi.py                 |  9 ++++++++-
 pyopencl/c_wrapper/wrap_cl_core.h |  2 +-
 pyopencl/cffi_cl.py               |  5 ++++-
 src/c_wrapper/event.cpp           | 14 +++++++++-----
 src/c_wrapper/event.h             |  4 ++--
 src/c_wrapper/pyhelper.cpp        |  4 ++--
 src/c_wrapper/pyhelper.h          |  2 +-
 7 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/pyopencl/_cffi.py b/pyopencl/_cffi.py
index 953be862..60cb2e69 100644
--- a/pyopencl/_cffi.py
+++ b/pyopencl/_cffi.py
@@ -187,9 +187,16 @@ def _py_deref(handle):
     except:
         pass
 
-@_ffi.callback('void(void*)')
+# TODO:
+# Not sure if cffi always return the same address for the same object
+# Unless it is, this function might return a different pointer from its input
+# and should only be called once.
+@_ffi.callback('void*(void*)')
 def _py_ref(handle):
+    obj = _ffi.from_handle(handle)
+    handle = _ffi.new_handle(obj)
     _pyrefs[handle] = handle
+    return handle
 
 @_ffi.callback('void(void*, cl_int)')
 def _py_call(handle, status):
diff --git a/pyopencl/c_wrapper/wrap_cl_core.h b/pyopencl/c_wrapper/wrap_cl_core.h
index 7069dcbc..5427fa3c 100644
--- a/pyopencl/c_wrapper/wrap_cl_core.h
+++ b/pyopencl/c_wrapper/wrap_cl_core.h
@@ -48,7 +48,7 @@ typedef struct {
 int get_cl_version();
 void free_pointer(void*);
 void free_pointer_array(void**, uint32_t size);
-void set_py_funcs(int (*_gc)(), void (*_ref)(void*), void (*_deref)(void*),
+void set_py_funcs(int (*_gc)(), void *(*_ref)(void*), void (*_deref)(void*),
                   void (*_call)(void*, cl_int));
 int have_gl();
 
diff --git a/pyopencl/cffi_cl.py b/pyopencl/cffi_cl.py
index 29d2dec0..1ee6ac73 100644
--- a/pyopencl/cffi_cl.py
+++ b/pyopencl/cffi_cl.py
@@ -847,7 +847,10 @@ def wait_for_events(wait_for):
 
 class NannyEvent(Event):
     def get_ward(self):
-        return _ffi.from_handle(_lib.nanny_event__get_ward(self.ptr))
+        _handle = _lib.nanny_event__get_ward(self.ptr)
+        if _handle == _ffi.NULL:
+            return
+        return _ffi.from_handle(_handle)
 
 # TODO
 #   UserEvent
diff --git a/src/c_wrapper/event.cpp b/src/c_wrapper/event.cpp
index d7373af4..61af726c 100644
--- a/src/c_wrapper/event.cpp
+++ b/src/c_wrapper/event.cpp
@@ -143,11 +143,15 @@ event__set_callback(clobj_t _evt, cl_int type, void *pyobj)
 {
     auto evt = static_cast<event*>(_evt);
     return c_handle_error([&] {
-            evt->set_callback(type, [=] (cl_int status) {
-                    py::call(pyobj, status);
-                    py::deref(pyobj);
-                });
-            py::ref(pyobj);
+            pyobj = py::ref(pyobj);
+            try {
+                evt->set_callback(type, [=] (cl_int status) {
+                        py::call(pyobj, status);
+                        py::deref(pyobj);
+                    });
+            } catch (...) {
+                py::deref(pyobj);
+            }
         });
 }
 #endif
diff --git a/src/c_wrapper/event.h b/src/c_wrapper/event.h
index 7f3d6759..3bcd0902 100644
--- a/src/c_wrapper/event.h
+++ b/src/c_wrapper/event.h
@@ -43,10 +43,10 @@ private:
     void *m_ward;
 public:
     nanny_event(cl_event evt, bool retain, void *ward=nullptr)
-        : event(evt, retain), m_ward(ward)
+        : event(evt, retain), m_ward(nullptr)
     {
         if (ward) {
-            py::ref(ward);
+            m_ward = py::ref(ward);
         }
     }
     ~nanny_event();
diff --git a/src/c_wrapper/pyhelper.cpp b/src/c_wrapper/pyhelper.cpp
index ca18c96a..0000728e 100644
--- a/src/c_wrapper/pyhelper.cpp
+++ b/src/c_wrapper/pyhelper.cpp
@@ -4,7 +4,7 @@ namespace pyopencl {
 
 namespace py {
 WrapFunc<int()> gc;
-WrapFunc<void(void*)> ref;
+WrapFunc<void*(void*)> ref;
 WrapFunc<void(void*)> deref;
 WrapFunc<void(void*, cl_int)> call;
 }
@@ -12,7 +12,7 @@ WrapFunc<void(void*, cl_int)> call;
 }
 
 void
-set_py_funcs(int (*_gc)(), void (*_ref)(void*), void (*_deref)(void*),
+set_py_funcs(int (*_gc)(), void *(*_ref)(void*), void (*_deref)(void*),
              void (*_call)(void*, cl_int))
 {
     pyopencl::py::gc = _gc;
diff --git a/src/c_wrapper/pyhelper.h b/src/c_wrapper/pyhelper.h
index f336cbae..15a72f47 100644
--- a/src/c_wrapper/pyhelper.h
+++ b/src/c_wrapper/pyhelper.h
@@ -37,7 +37,7 @@ public:
 
 namespace py {
 extern WrapFunc<int()> gc;
-extern WrapFunc<void(void*)> ref;
+extern WrapFunc<void*(void*)> ref;
 extern WrapFunc<void(void*)> deref;
 extern WrapFunc<void(void*, cl_int)> call;
 }
-- 
GitLab