1349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
981ad6265SDimitry Andric #include <__assert>
1006c3fb27SDimitry Andric #include <__thread/id.h>
115f757f3fSDimitry Andric #include <__utility/exception_guard.h>
1281ad6265SDimitry Andric #include <limits>
1381ad6265SDimitry Andric #include <mutex>
1481ad6265SDimitry Andric 
150b57cec5SDimitry Andric #include "include/atomic_support.h"
160b57cec5SDimitry Andric 
17480093f4SDimitry Andric #if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
180b57cec5SDimitry Andric #  pragma comment(lib, "pthread")
190b57cec5SDimitry Andric #endif
200b57cec5SDimitry Andric 
2181ad6265SDimitry Andric _LIBCPP_PUSH_MACROS
2281ad6265SDimitry Andric #include <__undef_macros>
2381ad6265SDimitry Andric 
240b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
2581ad6265SDimitry Andric 
260b57cec5SDimitry Andric // ~mutex is defined elsewhere
270b57cec5SDimitry Andric 
lock()28cb14a3feSDimitry Andric void mutex::lock() {
290b57cec5SDimitry Andric   int ec = __libcpp_mutex_lock(&__m_);
300b57cec5SDimitry Andric   if (ec)
310b57cec5SDimitry Andric     __throw_system_error(ec, "mutex lock failed");
320b57cec5SDimitry Andric }
330b57cec5SDimitry Andric 
try_lock()34cb14a3feSDimitry Andric bool mutex::try_lock() noexcept { return __libcpp_mutex_trylock(&__m_); }
350b57cec5SDimitry Andric 
unlock()36cb14a3feSDimitry Andric void mutex::unlock() noexcept {
370b57cec5SDimitry Andric   int ec = __libcpp_mutex_unlock(&__m_);
380b57cec5SDimitry Andric   (void)ec;
397a6dacacSDimitry Andric   _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(
407a6dacacSDimitry Andric       ec == 0, "call to mutex::unlock failed. A possible reason is that the mutex wasn't locked");
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric // recursive_mutex
440b57cec5SDimitry Andric 
recursive_mutex()45cb14a3feSDimitry Andric recursive_mutex::recursive_mutex() {
460b57cec5SDimitry Andric   int ec = __libcpp_recursive_mutex_init(&__m_);
470b57cec5SDimitry Andric   if (ec)
480b57cec5SDimitry Andric     __throw_system_error(ec, "recursive_mutex constructor failed");
490b57cec5SDimitry Andric }
500b57cec5SDimitry Andric 
~recursive_mutex()51cb14a3feSDimitry Andric recursive_mutex::~recursive_mutex() {
520b57cec5SDimitry Andric   int e = __libcpp_recursive_mutex_destroy(&__m_);
530b57cec5SDimitry Andric   (void)e;
547a6dacacSDimitry Andric   _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(e == 0, "call to ~recursive_mutex() failed");
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric 
lock()57cb14a3feSDimitry Andric void recursive_mutex::lock() {
580b57cec5SDimitry Andric   int ec = __libcpp_recursive_mutex_lock(&__m_);
590b57cec5SDimitry Andric   if (ec)
600b57cec5SDimitry Andric     __throw_system_error(ec, "recursive_mutex lock failed");
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric 
unlock()63cb14a3feSDimitry Andric void recursive_mutex::unlock() noexcept {
640b57cec5SDimitry Andric   int e = __libcpp_recursive_mutex_unlock(&__m_);
650b57cec5SDimitry Andric   (void)e;
667a6dacacSDimitry Andric   _LIBCPP_ASSERT_VALID_EXTERNAL_API_CALL(
677a6dacacSDimitry Andric       e == 0, "call to recursive_mutex::unlock() failed. A possible reason is that the mutex wasn't locked");
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric 
try_lock()70cb14a3feSDimitry Andric bool recursive_mutex::try_lock() noexcept { return __libcpp_recursive_mutex_trylock(&__m_); }
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric // timed_mutex
730b57cec5SDimitry Andric 
timed_mutex()74cb14a3feSDimitry Andric timed_mutex::timed_mutex() : __locked_(false) {}
750b57cec5SDimitry Andric 
~timed_mutex()76cb14a3feSDimitry Andric timed_mutex::~timed_mutex() { lock_guard<mutex> _(__m_); }
770b57cec5SDimitry Andric 
lock()78cb14a3feSDimitry Andric void timed_mutex::lock() {
790b57cec5SDimitry Andric   unique_lock<mutex> lk(__m_);
800b57cec5SDimitry Andric   while (__locked_)
810b57cec5SDimitry Andric     __cv_.wait(lk);
820b57cec5SDimitry Andric   __locked_ = true;
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric 
try_lock()85cb14a3feSDimitry Andric bool timed_mutex::try_lock() noexcept {
860b57cec5SDimitry Andric   unique_lock<mutex> lk(__m_, try_to_lock);
87cb14a3feSDimitry Andric   if (lk.owns_lock() && !__locked_) {
880b57cec5SDimitry Andric     __locked_ = true;
890b57cec5SDimitry Andric     return true;
900b57cec5SDimitry Andric   }
910b57cec5SDimitry Andric   return false;
920b57cec5SDimitry Andric }
930b57cec5SDimitry Andric 
unlock()94cb14a3feSDimitry Andric void timed_mutex::unlock() noexcept {
950b57cec5SDimitry Andric   lock_guard<mutex> _(__m_);
960b57cec5SDimitry Andric   __locked_ = false;
970b57cec5SDimitry Andric   __cv_.notify_one();
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric // recursive_timed_mutex
1010b57cec5SDimitry Andric 
recursive_timed_mutex()102cb14a3feSDimitry Andric recursive_timed_mutex::recursive_timed_mutex() : __count_(0), __id_{} {}
1030b57cec5SDimitry Andric 
~recursive_timed_mutex()104cb14a3feSDimitry Andric recursive_timed_mutex::~recursive_timed_mutex() { lock_guard<mutex> _(__m_); }
1050b57cec5SDimitry Andric 
lock()106cb14a3feSDimitry Andric void recursive_timed_mutex::lock() {
1070b57cec5SDimitry Andric   __thread_id id = this_thread::get_id();
1080b57cec5SDimitry Andric   unique_lock<mutex> lk(__m_);
109cb14a3feSDimitry Andric   if (id == __id_) {
1100b57cec5SDimitry Andric     if (__count_ == numeric_limits<size_t>::max())
1110b57cec5SDimitry Andric       __throw_system_error(EAGAIN, "recursive_timed_mutex lock limit reached");
1120b57cec5SDimitry Andric     ++__count_;
1130b57cec5SDimitry Andric     return;
1140b57cec5SDimitry Andric   }
1150b57cec5SDimitry Andric   while (__count_ != 0)
1160b57cec5SDimitry Andric     __cv_.wait(lk);
1170b57cec5SDimitry Andric   __count_ = 1;
1180b57cec5SDimitry Andric   __id_    = id;
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric 
try_lock()121cb14a3feSDimitry Andric bool recursive_timed_mutex::try_lock() noexcept {
1220b57cec5SDimitry Andric   __thread_id id = this_thread::get_id();
1230b57cec5SDimitry Andric   unique_lock<mutex> lk(__m_, try_to_lock);
124cb14a3feSDimitry Andric   if (lk.owns_lock() && (__count_ == 0 || id == __id_)) {
1250b57cec5SDimitry Andric     if (__count_ == numeric_limits<size_t>::max())
1260b57cec5SDimitry Andric       return false;
1270b57cec5SDimitry Andric     ++__count_;
1280b57cec5SDimitry Andric     __id_ = id;
1290b57cec5SDimitry Andric     return true;
1300b57cec5SDimitry Andric   }
1310b57cec5SDimitry Andric   return false;
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric 
unlock()134cb14a3feSDimitry Andric void recursive_timed_mutex::unlock() noexcept {
1350b57cec5SDimitry Andric   unique_lock<mutex> lk(__m_);
136cb14a3feSDimitry Andric   if (--__count_ == 0) {
1370b57cec5SDimitry Andric     __id_.__reset();
1380b57cec5SDimitry Andric     lk.unlock();
1390b57cec5SDimitry Andric     __cv_.notify_one();
1400b57cec5SDimitry Andric   }
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD
14481ad6265SDimitry Andric 
14581ad6265SDimitry Andric _LIBCPP_POP_MACROS
146