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,