Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libc++] Make std::lock_guard available with _LIBCPP_HAS_NO_THREADS #98717

Merged
merged 20 commits into from
Jul 17, 2024

Conversation

petrhosek
Copy link
Member

@petrhosek petrhosek commented Jul 13, 2024

This change makes std::lock_guard available when _LIBCPP_HAS_NO_THREADS is set. This class is generic and doesn't require threading support, and is regularly used even in environments where threading isn't available like embedded.

fixes #89891

This change makes std::lock_guard, std::unique_lock, std::scoped_lock,
and std::shared_lock available when _LIBCPP_HAS_NO_THREADS is set.
These classes are generic and don't require threading support, and are
regularly used even in environments where threading isn't available like
embedded.

fixes llvm#89891
@petrhosek petrhosek requested a review from ldionne July 13, 2024 05:54
@petrhosek petrhosek requested a review from a team as a code owner July 13, 2024 05:54
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Jul 13, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Jul 13, 2024

@llvm/pr-subscribers-libcxx

Author: Petr Hosek (petrhosek)

Changes

This change makes std::lock_guard, std::unique_lock, std::scoped_lock, and std::shared_lock available when _LIBCPP_HAS_NO_THREADS is set. These classes are generic and don't require threading support, and are regularly used even in environments where threading isn't available like embedded.

fixes #89891


Full diff: https://github.com/llvm/llvm-project/pull/98717.diff

4 Files Affected:

  • (modified) libcxx/include/__mutex/lock_guard.h (-4)
  • (modified) libcxx/include/__mutex/unique_lock.h (-4)
  • (modified) libcxx/include/mutex (+3-3)
  • (modified) libcxx/include/shared_mutex (+7-8)
diff --git a/libcxx/include/__mutex/lock_guard.h b/libcxx/include/__mutex/lock_guard.h
index 8340b9bbd4453..ef56896be9f68 100644
--- a/libcxx/include/__mutex/lock_guard.h
+++ b/libcxx/include/__mutex/lock_guard.h
@@ -16,8 +16,6 @@
 #  pragma GCC system_header
 #endif
 
-#ifndef _LIBCPP_HAS_NO_THREADS
-
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Mutex>
@@ -47,6 +45,4 @@ _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(lock_guard);
 
 _LIBCPP_END_NAMESPACE_STD
 
-#endif // _LIBCPP_HAS_NO_THREADS
-
 #endif // _LIBCPP___MUTEX_LOCK_GUARD_H
diff --git a/libcxx/include/__mutex/unique_lock.h b/libcxx/include/__mutex/unique_lock.h
index 4a616ba51ee1c..5df791de4c742 100644
--- a/libcxx/include/__mutex/unique_lock.h
+++ b/libcxx/include/__mutex/unique_lock.h
@@ -22,8 +22,6 @@
 #  pragma GCC system_header
 #endif
 
-#ifndef _LIBCPP_HAS_NO_THREADS
-
 _LIBCPP_BEGIN_NAMESPACE_STD
 
 template <class _Mutex>
@@ -172,6 +170,4 @@ inline _LIBCPP_HIDE_FROM_ABI void swap(unique_lock<_Mutex>& __x, unique_lock<_Mu
 
 _LIBCPP_END_NAMESPACE_STD
 
-#endif // _LIBCPP_HAS_NO_THREADS
-
 #endif // _LIBCPP___MUTEX_UNIQUE_LOCK_H
diff --git a/libcxx/include/mutex b/libcxx/include/mutex
index 02c52dd72f02b..d4d7539240094 100644
--- a/libcxx/include/mutex
+++ b/libcxx/include/mutex
@@ -419,8 +419,9 @@ inline _LIBCPP_HIDE_FROM_ABI void lock(_L0& __l0, _L1& __l1, _L2& __l2, _L3&...
 }
 
 #  endif // _LIBCPP_CXX03_LANG
+#endif   // !_LIBCPP_HAS_NO_THREADS
 
-#  if _LIBCPP_STD_VER >= 17
+#if _LIBCPP_STD_VER >= 17
 template <class... _Mutexes>
 class _LIBCPP_TEMPLATE_VIS scoped_lock;
 
@@ -491,8 +492,7 @@ private:
 };
 _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(scoped_lock);
 
-#  endif // _LIBCPP_STD_VER >= 17
-#endif   // !_LIBCPP_HAS_NO_THREADS
+#endif // _LIBCPP_STD_VER >= 17
 
 _LIBCPP_END_NAMESPACE_STD
 
diff --git a/libcxx/include/shared_mutex b/libcxx/include/shared_mutex
index 397ac290d9b2e..5918af4a214c1 100644
--- a/libcxx/include/shared_mutex
+++ b/libcxx/include/shared_mutex
@@ -122,16 +122,11 @@ template <class Mutex>
 
 */
 
-#include <__config>
-
-#ifdef _LIBCPP_HAS_NO_THREADS
-#  error "<shared_mutex> is not supported since libc++ has been configured without support for threads."
-#endif
-
 #include <__chrono/duration.h>
 #include <__chrono/steady_clock.h>
 #include <__chrono/time_point.h>
 #include <__condition_variable/condition_variable.h>
+#include <__config>
 #include <__memory/addressof.h>
 #include <__mutex/mutex.h>
 #include <__mutex/tag_types.h>
@@ -152,6 +147,8 @@ _LIBCPP_PUSH_MACROS
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+#  ifndef _LIBCPP_HAS_NO_THREADS
+
 struct _LIBCPP_EXPORTED_FROM_ABI __shared_mutex_base {
   mutex __mut_;
   condition_variable __gate1_;
@@ -181,7 +178,7 @@ struct _LIBCPP_EXPORTED_FROM_ABI __shared_mutex_base {
   //     native_handle_type native_handle(); // See 30.2.3
 };
 
-#  if _LIBCPP_STD_VER >= 17
+#    if _LIBCPP_STD_VER >= 17
 class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_THREAD_SAFETY_ANNOTATION(__capability__("shared_mutex")) shared_mutex {
   __shared_mutex_base __base_;
 
@@ -218,7 +215,7 @@ public:
   //     typedef __shared_mutex_base::native_handle_type native_handle_type;
   //     _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return __base::unlock_shared(); }
 };
-#  endif
+#    endif
 
 class _LIBCPP_EXPORTED_FROM_ABI
 _LIBCPP_THREAD_SAFETY_ANNOTATION(__capability__("shared_timed_mutex")) shared_timed_mutex {
@@ -308,6 +305,8 @@ bool shared_timed_mutex::try_lock_shared_until(const chrono::time_point<_Clock,
   return true;
 }
 
+#  endif   // !_LIBCPP_HAS_NO_THREADS
+
 template <class _Mutex>
 class shared_lock {
 public:

@petrhosek petrhosek changed the title [libcxx] Make locks available with _LIBCPP_HAS_NO_THREADS [libc++] Make locks available with _LIBCPP_HAS_NO_THREADS Jul 13, 2024
Copy link

github-actions bot commented Jul 13, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Contributor

@philnik777 philnik777 left a comment

Choose a reason for hiding this comment

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

There should be at least some test that this works with threading disabled. I don't know whether we have any tests currently that could now be enabled. If not, let's add at least a simple one for all the classes.

libcxx/include/mutex Outdated Show resolved Hide resolved
@petrhosek
Copy link
Member Author

There should be at least some test that this works with threading disabled. I don't know whether we have any tests currently that could now be enabled. If not, let's add at least a simple one for all the classes.

There are several tests that should now pass even with threading disabled, I removed UNSUPPORTED: no-threads from all of them.

@petrhosek petrhosek changed the title [libc++] Make locks available with _LIBCPP_HAS_NO_THREADS [libc++] Make std::lock_guard available with _LIBCPP_HAS_NO_THREADS Jul 15, 2024
@petrhosek
Copy link
Member Author

After doing more testing, I decide to exclude std::unique_lock, std::scoped_lock, and std::shared_lock since those have additional dependencies. The change should be ready for review as-is since all tests appear to be passing.

@petrhosek petrhosek requested a review from a team July 15, 2024 15:04
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: no-threads
Copy link
Member

Choose a reason for hiding this comment

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

We can lift this UNSUPPORTED by defining our own mutex-like class. Also, while we're at it this test should be a .compile.pass.cpp and it should test static_assert(!std::is_copy_assignable<std::lock_guard<MyMutexType>>::value, "");.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: no-threads
Copy link
Member

Choose a reason for hiding this comment

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

Similar comment here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

@@ -18,31 +18,44 @@
// -> lock_guard<_Mutex>; // C++17

#include <mutex>
Copy link
Member

Choose a reason for hiding this comment

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

I would suggest that we formulate the tests in terms of the TestMutex only, that way they would all become enabled when threading is disabled.

And then we can have a single test (probably in this test file) where we test basic interoperation between std::lock_guard and std::mutex, and that one would be the only one with UNSUPPORTED: no-threads.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

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

A few more comments but this LGTM once they are applied.

Comment on lines 19 to 22
int main(int, char**) {
static_assert(!std::is_copy_assignable<std::lock_guard<MyMutex> >::value, "");
return 0;
}
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
int main(int, char**) {
static_assert(!std::is_copy_assignable<std::lock_guard<MyMutex> >::value, "");
return 0;
}
static_assert(!std::is_copy_assignable<std::lock_guard<MyMutex> >::value, "");

Just as a matter of style, we don't use main function in these compile-only tests when they are not needed to avoid any confusion about the test running.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.


int main(int, char**) {
Copy link
Member

Choose a reason for hiding this comment

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

Same.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

@@ -16,10 +14,12 @@

#include <mutex>

struct MyMutex {};
Copy link
Member

Choose a reason for hiding this comment

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

I think you need to use a valid BasicLockable all the time, otherwise the code is ill-formed. I suggest you define MyMutex in a local header like types.h and include it from all the tests in this directory that use MyMutex.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

std::mutex>::value), "");
struct MyMutex {};

int main(int, char**) {
Copy link
Member

Choose a reason for hiding this comment

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

No main needed, and this can be a .compile.pass.cpp

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

@@ -6,8 +6,6 @@
//
Copy link
Member

Choose a reason for hiding this comment

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

Maybe rename to ctor.mutex.pass.cpp and test the constructor as a whole instead?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

std::mutex m;
std::lock_guard<std::mutex> lg = m; // expected-error{{no viable conversion}}
MyMutex m;
std::lock_guard<MyMutex> lg = m; // expected-error{{no viable conversion}}
Copy link
Member

Choose a reason for hiding this comment

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

Instead, we should do something like

std::lock_guard<MyMutex> lg(m); // make sure this compiles and runs

static_assert(!std::is_convertible_v<MyMutex, std::lock_guard<MyMutex>>, "constructor must be explicit");

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

@petrhosek
Copy link
Member Author

A few more comments but this LGTM once they are applied.

Thanks, I believe it should be all addressed.

Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

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

LGTM if CI is green.

@petrhosek petrhosek merged commit 6192f45 into llvm:main Jul 17, 2024
9 of 11 checks passed
sgundapa pushed a commit to sgundapa/upstream_effort that referenced this pull request Jul 23, 2024
…S` (llvm#98717)

This change makes `std::lock_guard` available when
`_LIBCPP_HAS_NO_THREADS` is set. This class is generic and doesn't
require threading support, and is regularly used even in environments
where threading isn't available like embedded.

fixes llvm#89891

---------

Co-authored-by: Louis Dionne <[email protected]>
yuxuanchen1997 pushed a commit that referenced this pull request Jul 25, 2024
…S` (#98717)

Summary:
This change makes `std::lock_guard` available when
`_LIBCPP_HAS_NO_THREADS` is set. This class is generic and doesn't
require threading support, and is regularly used even in environments
where threading isn't available like embedded.

fixes #89891

---------

Co-authored-by: Louis Dionne <[email protected]>

Test Plan: 

Reviewers: 

Subscribers: 

Tasks: 

Tags: 


Differential Revision: https://phabricator.intern.facebook.com/D60251575
ilovepi added a commit that referenced this pull request Jul 31, 2024
…99562)

This is a follow up to #98717,
which made lock_guard available under _LIBCPP_HAS_NO_THREADS. We can
make unique_lock available under similar circumstances. This patch
follows the example in #98717, by:

  - Removing the preprocessor guards for _LIBCPP_HAS_NO_THREADS in the
    unique_lock header.
  - providing a set of custom mutex implementations in a local header.
  - using custom locks in tests that can be made to work under
    `no-threads`.
clementval pushed a commit to clementval/llvm-project that referenced this pull request Jul 31, 2024
…lvm#99562)

This is a follow up to llvm#98717,
which made lock_guard available under _LIBCPP_HAS_NO_THREADS. We can
make unique_lock available under similar circumstances. This patch
follows the example in llvm#98717, by:

  - Removing the preprocessor guards for _LIBCPP_HAS_NO_THREADS in the
    unique_lock header.
  - providing a set of custom mutex implementations in a local header.
  - using custom locks in tests that can be made to work under
    `no-threads`.
banach-space pushed a commit to banach-space/llvm-project that referenced this pull request Aug 7, 2024
…lvm#99562)

This is a follow up to llvm#98717,
which made lock_guard available under _LIBCPP_HAS_NO_THREADS. We can
make unique_lock available under similar circumstances. This patch
follows the example in llvm#98717, by:

  - Removing the preprocessor guards for _LIBCPP_HAS_NO_THREADS in the
    unique_lock header.
  - providing a set of custom mutex implementations in a local header.
  - using custom locks in tests that can be made to work under
    `no-threads`.
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.

std::lock_guard is unavailable when _LIBCPP_HAS_NO_THREADS is set
5 participants