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

<semaphore> Implement semaphore - WIP #420

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions stl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ set(HEADERS
${CMAKE_CURRENT_LIST_DIR}/inc/ratio
${CMAKE_CURRENT_LIST_DIR}/inc/regex
${CMAKE_CURRENT_LIST_DIR}/inc/scoped_allocator
${CMAKE_CURRENT_LIST_DIR}/inc/semaphore
${CMAKE_CURRENT_LIST_DIR}/inc/set
${CMAKE_CURRENT_LIST_DIR}/inc/shared_mutex
${CMAKE_CURRENT_LIST_DIR}/inc/sstream
Expand Down
85 changes: 85 additions & 0 deletions stl/inc/semaphore
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// semaphore standard header

// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#pragma once

#ifndef _SEMAPHORE_
#define _SEMAPHORE_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR

#if !_HAS_CXX20
#pragma message("The contents of <semaphore> are available only with C++20 or later.")
#else // ^^^ !_HAS_CXX20 / _HAS_CXX20 vvv
#include <atomic>
#include <cassert>
#include <chrono>
#include <cstddef>

#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

_STD_BEGIN
template <ptrdiff_t _LeastMaxValue = 256>
class counting_semaphore {
public:
static constexpr ptrdiff_t max() noexcept {
// _LeastMaxValue is used here so that things such as binary_semaphore are
return _LeastMaxValue;
}
constexpr explicit counting_semaphore(ptrdiff_t _Desired) {
_STL_ASSERT(
_Desired >= 0 && _Desired <= max(), "Desired value for the semaphore falls outside of semaphore range");
atomic_init(&_Counter, _Desired);
}
~counting_semaphore() = default;
counting_semaphore(const counting_semaphore&) = delete;
counting_semaphore& operator=(const counting_semaphore&) = delete;

void release(ptrdiff_t _Update = 1) {
_Counter.fetch_add(_Update, memory_order::release);
}
void acquire() {
while (!try_acquire()) {
Copy link
Member

Choose a reason for hiding this comment

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

Ditto I don't think this is acceptable due to busy waiting.

}
}
bool try_acquire() noexcept {
ptrdiff_t _Old = _Counter.load(memory_order::acquire);
ptrdiff_t _Desired = _Old - 1;
if (_Old > 0 && _Counter.compare_exchange_strong(_Old, _Desired)) {
return true;
}
return false;
}
template <class _Rep, class _Period>
bool try_acquire_for(const chrono::duration<_Rep, _Period>& _Rel_time) {
return try_acquire_until(chrono::steady_clock::now() + _Rel_time);
}
template <class _Clock, class _Duration>
bool try_acquire_until(const chrono::time_point<_Clock, _Duration>& _Abs_time) {
while (!try_acquire()) {
if (_Clock::now() >= _Abs_time) {
return false;
}
}
return true;
}

private:
atomic<ptrdiff_t> _Counter;
};
using binary_semaphore = counting_semaphore<1>;
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif
#endif
#endif
2 changes: 2 additions & 0 deletions stl/inc/yvals_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,8 @@
#define __cpp_lib_constexpr_numeric 201911L
#endif // __cpp_lib_is_constant_evaluated

#define __cpp_lib_semaphore 201907L

#endif // _HAS_CXX20

// EXPERIMENTAL
Expand Down