Skip to content

Conversation

mordante
Copy link
Member

@mordante mordante commented Nov 16, 2023

This is based on the __wrapped_streambuf_mutex class used in <syncstream>. This is a generic version set to replace __wrapped_streambuf_mutex.

@mordante mordante force-pushed the GH-shared_resource branch 2 times, most recently from 3584476 to 82616ca Compare November 16, 2023 18:59
This is based on the __wrapped_streambuf_mutex class used in
<syncstream>. This is a generic version set to replace
__wrapped_streambuf_mutex.
@mordante mordante marked this pull request as ready for review November 25, 2023 13:03
@mordante mordante requested a review from a team as a code owner November 25, 2023 13:03
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Nov 25, 2023
@llvmbot
Copy link
Member

llvmbot commented Nov 25, 2023

@llvm/pr-subscribers-libcxx

Author: Mark de Wever (mordante)

Changes

This is based on the __wrapped_streambuf_mutex class used in <syncstream>. This is a generic version set to replace __wrapped_streambuf_mutex.


Patch is 22.87 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/72529.diff

15 Files Affected:

  • (modified) libcxx/include/CMakeLists.txt (+1)
  • (modified) libcxx/include/__availability (+9)
  • (added) libcxx/include/__utility/shared_resource.h (+59)
  • (modified) libcxx/include/module.modulemap.in (+1)
  • (modified) libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist (+3)
  • (modified) libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist (+3)
  • (modified) libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist (+3)
  • (modified) libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist (+3)
  • (modified) libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist (+4-1)
  • (modified) libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist (+3)
  • (modified) libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist (+3)
  • (modified) libcxx/src/CMakeLists.txt (+1)
  • (added) libcxx/src/shared_resource.cpp (+83)
  • (added) libcxx/test/libcxx/utilities/utility/shared_resource.pass.cpp (+46)
  • (modified) libcxx/utils/libcxx/test/features.py (+9)
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 889d7fedbf2965f..75d47979645c7bd 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -854,6 +854,7 @@ set(files
   __utility/piecewise_construct.h
   __utility/priority_tag.h
   __utility/rel_ops.h
+  __utility/shared_resource.h
   __utility/small_buffer.h
   __utility/swap.h
   __utility/to_underlying.h
diff --git a/libcxx/include/__availability b/libcxx/include/__availability
index 99a16c968de3c60..c76faf5eefce9f3 100644
--- a/libcxx/include/__availability
+++ b/libcxx/include/__availability
@@ -139,6 +139,12 @@
 // #   define _LIBCPP_AVAILABILITY_HAS_NO_TZDB
 #   define _LIBCPP_AVAILABILITY_TZDB
 
+    // This controls the availability of the shared resource code.
+    // This is used in syncstream to synchronize write operations,
+    // but the code is generic and can be used for similar purposes.
+// #   define _LIBCPP_AVAILABILITY_HAS_NO_SHARED_RESOURCE
+#   define _LIBCPP_AVAILABILITY_SHARED_RESOURCE
+
 // Enable additional explicit instantiations of iostreams components. This
 // reduces the number of weak definitions generated in programs that use
 // iostreams by providing a single strong definition in the shared library.
@@ -241,6 +247,9 @@
 #  define _LIBCPP_AVAILABILITY_HAS_NO_TZDB
 #  define _LIBCPP_AVAILABILITY_TZDB __attribute__((unavailable))
 
+#   define _LIBCPP_AVAILABILITY_HAS_NO_SHARED_RESOURCE
+#   define _LIBCPP_AVAILABILITY_SHARED_RESOURCE __attribute__((unavailable))
+
 #  if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 120000)   || \
       (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 150000) || \
       (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 150000)         || \
diff --git a/libcxx/include/__utility/shared_resource.h b/libcxx/include/__utility/shared_resource.h
new file mode 100644
index 000000000000000..ee5182007a9c65f
--- /dev/null
+++ b/libcxx/include/__utility/shared_resource.h
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___UTILITY_SHARED_RESOURCE_H
+#define _LIBCPP___UTILITY_SHARED_RESOURCE_H
+
+#include <__availability>
+#include <__config>
+#include <__mutex/lock_guard.h>
+#include <__mutex/mutex.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+#ifndef _LIBCPP_HAS_NO_THREADS
+
+// Contains helper functions for a reference counted resource.
+// The resources are identified by their address. The reference counting is
+// done by calling increasing and decreasing the reference count at the
+// appropriate time.
+//
+// There are two ways to guard the resource against concurrent access:
+// - Call the lock function. The function locks two mutexes
+//   - The internal map's mutex
+//   - The mutex of the resource
+//   This approach does not require to store a pointer/reference to the mutex,
+//   reducing the size of the object.
+// - Store the mutex of the inc function. Then the caller can lock the mutex at
+//   the appropriate time.
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// std::mutex is available as an extension since C++03, but returning a
+// lock_guard requires C++17. Since the current use-cases require newer C++
+// versions the older versions are not supported.
+#  if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_AVAILABILITY_SHARED_RESOURCE mutex&
+__shared_resource_inc_reference(const void* __ptr);
+
+// precondition: __ptr's reference count > 0
+_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_AVAILABILITY_SHARED_RESOURCE void __shared_resource_dec_reference(const void* __ptr);
+
+// precondition: __ptr's reference count > 0
+[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_AVAILABILITY_SHARED_RESOURCE lock_guard<mutex>
+__shared_resource_get_lock(const void* __ptr);
+
+#  endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_HAS_NO_THREADS
+#endif // _LIBCPP___UTILITY_SHARED_RESOURCE_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 17ebe48f329963d..607caea93ce2f23 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -2084,6 +2084,7 @@ module std_private_utility_piecewise_construct    [system] { header "__utility/p
 module std_private_utility_priority_tag           [system] { header "__utility/priority_tag.h" }
 module std_private_utility_rel_ops                [system] { header "__utility/rel_ops.h" }
 module std_private_utility_small_buffer           [system] { header "__utility/small_buffer.h" }
+module std_private_utility_shared_resource        [system] { header "__utility/shared_resource.h" }
 module std_private_utility_swap                   [system] {
   header "__utility/swap.h"
   export std_private_type_traits_is_swappable
diff --git a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index 8daad89f52e6f7c..76db0097233ea6a 100644
--- a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1534,7 +1534,10 @@
 {'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__126__shared_resource_get_lockEPKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__131__shared_resource_dec_referenceEPKv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__131__shared_resource_inc_referenceEPKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__13cinE', 'size': 0, 'type': 'OBJECT'}
diff --git a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 91976f500539daa..4d9f7f690e06727 100644
--- a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -568,7 +568,10 @@
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIiNS_22__cxx_atomic_base_implIiEEEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__126__shared_resource_get_lockEPKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__131__shared_resource_dec_referenceEPKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__131__shared_resource_inc_referenceEPKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__134__construct_barrier_algorithm_baseERl', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__13cinE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
diff --git a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 8a98d42a2a1aa02..1f866c69468047d 100644
--- a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -568,7 +568,10 @@
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIlNS_22__cxx_atomic_base_implIlEEEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__126__shared_resource_get_lockEPKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__131__shared_resource_dec_referenceEPKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
+{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__131__shared_resource_inc_referenceEPKv', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__134__construct_barrier_algorithm_baseERl', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
 {'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__13cinE', 'storage_mapping_class': 'RW', 'type': 'OBJECT'}
diff --git a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index 0c06b5097b83f80..cdad4ccc69cdbd9 100644
--- a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1534,7 +1534,10 @@
 {'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIxNS_22__cxx_atomic_base_implIxEEEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__126__shared_resource_get_lockEPKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__131__shared_resource_dec_referenceEPKv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '__ZNSt3__131__shared_resource_inc_referenceEPKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'}
 {'is_defined': True, 'name': '__ZNSt3__13cinE', 'size': 0, 'type': 'OBJECT'}
diff --git a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
index 16658fdff54932b..58566be937c1f3e 100644
--- a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1229,7 +1229,10 @@
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIlNS_22__cxx_atomic_base_implIlEEEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__126__shared_resource_get_lockEPKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__131__shared_resource_dec_referenceEPKv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__131__shared_resource_inc_referenceEPKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__13cinE', 'size': 168, 'type': 'OBJECT'}
@@ -2025,4 +2028,4 @@
 {'is_defined': True, 'name': '_ZTv0_n24_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED0Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZTv0_n24_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED1Ev', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD0Ev', 'type': 'FUNC'}
-{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD1Ev', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD1Ev', 'type': 'FUNC'}
\ No newline at end of file
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
index 49e3579614ee8c1..0e6661dbb6df9bb 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -1227,7 +1227,10 @@
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIiNS_22__cxx_atomic_base_implIiEEEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__126__shared_resource_get_lockEPKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__131__shared_resource_dec_referenceEPKv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__131__shared_resource_inc_referenceEPKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__13cinE', 'size': 168, 'type': 'OBJECT'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
index 764e7c37daacb7c..869b96bfcea1d94 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
@@ -1199,7 +1199,10 @@
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKNS_17__cxx_atomic_implIiNS_22__cxx_atomic_base_implIiEEEE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__123__libcpp_atomic_monitorEPVKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__125notify_all_at_thread_exitERNS_18condition_variableENS_11unique_lockINS_5mutexEEE', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__126__shared_resource_get_lockEPKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__131__arrive_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseEh', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__131__shared_resource_dec_referenceEPKv', 'type': 'FUNC'}
+{'is_defined': True, 'name': '_ZNSt3__131__shared_resource_inc_referenceEPKv', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__132__destroy_barrier_algorithm_baseEPNS_24__barrier_algorithm_baseE', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__134__construct_barrier_algorithm_baseERl', 'type': 'FUNC'}
 {'is_defined': True, 'name': '_ZNSt3__13cinE', 'size': 168, 'type': 'OBJECT'}
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index 156dbe8a4c2f92e..c9671d76e48380c 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -72,6 +72,7 @@ if (LIBCXX_ENABLE_THREADS)
     mutex_destructor.cpp
     mutex.cpp
     shared_mutex.cpp
+    shared_resource.cpp
     thread.cpp
     )
 endif()
diff --git a/libcxx/src/shared_resource.cpp b/libcxx/src/shared_resource.cpp
new file mode 100644
index 000000000000000..6c4fb442a2c1c82
--- /dev/null
+++ b/libcxx/src/shared_resource.cpp
@@ -0,0 +1,83 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <map>
+#include <mutex>
+#include <shared_mutex>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+class __shared_resource {
+public:
+  _LIBCPP_HIDE_FROM_ABI __shared_resource()              = default;
+  __shared_resource(const __shared_resource&)            = delete;
+  __shared_resource& operator=(const __shared_resource&) = delete;
+
+  _LIBCPP_HIDE_FROM_ABI mutex& __inc_reference(const void* __ptr) {
+    _LIBCPP_ASSERT_NON_NULL(__ptr != nullptr, "not a valid resource");
+    unique_lock __lock{__mutex_};
+
+    auto& __resource = __lut_[reinterpret_cast<uintptr_t>(__ptr)];
+    ++__resource.__count;
+    return __resource.__mutex;
+  }
+
+  _LIBCPP_HIDE_FROM_ABI void __dec_reference(const void* __ptr) {
+    unique_lock __lock{__mutex_};
+
+    auto __it = __get_it(__ptr);
+    if (__it->second.__count == 1)
+      __lut_.erase(__it);
+    else
+      --__it->second.__count;
+  }
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI lock_guard<mutex> __get_lock(const void* __ptr) {
+    shared_lock __lock{__mutex_};
+    return lock_guard{__get_it(__ptr)->second.__mutex};
+  }
+
+  [[nodiscard]] static _LIBCPP_HIDE_FROM_ABI __shared_resource& __instance() {
+    static __shared_resource __result;
+    return __result;
+  }
+
+private:
+  struct __value {
+    mutex __mutex;
+    size_t __count{0};
+  };
+
+  shared_mutex __mutex_;
+  map<uintptr_t, __value> __lut_;
+
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI map<uintptr_t, __value>::iterator __get_it(const void* __ptr) {
+    _LIBCPP_ASSERT_NON_NULL(__ptr != nullptr, "not a valid resource");
+
+    auto __it = __lut_.find(reinterpret_cast<uintptr_t>(__ptr));
+    _LIBCPP_ASSERT_INTERNAL(__it != __lut_.end(), "the resource is not registered");
+    _LIBCPP_ASSERT_INTERNAL(__it->second.__count > 0, "the resouce is not active");
+    return __it;
+  }
+};
+
+_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_AVAILABILITY_SHARED_RESOURCE mutex&
+__shared_resource_inc_reference(const void* __ptr) {
+  return __shared_resource::__instance().__inc_reference(__ptr);
+}
+
+_LIBCPP_EXPORTED_FROM_ABI _LIBCPP_AVAILABILITY_SHARED_RESOURCE void __shared_resource_dec_reference(const void* __ptr) {
+  _...
[truncated]

// This controls the availability of the shared resource code.
// This is used in syncstream to synchronize write operations,
// but the code is generic and can be used for similar purposes.
// # define _LIBCPP_AVAILABILITY_HAS_NO_SHARED_RESOURCE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be adjusted on top of main.

{'is_defined': True, 'name': '_ZTv0_n24_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD0Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD1Ev', 'type': 'FUNC'}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's just add a newline to remove this diff.

Feature(
name="availability-shared_resource-missing",
when=lambda cfg: BooleanExpression.evaluate(
# TODO(ldionne) Please provide the correct value.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# TODO(ldionne) Please provide the correct value.
# TODO(ldionne): Update once this has shipped.

std::lock_guard b_lock{b_mutex};
std::lock_guard c_lock = std::__shared_resource_get_lock(&c);
}
{ // Test the lock of a locks the mutex returned by inc.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{ // Test the lock of a locks the mutex returned by inc.
{ // Test that the lock is really associated to the given address.

size_t __count{0};
};

shared_mutex __mutex_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's rename this to something like __map_mutex_ since it's really intended to guard the std::map access.

};

shared_mutex __mutex_;
map<uintptr_t, __value> __lut_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

map is rarely the best way of storing data. I would suggest either using unordered_map or implementing a simple hash table for internal use only. Maybe unordered_map is easiest for now, especially since we can change it however we want since it's just in the dylib.

}

private:
struct __value {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@huixie90

I think there are many similarities with what we do in stop_token here. This is basically a ref-counted mutex, and that's very close to what we do with __intrusive_shared_ptr and __atomic_unique_lock in the stop_token implementation. I wonder whether it would make sense to reuse some of that work here. In particular, we know for sure that std::map + std::mutex is probably not the best way of implementing the storage for this, so perhaps we can do something clever by using a slightly different data structure.

I'd be curious if you have thoughts about this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@huixie90 Do you have thoughts on this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@huixie90 Friendly ping.

@EricWF
Copy link
Member

EricWF commented Apr 18, 2024

I would like a day or two to look over this.

@EricWF
Copy link
Member

EricWF commented Apr 18, 2024

This abstraction is scary & heavy weight. Why do we need a generic version of it?

I wouldn't be comfortable proceeding with this change until I understand where and how it's going to be used, and I see it used in real code. I'm very uncomfortable adding utility code without users.

I don't need this change to contain the changes which use it, but I would like to see it before this proceeds.

@EricWF EricWF self-requested a review April 18, 2024 19:22
@ldionne
Copy link
Member

ldionne commented Apr 26, 2024

This abstraction is scary & heavy weight. Why do we need a generic version of it?

I wouldn't be comfortable proceeding with this change until I understand where and how it's going to be used, and I see it used in real code. I'm very uncomfortable adding utility code without users.

I don't need this change to contain the changes which use it, but I would like to see it before this proceeds.

This is to refactor <syncstream>, which uses a specialized version of this. We discussed this generalization in the <syncstream> review (https://reviews.llvm.org/D67086)

@mordante
Copy link
Member Author

This abstraction is scary & heavy weight. Why do we need a generic version of it?
I wouldn't be comfortable proceeding with this change until I understand where and how it's going to be used, and I see it used in real code. I'm very uncomfortable adding utility code without users.
I don't need this change to contain the changes which use it, but I would like to see it before this proceeds.

This is to refactor <syncstream>, which uses a specialized version of this. We discussed this generalization in the <syncstream> review (https://reviews.llvm.org/D67086)

@ldionne FYI I discussed this offline with @EricWF last week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants