Skip to content

Commit 6445feb

Browse files
Python: reacquire GIL for deallocation operations (#1878)
* Delete stray inc_ref * Reaquire the GIL for releasing references to Python buffers * Use std::optional for simplified explicit destruction * Make Iterator GIL free * Add this also for other flushing methods
1 parent 5d93ce0 commit 6445feb

4 files changed

Lines changed: 38 additions & 34 deletions

File tree

src/binding/python/Attributable.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,11 +520,17 @@ void init_Attributable(py::module &m)
520520
})
521521
.def(
522522
"series_flush",
523-
py::overload_cast<std::string>(&Attributable::seriesFlush),
523+
[](Attributable &attr, std::string const &backend_config) {
524+
py::gil_scoped_release release_gil;
525+
attr.seriesFlush(backend_config);
526+
},
524527
py::arg("backend_config") = "{}")
525528
.def(
526529
"iteration_flush",
527-
py::overload_cast<std::string>(&Attributable::iterationFlush),
530+
[](Attributable &attr, std::string const &backend_config) {
531+
py::gil_scoped_release release_gil;
532+
attr.iterationFlush(backend_config);
533+
},
528534
py::arg("backend_config") = "{}")
529535

530536
.def_property_readonly(

src/binding/python/Iteration.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,10 @@ void init_Iteration(py::module &m)
8282
})
8383
.def(
8484
"close",
85-
/*
86-
* Cannot release the GIL here since Python buffers might be
87-
* accessed in deferred tasks
88-
*/
89-
&Iteration::close,
85+
[](Iteration &iteration, bool flush) {
86+
py::gil_scoped_release release_gil;
87+
iteration.close(flush);
88+
},
9089
py::arg("flush") = true)
9190

9291
// TODO remove in future versions (deprecated)

src/binding/python/RecordComponent.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121
#include <limits>
2222
#include <pybind11/detail/common.h>
23+
#include <pybind11/gil.h>
2324
#include <pybind11/numpy.h>
2425
#include <pybind11/pybind11.h>
2526
#include <pybind11/pytypes.h>
@@ -330,8 +331,11 @@ struct StoreChunkFromPythonArray
330331
// note: this does not yet prevent the user, as in C++, to build
331332
// a race condition by manipulating the data that was passed
332333
std::shared_ptr<T> shared(
333-
(T *)data, [owning_handle = a.cast<py::object>()](T *) {
334-
// no-op
334+
(T *)data,
335+
[owning_handle =
336+
std::make_optional(a.cast<py::object>())](T *) mutable {
337+
py::gil_scoped_acquire need_the_gil_for_this;
338+
owning_handle.reset();
335339
});
336340
r.storeChunk(std::move(shared), offset, extent);
337341
}
@@ -353,8 +357,11 @@ struct LoadChunkIntoPythonArray
353357
// note: this does not yet prevent the user, as in C++, to build
354358
// a race condition by manipulating the data that was passed
355359
std::shared_ptr<T> shared(
356-
(T *)data, [owning_handle = a.cast<py::object>()](T *) {
357-
// no-op
360+
(T *)data,
361+
[owning_handle =
362+
std::make_optional(a.cast<py::object>())](T *) mutable {
363+
py::gil_scoped_acquire need_the_gil_for_this;
364+
owning_handle.reset();
358365
});
359366
r.loadChunk(std::move(shared), offset, extent);
360367
}
@@ -377,8 +384,11 @@ struct LoadChunkIntoPythonBuffer
377384
// note: this does not yet prevent the user, as in C++, to build
378385
// a race condition by manipulating the data that was passed
379386
std::shared_ptr<T> shared(
380-
(T *)data, [owning_handle = buffer.cast<py::object>()](T *) {
381-
// no-op
387+
(T *)data,
388+
[owning_handle =
389+
std::make_optional(buffer.cast<py::object>())](T *) mutable {
390+
py::gil_scoped_acquire need_the_gil_for_this;
391+
owning_handle.reset();
382392
});
383393
r.loadChunk(std::move(shared), offset, extent);
384394
}

src/binding/python/Series.cpp

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
#include <optional>
3737
#include <pybind11/attr.h>
38+
#include <pybind11/gil.h>
3839
#include <stdexcept>
3940
#include <tuple>
4041

@@ -283,22 +284,8 @@ not possible once it has been closed.
283284
.def(
284285
"__getitem__",
285286
[](Snapshots &s, Series::IterationIndex_t key) {
286-
switch (s.snapshotWorkflow())
287-
{
288-
case openPMD::SnapshotWorkflow::RandomAccess:
289-
return s[key];
290-
case openPMD::SnapshotWorkflow::Synchronous:
291-
auto lastIteration = s.currentIteration();
292-
if (lastIteration.has_value() &&
293-
lastIteration.value()->first != key)
294-
{
295-
// this must happen under the GIL
296-
lastIteration.value()->second.close();
297-
}
298-
py::gil_scoped_release release;
299-
return s[key];
300-
}
301-
throw std::runtime_error("Unreachable");
287+
py::gil_scoped_release release;
288+
return s[key];
302289
},
303290
// copy + keepalive
304291
py::return_value_policy::copy,
@@ -336,10 +323,6 @@ not possible once it has been closed.
336323
*/
337324
if (!iterator.first_iteration)
338325
{
339-
if (!(*iterator).closed())
340-
{
341-
(*iterator).close();
342-
}
343326
py::gil_scoped_release release;
344327
++iterator;
345328
}
@@ -482,7 +465,13 @@ this method.
482465
&Series::iterationFormat,
483466
&Series::setIterationFormat)
484467
.def_property("name", &Series::name, &Series::setName)
485-
.def("flush", &Series::flush, py::arg("backend_config") = "{}")
468+
.def(
469+
"flush",
470+
[](Series &s, std::string const &backend_config) {
471+
py::gil_scoped_release release_gil;
472+
s.flush(backend_config);
473+
},
474+
py::arg("backend_config") = "{}")
486475

487476
.def_property_readonly(
488477
"backend", static_cast<std::string (Series::*)()>(&Series::backend))

0 commit comments

Comments
 (0)