Skip to content

Commit 00f64cc

Browse files
Arthur O'Dwyerldionne
authored andcommitted
[libc++] Remove non-atomic "platform" semaphore implementations.
These can't be made constexpr-constructible (constinit'able), so they aren't C++20-conforming. Also, the platform versions are going to be bigger than the atomic/futex version, so we'd have the awkward situation that `semaphore<42>` could be bigger than `semaphore<43>`, and that's just silly. Differential Revision: https://reviews.llvm.org/D110110 (cherry picked from commit d0eaf75) CHERRY-PICK NOTE BY @ldionne: I added a release note mentioning the ABI break.
1 parent 6cf25de commit 00f64cc

File tree

7 files changed

+19
-171
lines changed

7 files changed

+19
-171
lines changed

libcxx/docs/ReleaseNotes.rst

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ New Features
6161
- The documentation conversion from html to restructured text has been
6262
completed.
6363

64-
API Changes
65-
-----------
64+
API and ABI Changes
65+
-------------------
6666

6767
- There has been several changes in the tuple constructors provided by libc++.
6868
Those changes were made as part of an effort to regularize libc++'s tuple
@@ -95,3 +95,10 @@ API Changes
9595

9696
- The ``std::result_of`` and ``std::is_literal_type`` type traits have been removed in
9797
C++20 mode.
98+
99+
- The C++20 type ``std::counted_semaphore<N>`` is now based on ``std::atomic``
100+
on all platforms, and does not use "native" semaphores such as pthreads
101+
``sem_t`` even on platforms that would support them. This changes the layout
102+
of ``counted_semaphore<N>`` notably on Linux, so it is an ABI break on that
103+
platform. This change is needed to conform to the Standard, which requires
104+
``counted_semaphore``'s constructor to be constexpr.

libcxx/include/__threading_support

Lines changed: 0 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,9 @@
2929
# include <__external_threading>
3030
#elif !defined(_LIBCPP_HAS_NO_THREADS)
3131

32-
#if defined(__APPLE__) || defined(__MVS__)
33-
# define _LIBCPP_NO_NATIVE_SEMAPHORES
34-
#endif
35-
3632
#if defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
3733
# include <pthread.h>
3834
# include <sched.h>
39-
# ifndef _LIBCPP_NO_NATIVE_SEMAPHORES
40-
# include <semaphore.h>
41-
# endif
4235
#elif defined(_LIBCPP_HAS_THREAD_API_C11)
4336
# include <threads.h>
4437
#endif
@@ -78,12 +71,6 @@ typedef pthread_mutex_t __libcpp_recursive_mutex_t;
7871
typedef pthread_cond_t __libcpp_condvar_t;
7972
#define _LIBCPP_CONDVAR_INITIALIZER PTHREAD_COND_INITIALIZER
8073

81-
#ifndef _LIBCPP_NO_NATIVE_SEMAPHORES
82-
// Semaphore
83-
typedef sem_t __libcpp_semaphore_t;
84-
# define _LIBCPP_SEMAPHORE_MAX SEM_VALUE_MAX
85-
#endif
86-
8774
// Execute once
8875
typedef pthread_once_t __libcpp_exec_once_flag;
8976
#define _LIBCPP_EXEC_ONCE_INITIALIZER PTHREAD_ONCE_INIT
@@ -149,12 +136,6 @@ typedef void* __libcpp_recursive_mutex_t[5];
149136
typedef void* __libcpp_condvar_t;
150137
#define _LIBCPP_CONDVAR_INITIALIZER 0
151138

152-
// Semaphore
153-
typedef void* __libcpp_semaphore_t;
154-
#if defined(_LIBCPP_HAS_THREAD_API_WIN32)
155-
# define _LIBCPP_SEMAPHORE_MAX (::std::numeric_limits<long>::max())
156-
#endif
157-
158139
// Execute Once
159140
typedef void* __libcpp_exec_once_flag;
160141
#define _LIBCPP_EXEC_ONCE_INITIALIZER 0
@@ -219,26 +200,6 @@ int __libcpp_condvar_timedwait(__libcpp_condvar_t *__cv, __libcpp_mutex_t *__m,
219200
_LIBCPP_THREAD_ABI_VISIBILITY
220201
int __libcpp_condvar_destroy(__libcpp_condvar_t* __cv);
221202

222-
#ifndef _LIBCPP_NO_NATIVE_SEMAPHORES
223-
224-
// Semaphore
225-
_LIBCPP_THREAD_ABI_VISIBILITY
226-
bool __libcpp_semaphore_init(__libcpp_semaphore_t* __sem, int __init);
227-
228-
_LIBCPP_THREAD_ABI_VISIBILITY
229-
bool __libcpp_semaphore_destroy(__libcpp_semaphore_t* __sem);
230-
231-
_LIBCPP_THREAD_ABI_VISIBILITY
232-
bool __libcpp_semaphore_post(__libcpp_semaphore_t* __sem);
233-
234-
_LIBCPP_THREAD_ABI_VISIBILITY
235-
bool __libcpp_semaphore_wait(__libcpp_semaphore_t* __sem);
236-
237-
_LIBCPP_THREAD_ABI_VISIBILITY
238-
bool __libcpp_semaphore_wait_timed(__libcpp_semaphore_t* __sem, chrono::nanoseconds const& __ns);
239-
240-
#endif // _LIBCPP_NO_NATIVE_SEMAPHORES
241-
242203
// Execute once
243204
_LIBCPP_THREAD_ABI_VISIBILITY
244205
int __libcpp_execute_once(__libcpp_exec_once_flag *flag,
@@ -452,38 +413,6 @@ int __libcpp_condvar_destroy(__libcpp_condvar_t *__cv)
452413
return pthread_cond_destroy(__cv);
453414
}
454415

455-
#ifndef _LIBCPP_NO_NATIVE_SEMAPHORES
456-
457-
// Semaphore
458-
bool __libcpp_semaphore_init(__libcpp_semaphore_t* __sem, int __init)
459-
{
460-
return sem_init(__sem, 0, __init) == 0;
461-
}
462-
463-
bool __libcpp_semaphore_destroy(__libcpp_semaphore_t* __sem)
464-
{
465-
return sem_destroy(__sem) == 0;
466-
}
467-
468-
bool __libcpp_semaphore_post(__libcpp_semaphore_t* __sem)
469-
{
470-
return sem_post(__sem) == 0;
471-
}
472-
473-
bool __libcpp_semaphore_wait(__libcpp_semaphore_t* __sem)
474-
{
475-
return sem_wait(__sem) == 0;
476-
}
477-
478-
bool __libcpp_semaphore_wait_timed(__libcpp_semaphore_t* __sem, chrono::nanoseconds const& __ns)
479-
{
480-
auto const __abs_time = chrono::system_clock::now().time_since_epoch() + __ns;
481-
__libcpp_timespec_t __ts = __thread_detail::__convert_to_timespec(__abs_time);
482-
return sem_timedwait(__sem, &__ts) == 0;
483-
}
484-
485-
#endif //_LIBCPP_NO_NATIVE_SEMAPHORES
486-
487416
// Execute once
488417
int __libcpp_execute_once(__libcpp_exec_once_flag *flag,
489418
void (*init_routine)()) {

libcxx/include/semaphore

Lines changed: 2 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
6767

6868
/*
6969
70-
__atomic_semaphore_base is the general-case implementation, to be used for
71-
user-requested least-max values that exceed the OS implementation support
72-
(incl. when the OS has no support of its own) and for binary semaphores.
73-
70+
__atomic_semaphore_base is the general-case implementation.
7471
It is a typical Dijkstra semaphore algorithm over atomics, wait and notify
7572
functions. It avoids contention against users' own use of those facilities.
7673
@@ -121,68 +118,12 @@ public:
121118
}
122119
};
123120

124-
#ifndef _LIBCPP_NO_NATIVE_SEMAPHORES
125-
126-
/*
127-
128-
__platform_semaphore_base a simple wrapper for the OS semaphore type. That
129-
is, every call is routed to the OS in the most direct manner possible.
130-
131-
*/
132-
133-
class __platform_semaphore_base
134-
{
135-
__libcpp_semaphore_t __semaphore;
136-
137-
public:
138-
_LIBCPP_INLINE_VISIBILITY
139-
explicit __platform_semaphore_base(ptrdiff_t __count) :
140-
__semaphore()
141-
{
142-
__libcpp_semaphore_init(&__semaphore, __count);
143-
}
144-
_LIBCPP_INLINE_VISIBILITY
145-
~__platform_semaphore_base() {
146-
__libcpp_semaphore_destroy(&__semaphore);
147-
}
148-
_LIBCPP_INLINE_VISIBILITY
149-
void release(ptrdiff_t __update)
150-
{
151-
for(; __update; --__update)
152-
__libcpp_semaphore_post(&__semaphore);
153-
}
154-
_LIBCPP_INLINE_VISIBILITY
155-
void acquire()
156-
{
157-
__libcpp_semaphore_wait(&__semaphore);
158-
}
159-
_LIBCPP_INLINE_VISIBILITY
160-
bool try_acquire_for(chrono::nanoseconds __rel_time)
161-
{
162-
return __libcpp_semaphore_wait_timed(&__semaphore, __rel_time);
163-
}
164-
};
165-
166-
template<ptrdiff_t __least_max_value>
167-
using __semaphore_base =
168-
typename conditional<(__least_max_value > 1 && __least_max_value <= _LIBCPP_SEMAPHORE_MAX),
169-
__platform_semaphore_base,
170-
__atomic_semaphore_base>::type;
171-
172-
#else
173-
174-
template<ptrdiff_t __least_max_value>
175-
using __semaphore_base =
176-
__atomic_semaphore_base;
177-
178121
#define _LIBCPP_SEMAPHORE_MAX (numeric_limits<ptrdiff_t>::max())
179122

180-
#endif //_LIBCPP_NO_NATIVE_SEMAPHORES
181-
182123
template<ptrdiff_t __least_max_value = _LIBCPP_SEMAPHORE_MAX>
183124
class counting_semaphore
184125
{
185-
__semaphore_base<__least_max_value> __semaphore;
126+
__atomic_semaphore_base __semaphore;
186127

187128
public:
188129
static constexpr ptrdiff_t max() noexcept {

libcxx/src/support/win32/thread_win32.cpp

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ static_assert(alignof(__libcpp_thread_t) == alignof(HANDLE), "");
3939
static_assert(sizeof(__libcpp_tls_key) == sizeof(DWORD), "");
4040
static_assert(alignof(__libcpp_tls_key) == alignof(DWORD), "");
4141

42-
static_assert(sizeof(__libcpp_semaphore_t) == sizeof(HANDLE), "");
43-
static_assert(alignof(__libcpp_semaphore_t) == alignof(HANDLE), "");
44-
4542
// Mutex
4643
int __libcpp_recursive_mutex_init(__libcpp_recursive_mutex_t *__m)
4744
{
@@ -275,37 +272,4 @@ int __libcpp_tls_set(__libcpp_tls_key __key, void *__p)
275272
return 0;
276273
}
277274

278-
// Semaphores
279-
bool __libcpp_semaphore_init(__libcpp_semaphore_t* __sem, int __init)
280-
{
281-
*(PHANDLE)__sem = CreateSemaphoreEx(nullptr, __init, _LIBCPP_SEMAPHORE_MAX,
282-
nullptr, 0, SEMAPHORE_ALL_ACCESS);
283-
return *__sem != nullptr;
284-
}
285-
286-
bool __libcpp_semaphore_destroy(__libcpp_semaphore_t* __sem)
287-
{
288-
CloseHandle(*(PHANDLE)__sem);
289-
return true;
290-
}
291-
292-
bool __libcpp_semaphore_post(__libcpp_semaphore_t* __sem)
293-
{
294-
return ReleaseSemaphore(*(PHANDLE)__sem, 1, nullptr);
295-
}
296-
297-
bool __libcpp_semaphore_wait(__libcpp_semaphore_t* __sem)
298-
{
299-
return WaitForSingleObjectEx(*(PHANDLE)__sem, INFINITE, false) ==
300-
WAIT_OBJECT_0;
301-
}
302-
303-
bool __libcpp_semaphore_wait_timed(__libcpp_semaphore_t* __sem,
304-
chrono::nanoseconds const& __ns)
305-
{
306-
chrono::milliseconds __ms = chrono::ceil<chrono::milliseconds>(__ns);
307-
return WaitForSingleObjectEx(*(PHANDLE)__sem, __ms.count(), false) ==
308-
WAIT_OBJECT_0;
309-
}
310-
311275
_LIBCPP_END_NAMESPACE_STD

libcxx/test/std/thread/thread.semaphore/acquire.pass.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
// macOS 11.0.
1414
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}}
1515

16+
// TODO(ldionne): This test fails on Ubuntu Focal on our CI nodes (and only there), in 32 bit mode.
17+
// UNSUPPORTED: linux && 32bits-on-64bits
18+
1619
// <semaphore>
1720

1821
#include <semaphore>

libcxx/test/std/thread/thread.semaphore/ctor.compile.pass.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ static_assert(!std::is_default_constructible<std::counting_semaphore<>>::value,
2424
static_assert(!std::is_convertible<int, std::binary_semaphore>::value, "");
2525
static_assert(!std::is_convertible<int, std::counting_semaphore<>>::value, "");
2626

27-
#if 0 // TODO FIXME: the ctor should be constexpr when TEST_STD_VER > 17
27+
#if TEST_STD_VER > 17
28+
// Test constexpr-constructibility. (But not destructibility.)
2829
constinit std::binary_semaphore bs(1);
2930
constinit std::counting_semaphore cs(1);
3031
#endif

libcxx/test/std/thread/thread.semaphore/release.pass.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
// macOS 11.0.
1414
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}}
1515

16+
// TODO(ldionne): This test fails on Ubuntu Focal on our CI nodes (and only there), in 32 bit mode.
17+
// UNSUPPORTED: linux && 32bits-on-64bits
18+
1619
// <semaphore>
1720

1821
#include <semaphore>

0 commit comments

Comments
 (0)