diff --git a/pybind11_protobuf/tests/BUILD b/pybind11_protobuf/tests/BUILD index dabac1a..7ac414f 100644 --- a/pybind11_protobuf/tests/BUILD +++ b/pybind11_protobuf/tests/BUILD @@ -208,3 +208,27 @@ py_test( "@com_google_absl_py//absl/testing:parameterized", ], ) + +pybind_extension( + name = "thread_module", + srcs = ["thread_module.cc"], + deps = [ + ":test_cc_proto", + "//pybind11_protobuf:native_proto_caster", + "@com_google_absl//absl/time", + "@com_google_protobuf//:protobuf", + ], +) + +py_test( + name = "thread_module_test", + srcs = ["thread_module_test.py"], + data = [":thread_module.so"], + python_version = "PY3", + srcs_version = "PY3", + deps = [ + ":test_py_pb2", + "@com_google_absl_py//absl/testing:absltest", + "@com_google_absl_py//absl/testing:parameterized", + ], +) diff --git a/pybind11_protobuf/tests/thread_module.cc b/pybind11_protobuf/tests/thread_module.cc new file mode 100644 index 0000000..283709b --- /dev/null +++ b/pybind11_protobuf/tests/thread_module.cc @@ -0,0 +1,61 @@ +// Copyright (c) 2021 The Pybind Development Team. All rights reserved. +// +// All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include + +#include +#include +#include + +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "pybind11_protobuf/native_proto_caster.h" +#include "pybind11_protobuf/tests/test.pb.h" + +namespace py = ::pybind11; + +using pybind11::test::TestMessage; + +namespace { + +PYBIND11_MODULE(thread_module, m) { + m.def( + "make_message", + [](std::string text) -> TestMessage { + TestMessage msg; + msg.set_string_value(std::move(text)); + return msg; + }, + py::arg("text") = ""); + + m.def( + "make_message_string_view", + [](std::string_view text) -> TestMessage { + TestMessage msg; + msg.set_string_value(std::string(text)); + return msg; + }, + py::arg("text") = ""); + + m.def( + "make_message_no_gil", + [](std::string text) -> TestMessage { + TestMessage msg; + msg.set_string_value(std::move(text)); + return msg; + }, + py::arg("text") = "", py::call_guard()); + + m.def( + "make_message_string_view_no_gil", + [](std::string_view text) -> TestMessage { + TestMessage msg; + msg.set_string_value(std::string(text)); + return msg; + }, + py::arg("text") = "", py::call_guard()); +} + +} // namespace diff --git a/pybind11_protobuf/tests/thread_module_test.py b/pybind11_protobuf/tests/thread_module_test.py new file mode 100644 index 0000000..f12aad7 --- /dev/null +++ b/pybind11_protobuf/tests/thread_module_test.py @@ -0,0 +1,50 @@ +"""Test pybind11_protobuf with multiple threads. + +Run with `blaze test :thread_test --config=tsan`. +""" + +import concurrent.futures + +from absl.testing import absltest +from absl.testing import parameterized +from pybind11_protobuf.tests import thread_module + + +def make_message(x): + return thread_module.make_message(x) + + +def make_message_string_view(x): + return thread_module.make_message_string_view(x) + + +def make_message_no_gil(x): + return thread_module.make_message_no_gil(x) + + +def make_message_string_view_no_gil(x): + return thread_module.make_message_string_view_no_gil(x) + + +class ThreadTest(parameterized.TestCase): + + @parameterized.named_parameters( + ('make_message', make_message), + ('make_message_string_view', make_message_string_view), + ('make_message_no_gil', make_message_no_gil), + # BUG: https://github.com/pybind/pybind11/issues/2765 + # The following fails due to std::string_view casting in pybind11 + # ('make_message_string_view_no_gil', make_message_string_view_no_gil), + ) + def test_parallel(self, fn): + fn('a') + + with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor: + results = list(executor.map(fn, ['abc'] * 10)) + + for x in results: + self.assertEqual('abc', x.string_value) + + +if __name__ == '__main__': + absltest.main()