From 4a422db79e1be0f212692655137ef24616b9c6b3 Mon Sep 17 00:00:00 2001
From: Yichao Yu <yyc1992@gmail.com>
Date: Sat, 24 May 2014 12:56:59 -0400
Subject: [PATCH] nanny_event

---
 pyopencl/_cffi.py          |  2 +-
 src/c_wrapper/pyhelper.cpp |  8 +++++--
 src/c_wrapper/wrap_cl.cpp  | 48 +++++++++++++++++++++++++++++++++++---
 3 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/pyopencl/_cffi.py b/pyopencl/_cffi.py
index eeeb7d84..5775078f 100644
--- a/pyopencl/_cffi.py
+++ b/pyopencl/_cffi.py
@@ -182,6 +182,6 @@ def _get_insert_func(obj):
     return _insert
 
 def _find_obj(_id):
-    return _pyref[_id]
+    return _pyref.get(_id, None)
 
 _lib.set_deref(_py_deref)
diff --git a/src/c_wrapper/pyhelper.cpp b/src/c_wrapper/pyhelper.cpp
index 4ea2113e..cc490c30 100644
--- a/src/c_wrapper/pyhelper.cpp
+++ b/src/c_wrapper/pyhelper.cpp
@@ -4,11 +4,15 @@
 
 namespace pyopencl {
 
-static std::atomic<unsigned long> pyobj_id = ATOMIC_VAR_INIT(0ul);
+static std::atomic<unsigned long> pyobj_id = ATOMIC_VAR_INIT(1ul);
 unsigned long
 next_obj_id()
 {
-    return std::atomic_fetch_add(&pyobj_id, 1ul);
+    unsigned long id;
+    do {
+        id = std::atomic_fetch_add(&pyobj_id, 1ul);
+    } while (id == 0);
+    return id;
 }
 
 static int
diff --git a/src/c_wrapper/wrap_cl.cpp b/src/c_wrapper/wrap_cl.cpp
index 7478675b..350d6f53 100644
--- a/src/c_wrapper/wrap_cl.cpp
+++ b/src/c_wrapper/wrap_cl.cpp
@@ -743,15 +743,57 @@ public:
         }
     }
     virtual void
-    wait() const
+    finished()
+    {}
+    void
+    wait()
     {
         pyopencl_call_guarded(clWaitForEvents, 1, &data());
+        finished();
+    }
+};
+
+class nanny_event : public event {
+private:
+    unsigned int m_ward;
+public:
+    nanny_event(cl_event evt, bool retain, void (*reffunc)(unsigned long)=0)
+        : event(evt, retain), m_ward(0)
+    {
+        if (reffunc) {
+            m_ward = next_obj_id();
+            reffunc(m_ward);
+        }
+    }
+    ~nanny_event()
+    {
+        if (m_ward) {
+            wait();
+        }
+    }
+    unsigned int
+    get_ward() const
+    {
+        return m_ward;
+    }
+    void
+    finished()
+    {
+        // No lock needed because multiple release is safe here.
+        unsigned long ward = m_ward;
+        m_ward = 0;
+        python_deref(ward);
     }
 };
+
 static inline event*
-new_event(cl_event evt)
+new_event(cl_event evt, void (*reffunc)(unsigned long)=0)
 {
-    return pyopencl_convert_obj(event, clReleaseEvent, evt);
+    if (reffunc) {
+        return pyopencl_convert_obj(nanny_event, clReleaseEvent, evt, reffunc);
+    } else {
+        return pyopencl_convert_obj(event, clReleaseEvent, evt);
+    }
 }
 
 // }}}
-- 
GitLab