winrt-runtime 4.0.2__tar.gz → 4.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. {winrt_runtime-4.0.2/python/winrt_runtime.egg-info → winrt_runtime-4.0.3}/PKG-INFO +1 -1
  2. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3/python/winrt_runtime.egg-info}/PKG-INFO +1 -1
  3. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt_runtime.egg-info/SOURCES.txt +1 -0
  4. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/setup.py +1 -0
  5. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/_winrt.cpp +13 -7
  6. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/compose.cpp +44 -7
  7. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/delegates.cpp +7 -1
  8. winrt_runtime-4.0.3/src/handles.cpp +159 -0
  9. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/pywinrt/handles.h +26 -4
  10. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/interp.cpp +1 -1
  11. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/objects.cpp +14 -5
  12. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/objects.h +24 -4
  13. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/protocols.cpp +12 -2
  14. winrt_runtime-4.0.3/version.txt +1 -0
  15. winrt_runtime-4.0.2/version.txt +0 -1
  16. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/LICENSE +0 -0
  17. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/MANIFEST.in +0 -0
  18. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/README.md +0 -0
  19. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/pyproject.toml +0 -0
  20. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt/__pyinstaller/__init__.py +0 -0
  21. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt/__pyinstaller/hook-winrt.py +0 -0
  22. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt/_winrt.pyi +0 -0
  23. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt/py.typed +0 -0
  24. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt/runtime/__init__.py +0 -0
  25. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt/runtime/_internals.py +0 -0
  26. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt/runtime/interop.py +0 -0
  27. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt/runtime/py.typed +0 -0
  28. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt/system/__init__.py +0 -0
  29. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt/system/hresult.py +0 -0
  30. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt/system/py.typed +0 -0
  31. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt_runtime.egg-info/dependency_links.txt +0 -0
  32. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt_runtime.egg-info/entry_points.txt +0 -0
  33. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt_runtime.egg-info/requires.txt +0 -0
  34. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/python/winrt_runtime.egg-info/top_level.txt +0 -0
  35. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/requirements.txt +0 -0
  36. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/setup.cfg +0 -0
  37. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/_winrt_array.cpp +0 -0
  38. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/_winrt_array.h +0 -0
  39. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/_winrt_box.cpp +0 -0
  40. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/_winrt_buffer.cpp +0 -0
  41. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/_winrt_buffer.h +0 -0
  42. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/arrays.cpp +0 -0
  43. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/arrays.h +0 -0
  44. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/async.cpp +0 -0
  45. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/async.h +0 -0
  46. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/callbacks.cpp +0 -0
  47. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/callbacks.h +0 -0
  48. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/collections.cpp +0 -0
  49. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/collections.h +0 -0
  50. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/compose.h +0 -0
  51. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/delegates.h +0 -0
  52. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/enums.cpp +0 -0
  53. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/enums.h +0 -0
  54. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/errors.cpp +0 -0
  55. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/generics.cpp +0 -0
  56. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/generics.h +0 -0
  57. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/implements.cpp +0 -0
  58. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/implements.h +0 -0
  59. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/Windows.Foundation.Collections.h +0 -0
  60. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/Windows.Foundation.Metadata.h +0 -0
  61. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/Windows.Foundation.h +0 -0
  62. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/Windows.Storage.Streams.h +0 -0
  63. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/Windows.Storage.h +0 -0
  64. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/base.h +0 -0
  65. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/base_macros.h +0 -0
  66. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Devices.Geolocation.0.h +0 -0
  67. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Devices.Geolocation.1.h +0 -0
  68. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Foundation.0.h +0 -0
  69. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Foundation.1.h +0 -0
  70. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Foundation.2.h +0 -0
  71. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Foundation.Collections.0.h +0 -0
  72. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Foundation.Collections.1.h +0 -0
  73. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Foundation.Collections.2.h +0 -0
  74. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Foundation.Metadata.0.h +0 -0
  75. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Foundation.Metadata.1.h +0 -0
  76. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Foundation.Metadata.2.h +0 -0
  77. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.0.h +0 -0
  78. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.1.h +0 -0
  79. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.2.h +0 -0
  80. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.FileProperties.0.h +0 -0
  81. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.FileProperties.1.h +0 -0
  82. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.FileProperties.2.h +0 -0
  83. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.Provider.0.h +0 -0
  84. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.Provider.1.h +0 -0
  85. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.Provider.2.h +0 -0
  86. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.Search.0.h +0 -0
  87. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.Search.1.h +0 -0
  88. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.Search.2.h +0 -0
  89. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.Streams.0.h +0 -0
  90. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.Streams.1.h +0 -0
  91. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.Storage.Streams.2.h +0 -0
  92. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.System.0.h +0 -0
  93. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.System.1.h +0 -0
  94. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.System.2.h +0 -0
  95. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.System.RemoteSystems.0.h +0 -0
  96. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/cppwinrt/winrt/impl/Windows.System.RemoteSystems.1.h +0 -0
  97. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/pythoncapi_compat.h +0 -0
  98. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/pywinrt/abi.h +0 -0
  99. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/pywinrt/array.h +0 -0
  100. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/pywinrt/async.h +0 -0
  101. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/pywinrt/base.h +0 -0
  102. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/pywinrt/buffer.h +0 -0
  103. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/pywinrt/convert.h +0 -0
  104. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/pywinrt/errors.h +0 -0
  105. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/pywinrt/prelude.h +0 -0
  106. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/pywinrt/throw_helpers.h +0 -0
  107. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/pywinrt/traits.h +0 -0
  108. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/include/pywinrt/wrappers.h +0 -0
  109. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/interp.h +0 -0
  110. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/members.cpp +0 -0
  111. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/members.h +0 -0
  112. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/metaclass.h +0 -0
  113. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/module_state.h +0 -0
  114. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/numerics-buffer.cpp +0 -0
  115. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/numerics-buffer.h +0 -0
  116. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/numerics-statics.cpp +0 -0
  117. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/numerics-statics.h +0 -0
  118. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/numerics-traits.h +0 -0
  119. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/numerics-values.h +0 -0
  120. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/numerics.cpp +0 -0
  121. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/numerics.h +0 -0
  122. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/protocols.h +0 -0
  123. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/pycollections.cpp +0 -0
  124. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/pycollections.h +0 -0
  125. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/pymapping.cpp +0 -0
  126. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/pymapping.h +0 -0
  127. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/pysequence.cpp +0 -0
  128. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/pysequence.h +0 -0
  129. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/runtime.cpp +0 -0
  130. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/runtime.h +0 -0
  131. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/shapes-generated.h +0 -0
  132. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/shapes.cpp +0 -0
  133. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/shapes.h +0 -0
  134. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/structs.cpp +0 -0
  135. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/structs.h +0 -0
  136. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/table.cpp +0 -0
  137. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/table.h +0 -0
  138. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/types.cpp +0 -0
  139. {winrt_runtime-4.0.2 → winrt_runtime-4.0.3}/src/types.h +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: winrt-runtime
3
- Version: 4.0.2
3
+ Version: 4.0.3
4
4
  Summary: The runtime that every PyWinRT projection package runs on
5
5
  License-Expression: MIT
6
6
  Project-URL: Documentation, https://pywinrt.readthedocs.io
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: winrt-runtime
3
- Version: 4.0.2
3
+ Version: 4.0.3
4
4
  Summary: The runtime that every PyWinRT projection package runs on
5
5
  License-Expression: MIT
6
6
  Project-URL: Documentation, https://pywinrt.readthedocs.io
@@ -45,6 +45,7 @@ src/enums.h
45
45
  src/errors.cpp
46
46
  src/generics.cpp
47
47
  src/generics.h
48
+ src/handles.cpp
48
49
  src/implements.cpp
49
50
  src/implements.h
50
51
  src/interp.cpp
@@ -56,6 +56,7 @@ setup(
56
56
  "src/enums.cpp",
57
57
  "src/errors.cpp",
58
58
  "src/generics.cpp",
59
+ "src/handles.cpp",
59
60
  "src/implements.cpp",
60
61
  "src/interp.cpp",
61
62
  "src/members.cpp",
@@ -184,11 +184,8 @@ namespace py::cpp::_winrt
184
184
  }
185
185
 
186
186
  auto const& guid = *static_cast<winrt::guid const*>(info->guid);
187
- auto const& instance
188
- = reinterpret_cast<
189
- py::winrt_wrapper<winrt::Windows::Foundation::IUnknown>*>(obj)
190
- ->obj;
191
- if (!instance)
187
+ auto const abi = py::interp::held_abi(obj);
188
+ if (!abi)
192
189
  {
193
190
  Py_RETURN_FALSE;
194
191
  }
@@ -201,7 +198,8 @@ namespace py::cpp::_winrt
201
198
 
202
199
  {
203
200
  auto _gil = py::release_gil();
204
- hr = instance.as(guid, queried.put_void());
201
+ hr = static_cast<::IUnknown*>(abi)->QueryInterface(
202
+ guid, queried.put_void());
205
203
  queried = nullptr;
206
204
  }
207
205
 
@@ -505,7 +503,7 @@ namespace py::cpp::_winrt
505
503
 
506
504
  // A Python object derived from a composable class holds nothing until
507
505
  // its __init__() has composed it, and is no other object until then.
508
- if (!self->obj)
506
+ if (!py::interp::held_abi(reinterpret_cast<PyObject*>(self)))
509
507
  {
510
508
  Py_RETURN_NOTIMPLEMENTED;
511
509
  }
@@ -522,6 +520,14 @@ namespace py::cpp::_winrt
522
520
  static Py_hash_t Object_hash(
523
521
  py::winrt_wrapper<winrt::Windows::Foundation::IInspectable>* self) noexcept
524
522
  {
523
+ // A Python object derived from a composable class holds nothing until
524
+ // its __init__() has composed it, and hashing it then would give a
525
+ // hash that changes when it is composed.
526
+ if (!py::interp::instance_abi(reinterpret_cast<PyObject*>(self)))
527
+ {
528
+ return -1;
529
+ }
530
+
525
531
  return static_cast<Py_hash_t>(
526
532
  std::hash<winrt::Windows::Foundation::IInspectable>{}(self->obj));
527
533
  }
@@ -923,15 +923,14 @@ namespace py::interp
923
923
  }
924
924
 
925
925
  /**
926
- * Composes @p self, an instance of a Python class derived from the
927
- * composable class @p entry that holds nothing yet, into a WinRT object:
928
- * the Python object, and the WinRT object it is composed into, each
929
- * holding the other.
926
+ * Composes @p self, which this thread has claimed by storing composing_abi
927
+ * in it, into a WinRT object: the Python object, and the WinRT object it
928
+ * is composed into, each holding the other.
930
929
  *
931
- * @returns @c true, or @c false with a Python error set and @p self left
932
- * holding nothing.
930
+ * @returns @c true with @p self holding the WinRT object, or @c false with
931
+ * a Python error set and @p self still holding composing_abi.
933
932
  */
934
- bool compose_into(
933
+ bool compose_claimed(
935
934
  PyObject* self,
936
935
  type_entry& entry,
937
936
  member_desc const& constructor,
@@ -1103,4 +1102,42 @@ namespace py::interp
1103
1102
 
1104
1103
  return true;
1105
1104
  }
1105
+
1106
+ /**
1107
+ * Composes @p self, an instance of a Python class derived from the
1108
+ * composable class @p entry that holds nothing yet, into a WinRT object.
1109
+ *
1110
+ * The constructor is a call into WinRT, which another thread can run
1111
+ * during, so the thread that composes claims @p self first, by storing
1112
+ * composing_abi in it, and a second thread's claim fails as a composition
1113
+ * of an object that is composed already.
1114
+ *
1115
+ * @returns @c true, or @c false with a Python error set and @p self left
1116
+ * holding nothing.
1117
+ */
1118
+ bool compose_into(
1119
+ PyObject* self,
1120
+ type_entry& entry,
1121
+ member_desc const& constructor,
1122
+ overload_desc& overload,
1123
+ PyObject* const* args,
1124
+ Py_ssize_t nargs) noexcept
1125
+ {
1126
+ void* expected{};
1127
+
1128
+ if (!std::atomic_ref<void*>{abi_of(self)}.compare_exchange_strong(
1129
+ expected, composing_abi))
1130
+ {
1131
+ set_already_composed_error(self);
1132
+ return false;
1133
+ }
1134
+
1135
+ if (!compose_claimed(self, entry, constructor, overload, args, nargs))
1136
+ {
1137
+ abi_of(self) = nullptr;
1138
+ return false;
1139
+ }
1140
+
1141
+ return true;
1142
+ }
1106
1143
  } // namespace py::interp
@@ -142,10 +142,16 @@ namespace py::interp
142
142
  return nullptr;
143
143
  }
144
144
 
145
+ auto const abi = instance_abi(self);
146
+ if (!abi)
147
+ {
148
+ return nullptr;
149
+ }
150
+
145
151
  return call_member(
146
152
  info->members[0],
147
153
  *overload,
148
- abi_of(self),
154
+ abi,
149
155
  nargs == 0 ? nullptr : &PyTuple_GET_ITEM(args, 0),
150
156
  nargs);
151
157
  }
@@ -0,0 +1,159 @@
1
+ // The part of handles.h that is not inline: the thread states of threads
2
+ // Python has not seen.
3
+ //
4
+ // WinRT calls back on threads of its own: the thread pool, the thread of a
5
+ // DispatcherQueue made with CreateOnDedicatedThread(), an AudioGraph's audio
6
+ // thread. Attaching from such a thread creates a thread state for it, and the
7
+ // matching release deletes it again, so on its own whatever Python keeps per
8
+ // thread state would last for one callback: a threading.local, the running
9
+ // asyncio loop, the contextvars context. It would also cost a thread state
10
+ // made and cleared on every callback.
11
+ //
12
+ // So the first attach on such a thread makes the thread state with
13
+ // PyGILState_Ensure() and keeps that count of it, and every attach after finds
14
+ // it and reuses it. The count is given back when the thread exits, from a
15
+ // fiber-local storage callback, and the last release clears and deletes the
16
+ // thread state as it would have: nothing is left behind. Unlike a C++
17
+ // thread_local destructor or DLL_THREAD_DETACH, Windows calls FLS callbacks on
18
+ // the exiting thread before it takes the loader lock, so clearing the thread
19
+ // state there, which can run any finalizer, is safe.
20
+ //
21
+ // The thread state is made by PyGILState_Ensure() rather than by
22
+ // PyThreadState_Ensure*() even from 3.15, because a thread state made that way
23
+ // is deleted when its count runs out, and PyThreadState_EnsureFromView()
24
+ // would hold an interpreter guard for as long as the count stayed up, which
25
+ // keeps the interpreter from ever finalizing. PyThreadState_Ensure*() reuses
26
+ // the thread state PyGILState_Ensure() bound to the thread, and lets go of
27
+ // its guard each time.
28
+
29
+ #ifndef NOMINMAX
30
+ #define NOMINMAX
31
+ #endif
32
+
33
+ #include <Windows.h>
34
+
35
+ #include <pywinrt/handles.h>
36
+
37
+ namespace
38
+ {
39
+ /**
40
+ * Gives back the count keep_thread_state() kept, on the thread that is
41
+ * exiting; the release that takes the count to zero clears and deletes
42
+ * the thread state.
43
+ */
44
+ void NTAPI on_thread_exit(void*) noexcept
45
+ {
46
+ #if PY_VERSION_HEX >= 0x030F0000
47
+ PyInterpreterView* const view = py::main_interpreter_view();
48
+ PyInterpreterGuard* const guard
49
+ = view ? PyInterpreterGuard_FromView(view) : nullptr;
50
+
51
+ // Without a guard, the interpreter is finalizing or gone, and deletes
52
+ // the thread states of all its threads itself.
53
+ if (!guard)
54
+ {
55
+ return;
56
+ }
57
+ #else
58
+ if (!Py_IsInitialized() || Py_IsFinalizing())
59
+ {
60
+ return;
61
+ }
62
+ #endif
63
+
64
+ // An interpreter initialized again since is not the one the thread
65
+ // state was kept in, and this thread has none in it.
66
+ if (PyGILState_GetThisThreadState())
67
+ {
68
+ PyGILState_STATE const state = PyGILState_Ensure();
69
+ // The kept count; the GIL stays held for the release below.
70
+ PyGILState_Release(PyGILState_LOCKED);
71
+ PyGILState_Release(state);
72
+ }
73
+
74
+ #if PY_VERSION_HEX >= 0x030F0000
75
+ PyInterpreterGuard_Close(guard);
76
+ #endif
77
+ }
78
+
79
+ /**
80
+ * The FLS slot whose callback gives the thread state back, or
81
+ * FLS_OUT_OF_INDEXES. It is never freed: FlsFree() would call the callback
82
+ * for every thread at once, on the thread that frees it, and the module is
83
+ * never unloaded.
84
+ */
85
+ DWORD fls_index() noexcept
86
+ {
87
+ static DWORD const index = FlsAlloc(on_thread_exit);
88
+ return index;
89
+ }
90
+
91
+ /**
92
+ * Any value but null, which FLS takes to mean "nothing to clean up".
93
+ */
94
+ void* const kept = reinterpret_cast<void*>(1);
95
+ } // namespace
96
+
97
+ namespace py
98
+ {
99
+ #if PY_VERSION_HEX >= 0x030F0000
100
+ /**
101
+ * The main interpreter, for attaching to it from a thread Python has not
102
+ * seen; @c nullptr if out of memory.
103
+ */
104
+ PyInterpreterView* main_interpreter_view() noexcept
105
+ {
106
+ // A view does not keep the interpreter from finalizing, so the one
107
+ // taken on first use serves for as long as the process runs.
108
+ static PyInterpreterView* const view = PyInterpreterView_FromMain();
109
+ return view;
110
+ }
111
+ #endif
112
+
113
+ /**
114
+ * Gives the calling thread, which has no Python thread state, one that
115
+ * lasts until the thread exits, so that what Python keeps per thread -
116
+ * threading.local, the running asyncio loop, the contextvars context -
117
+ * carries over from one WinRT callback to the next. Without it, the thread
118
+ * state that attaching creates is deleted again when the callback returns.
119
+ * Call it without the GIL and before attaching.
120
+ */
121
+ void keep_thread_state() noexcept
122
+ {
123
+ DWORD const index = fls_index();
124
+
125
+ if (index == FLS_OUT_OF_INDEXES)
126
+ {
127
+ return; // each callback makes its own thread state
128
+ }
129
+
130
+ #if PY_VERSION_HEX >= 0x030F0000
131
+ PyInterpreterView* const view = main_interpreter_view();
132
+ PyInterpreterGuard* const guard
133
+ = view ? PyInterpreterGuard_FromView(view) : nullptr;
134
+
135
+ if (!guard)
136
+ {
137
+ return; // finalizing: the attach that follows fails too
138
+ }
139
+ #endif
140
+
141
+ // Makes the thread state, binds it to the thread and attaches it.
142
+ PyGILState_STATE const state = PyGILState_Ensure();
143
+
144
+ if (FlsSetValue(index, kept))
145
+ {
146
+ // Detaches, keeping the count.
147
+ PyEval_SaveThread();
148
+ }
149
+ else
150
+ {
151
+ // Deletes the thread state again.
152
+ PyGILState_Release(state);
153
+ }
154
+
155
+ #if PY_VERSION_HEX >= 0x030F0000
156
+ PyInterpreterGuard_Close(guard);
157
+ #endif
158
+ }
159
+ } // namespace py
@@ -10,6 +10,12 @@
10
10
 
11
11
  namespace py
12
12
  {
13
+ #if PY_VERSION_HEX >= 0x030F0000
14
+ PyInterpreterView* main_interpreter_view() noexcept;
15
+ #endif
16
+
17
+ void keep_thread_state() noexcept;
18
+
13
19
  /**
14
20
  * Holds the Python GIL for as long as it is in scope, unless the
15
21
  * interpreter is being finalized or already has been, in which case it
@@ -27,7 +33,15 @@ namespace py
27
33
  * From Python 3.15, PyThreadState_EnsureFromView() (PEP 788) makes the
28
34
  * check and the attach one step. Before that they are two, so a thread
29
35
  * that passes the check just as another starts finalizing still attaches
30
- * to an interpreter that is going away.
36
+ * to an interpreter that is going away. on_thread_exit() in handles.cpp
37
+ * takes the same two steps on a thread that is exiting, inside
38
+ * LdrShutdownThread(), where the attach then hangs the thread (3.14) or
39
+ * re-enters thread exit (3.12, 3.13). That needs finalization to start
40
+ * during the thread's exit, a window of milliseconds.
41
+ *
42
+ * On a thread Python has not seen, which is most threads WinRT calls back
43
+ * on, the guard first gives the thread a thread state of its own: see
44
+ * keep_thread_state().
31
45
  */
32
46
  struct gil_guard
33
47
  {
@@ -55,15 +69,18 @@ namespace py
55
69
  private:
56
70
  static PyThreadStateToken* attach() noexcept
57
71
  {
58
- // A view does not keep the interpreter from finalizing, so the one
59
- // taken on first use serves for as long as the process runs.
60
- static PyInterpreterView* const view = PyInterpreterView_FromMain();
72
+ PyInterpreterView* const view = main_interpreter_view();
61
73
 
62
74
  if (!view)
63
75
  {
64
76
  return nullptr;
65
77
  }
66
78
 
79
+ if (!PyGILState_GetThisThreadState())
80
+ {
81
+ keep_thread_state();
82
+ }
83
+
67
84
  return PyThreadState_EnsureFromView(view);
68
85
  }
69
86
 
@@ -80,6 +97,11 @@ namespace py
80
97
  {
81
98
  if (m_held)
82
99
  {
100
+ if (!PyGILState_GetThisThreadState())
101
+ {
102
+ keep_thread_state();
103
+ }
104
+
83
105
  m_state = PyGILState_Ensure();
84
106
  }
85
107
  }
@@ -352,7 +352,7 @@ namespace py::interp
352
352
  }
353
353
 
354
354
  winrt::Windows::Foundation::IUnknown object;
355
- winrt::copy_from_abi(object, abi_of(value));
355
+ winrt::copy_from_abi(object, held_abi(value));
356
356
  if (!object)
357
357
  {
358
358
  // The conversion says the object holds nothing.
@@ -228,6 +228,19 @@ namespace py::interp
228
228
  Py_TYPE(self)->tp_name);
229
229
  }
230
230
 
231
+ /**
232
+ * Says that @p self is composed already, or is being composed on another
233
+ * thread, so cannot be composed again.
234
+ */
235
+ void set_already_composed_error(PyObject* self) noexcept
236
+ {
237
+ PyErr_Format(
238
+ PyExc_TypeError,
239
+ "'%s' object is already composed into a WinRT object, so it cannot "
240
+ "be initialized again",
241
+ Py_TYPE(self)->tp_name);
242
+ }
243
+
231
244
  namespace
232
245
  {
233
246
  void release_interface_capsule(PyObject* capsule) noexcept
@@ -424,11 +437,7 @@ namespace py::interp
424
437
 
425
438
  if (abi_of(self))
426
439
  {
427
- PyErr_Format(
428
- PyExc_TypeError,
429
- "'%s' object is already composed into a WinRT object, so "
430
- "it cannot be initialized again",
431
- type->tp_name);
440
+ set_already_composed_error(self);
432
441
  return -1;
433
442
  }
434
443
 
@@ -29,17 +29,37 @@ namespace py::interp
29
29
  return *reinterpret_cast<void**>(reinterpret_cast<uint8_t*>(self) + abi_offset);
30
30
  }
31
31
 
32
+ /**
33
+ * What abi_of() holds while compose_into() is composing the object, which
34
+ * is a call into WinRT that another thread can run during: not a pointer,
35
+ * so that the thread that holds it is the only one composing, and the
36
+ * object holds nothing yet to every other.
37
+ */
38
+ inline void* const composing_abi = reinterpret_cast<void*>(1);
39
+
40
+ /**
41
+ * The ABI pointer @p self holds, or @c nullptr when it holds none, which
42
+ * an instance of a Python class derived from a composable one does until
43
+ * its __init__() has called the WinRT class's, and while that call is
44
+ * under way.
45
+ */
46
+ inline void* held_abi(PyObject* self) noexcept
47
+ {
48
+ auto const abi = abi_of(self);
49
+ return abi == composing_abi ? nullptr : abi;
50
+ }
51
+
32
52
  void set_not_composed_error(PyObject* self) noexcept;
33
53
 
54
+ void set_already_composed_error(PyObject* self) noexcept;
55
+
34
56
  /**
35
57
  * The ABI pointer @p self holds, to call an instance member on, or
36
- * @c nullptr with a Python error set when it holds none, which an instance
37
- * of a Python class derived from a composable one does until its
38
- * __init__() has called the WinRT class's.
58
+ * @c nullptr with a Python error set when it holds none.
39
59
  */
40
60
  inline void* instance_abi(PyObject* self) noexcept
41
61
  {
42
- auto const abi = abi_of(self);
62
+ auto const abi = held_abi(self);
43
63
  if (!abi)
44
64
  {
45
65
  set_not_composed_error(self);
@@ -807,13 +807,19 @@ namespace py::interp
807
807
  return nullptr;
808
808
  }
809
809
 
810
+ auto const abi = instance_abi(self);
811
+ if (!abi)
812
+ {
813
+ return nullptr;
814
+ }
815
+
810
816
  // The three members take nothing and hand back one value each, so
811
817
  // where the table describes them the way IIterator<T> always does
812
818
  // they are called in one crossing rather than three. A table that
813
819
  // describes them some other way is answered below.
814
820
  bool fused{};
815
821
 
816
- auto* const item = call_iterator_step(*info, abi_of(self), fused);
822
+ auto* const item = call_iterator_step(*info, abi, fused);
817
823
 
818
824
  if (fused)
819
825
  {
@@ -1013,7 +1019,11 @@ namespace py::interp
1013
1019
  return false;
1014
1020
  }
1015
1021
 
1016
- auto const abi = abi_of(self);
1022
+ auto const abi = instance_abi(self);
1023
+ if (!abi)
1024
+ {
1025
+ return false;
1026
+ }
1017
1027
 
1018
1028
  {
1019
1029
  auto _gil = release_gil();
@@ -0,0 +1 @@
1
+ 4.0.3
@@ -1 +0,0 @@
1
- 4.0.2
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes