diff --git a/doc/source/misc.rst b/doc/source/misc.rst
index 493b285b5e1ecfa785a52da57261a64eb6ee5304..79614aba908ee5feabab58514a18216e7be066aa 100644
--- a/doc/source/misc.rst
+++ b/doc/source/misc.rst
@@ -85,6 +85,7 @@ Version 2011.2
   functionality.
 * Base :mod:`pyopencl.clrandom` on `RANLUXCL <https://bitbucket.org/ivarun/ranluxcl>`_,
   add functionality.
+* Add :class:`pyopencl.NannyEvent` objects.
 
 Version 2011.1.2
 ----------------
diff --git a/doc/source/runtime.rst b/doc/source/runtime.rst
index 973ae1588955fccfff0a88812785ee600e19cb32..978f83e2fc2ec77b0b31cde133e91f9d99634b77 100644
--- a/doc/source/runtime.rst
+++ b/doc/source/runtime.rst
@@ -268,6 +268,19 @@ Command Queues and Events
 
         See :class:`command_execution_status` for possible values of *status*.
 
+.. class:: NannyEvent
+
+    Transfers between host and device return events of this type. They hold
+    a reference to the host-side buffer and wait for the transfer to complete
+    when they are freed. Therefore, they can safely release the reference to
+    the object they're guarding upon destruction.
+
+    A subclass of :class:`Event`.
+
+    .. versionadded:: 2011.2
+
+    .. method:: get_ward()
+
 Memory
 ------
 
@@ -575,6 +588,9 @@ Transfers
     :arg is_blocking: Wait for completion. Defaults to *True*. 
       (Available on any copy involving host memory)
 
+    :return: A :class:`NannyEvent` if the transfer involved a
+        host-side buffer, otherwise an :class:`Event`.
+
     :class:`Buffer` ↔ host transfers:
 
     :arg device_offset: offset in bytes (optional)
diff --git a/src/wrapper/wrap_cl.hpp b/src/wrapper/wrap_cl.hpp
index 1a94c850dca1ae5bd97f446a97da45369da2cd66..9eef8ab045913753d091420f9a1eec6543f86ad3 100644
--- a/src/wrapper/wrap_cl.hpp
+++ b/src/wrapper/wrap_cl.hpp
@@ -221,14 +221,25 @@
         py::extract<event &>(evt)().data(); \
     }
 
-#define PYOPENCL_RETURN_NEW_EVENT(EVT) \
+#define PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, obj) \
     try \
     { \
-      return new event(EVT, false); \
+      return new nanny_event(evt, false, obj); \
     } \
     catch (...) \
     { \
-      clReleaseEvent(EVT); \
+      clReleaseEvent(evt); \
+      throw; \
+    }
+
+#define PYOPENCL_RETURN_NEW_EVENT(evt) \
+    try \
+    { \
+      return new event(evt, false); \
+    } \
+    catch (...) \
+    { \
+      clReleaseEvent(evt); \
       throw; \
     }
 
@@ -1051,6 +1062,31 @@ namespace pyopencl
       }
   };
 
+  class nanny_event : public event
+  {
+    // In addition to everything an event does, the nanny event holds a reference
+    // to a Python object and waits for its completion 
+
+    protected:
+      py::object        m_ward;
+
+    public:
+
+      nanny_event(cl_event evt, bool retain, py::object ward)
+        : event(evt, retain), m_ward(ward)
+      { }
+
+      nanny_event(nanny_event const &src)
+        : event(src), m_ward(src.m_ward)
+      { }
+
+      ~nanny_event()
+      { wait(); }
+
+      py::object get_ward() const
+      { return m_ward; }
+  };
+
 
 
 
@@ -1467,7 +1503,7 @@ namespace pyopencl
           device_offset, len, buf,
           num_events_in_wait_list, event_wait_list.empty( ) ? NULL : &event_wait_list.front(), &evt
           ));
-    PYOPENCL_RETURN_NEW_EVENT(evt);
+    PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer);
   }
 
 
@@ -1506,7 +1542,7 @@ namespace pyopencl
           device_offset, len, buf,
           num_events_in_wait_list, event_wait_list.empty( ) ? NULL : &event_wait_list.front(), &evt
           ));
-    PYOPENCL_RETURN_NEW_EVENT(evt);
+    PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer);
   }
 
 
@@ -1586,7 +1622,7 @@ namespace pyopencl
           buf,
           num_events_in_wait_list, event_wait_list.empty( ) ? NULL : &event_wait_list.front(), &evt
           ));
-    PYOPENCL_RETURN_NEW_EVENT(evt);
+    PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer);
   }
 
 
@@ -1630,7 +1666,7 @@ namespace pyopencl
           buf,
           num_events_in_wait_list, event_wait_list.empty( ) ? NULL : &event_wait_list.front(), &evt
           ));
-    PYOPENCL_RETURN_NEW_EVENT(evt);
+    PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer);
   }
 
 
@@ -1973,7 +2009,7 @@ namespace pyopencl
           origin, region, row_pitch, slice_pitch, buf,
           num_events_in_wait_list, event_wait_list.empty( ) ? NULL : &event_wait_list.front(), &evt
           ));
-    PYOPENCL_RETURN_NEW_EVENT(evt);
+    PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer);
   }
 
 
@@ -2015,7 +2051,7 @@ namespace pyopencl
           origin, region, row_pitch, slice_pitch, buf,
           num_events_in_wait_list, event_wait_list.empty( ) ? NULL : &event_wait_list.front(), &evt
           ));
-    PYOPENCL_RETURN_NEW_EVENT(evt);
+    PYOPENCL_RETURN_NEW_NANNY_EVENT(evt, buffer);
   }
 
 
diff --git a/src/wrapper/wrap_cl_part_1.cpp b/src/wrapper/wrap_cl_part_1.cpp
index 08f71f560570753fe440f4585d2162e504d9275c..3ea3709478654a9a7f9a772424939f2b2f41abe4 100644
--- a/src/wrapper/wrap_cl_part_1.cpp
+++ b/src/wrapper/wrap_cl_part_1.cpp
@@ -103,6 +103,12 @@ void pyopencl_expose_part_1()
       .def("__hash__", &cls::hash)
       ;
   }
+  {
+    typedef nanny_event cls;
+    py::class_<cls, boost::noncopyable, py::bases<event> >("NannyEvent", py::no_init)
+      .DEF_SIMPLE_METHOD(get_ward)
+      ;
+  }
 
   DEF_SIMPLE_FUNCTION(wait_for_events);
   py::def("enqueue_marker", enqueue_marker,